Skip to content

Fix SIGSEGV in -dnull extraction/DEF read: guard Tk_RestrictEvents with TxTkConsole#534

Open
hpretl wants to merge 1 commit into
RTimothyEdwards:masterfrom
hpretl:fix-dnull-tk-restrictevents-segfault
Open

Fix SIGSEGV in -dnull extraction/DEF read: guard Tk_RestrictEvents with TxTkConsole#534
hpretl wants to merge 1 commit into
RTimothyEdwards:masterfrom
hpretl:fix-dnull-tk-restrictevents-segfault

Conversation

@hpretl

@hpretl hpretl commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Problem

Running magic headless (magic -dnull -noconsole) segfaults during extract / DEF read. Minimal repro (sky130A, any cell with subcells):

magic -dnull -noconsole -rcfile sky130A.magicrc <<'TCL'
load inv.mag
extract all
TCL
Program received signal SIGSEGV
#0  extSubtree () at ExtSubtree.c:194
      oldProc = Tk_RestrictEvents(RestrictInputProc, NULL, &oldArg);
#1  extCellFile () ExtCell.c:523
#4  ExtAll () ExtMain.c:389

It is reliably fatal on aarch64 (the bad indirect call trips Pointer Authentication); on x86_64 it often survives, so it can go unnoticed. This breaks headless extraction/LVS in SAK / LibreLane / open_pdks-style flows.

Cause

Commit d8046fb added Tk_RestrictEvents() to extract/ExtSubtree.c, cif/CIFhier.c and lef/defRead.c, guarded by:

if (SigInterruptOnSigIO != -1)	/* Check for batch mode */

SigInterruptOnSigIO is only -1 for true batchmode (SigInit(TRUE)). The -dnull -noconsole interpreter (magicdnull) is not batch mode (SigInterruptOnSigIO == 0), so the guard passes — but magicdnull never initializes the Tk package, so the Tk stubs table is NULL and the call dereferences it.

Fix

Guard the six call sites with TxTkConsole (RuntimeFlags & MAIN_TK_CONSOLE, from utils/main.h) — true only when a Tk console is actually present — and add the missing #include "utils/main.h" to the two files that lacked it.

Verified on aarch64 (Ubuntu 24.04, magic 8.3.670): extract all + ext2spice on a sky130A inverter now completes cleanly and LVS passes; previously it segfaulted.

@hpretl

hpretl commented Jul 6, 2026

Copy link
Copy Markdown
Contributor Author

@RTimothyEdwards With the latest Magic I have a crash on arm, and it works on x86. With the help of Claude, I triaged the fail, and this PR was constructed as a consequence. Please review it carefully and merge it in. Thanks!

…th TxTkConsole

The Tk_RestrictEvents() calls added to extraction (ExtSubtree.c), CIF/GDS
hierarchy generation (CIFhier.c) and DEF read (defRead.c) are guarded by
`if (SigInterruptOnSigIO != -1)`, intended to skip them in batch mode.

That check is insufficient for `magic -dnull -noconsole`: this mode is not
"batch mode" (SigInterruptOnSigIO == 0), so the guard passes, but magicdnull
never initializes the Tk package. Calling into Tk with a NULL stubs table
segfaults. It is reliably fatal on aarch64 (Pointer Authentication faults the
bad indirect call) while x86_64 often survives it. This breaks headless
extraction/LVS flows (e.g. SAK / LibreLane / open_pdks regression).

Guard these call sites with TxTkConsole (RuntimeFlags & MAIN_TK_CONSOLE)
instead, which is true only when a Tk console is actually present, and add the
missing `#include "utils/main.h"` where needed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@RTimothyEdwards RTimothyEdwards left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this looks good to me (good catch, Claude!)

@RTimothyEdwards

Copy link
Copy Markdown
Owner

On second thought, that's not quite right. Running magic -noconsole should not prevent the window refresh from working, which happens with Claude's solution.

@hpretl

hpretl commented Jul 6, 2026

Copy link
Copy Markdown
Contributor Author

@RTimothyEdwards I tested the fix and can confirm it works. Maybe the issue is only with -dnull, because in this case none of the Tk stuff is initialized, causing the pointer segfault.

@RTimothyEdwards

Copy link
Copy Markdown
Owner

Okay, I realize now that Claude is just dead wrong. The problem is that on aarch64, char is unsigned by default, and so SigInterruptOnSigIO can never be equal to -1, which is why it fails.

Claude's "fix" works because it is a valid substitute when in magic -dnull -noconsole mode; however, if you were to run magic -noconsole (graphics but no console window), then although the code would not crash, the window would not be allowed to refresh during long-running commands as is the intent of the inserted code that was the point of failure.

The underlying error is my long-term misunderstanding that char does not automatically mean signed char, because it happens to have always meant signed char on all the systems I've ever used. I only discovered this misunderstanding about half a year ago, after 30+ years of coding in C. . .

@hpretl

hpretl commented Jul 6, 2026

Copy link
Copy Markdown
Contributor Author

@RTimothyEdwards So still expert knowledge is required, which is a good thing. :-) I happily take your fix, as long as the segfault is gone..

@hpretl

hpretl commented Jul 6, 2026

Copy link
Copy Markdown
Contributor Author

The underlying error is my long-term misunderstanding that char does not automatically mean signed char, because it happens to have always meant signed char on all the systems I've ever used. I only discovered this misunderstanding about half a year ago, after 30+ years of coding in C. . .

@RTimothyEdwards And so we know which systems you have programmed in the past :-)

Platform / architecture Default char
x86 / x86-64 (Linux, Windows, macOS) signed
ARM / AArch64 on Linux and Android unsigned
Apple platforms (iOS, macOS on Apple Silicon) signed — Apple keeps it signed even on ARM for consistency
PowerPC (AIX, Linux PPC) unsigned
s390x, older RISC systems often unsigned
MSVC (all targets) signed

@RTimothyEdwards

Copy link
Copy Markdown
Owner

So modern! Think further back: HP/UX, DEC Ultrix, IRIX, A/UX, Sun OS. . .

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants