graphics/grNull.c: typed no-op stubs for WASM call_indirect

Magic's graphics layer routes every drawing primitive through
function pointers (GrXxxPtr / grXxxPtr) that are bound to a driver
at startup. The original null driver assigned a single 0-arg
nullDoNothing() to every pointer, which works in native builds
because of K&R loose prototype rules but fails in WASM where
call_indirect requires an exact type match between caller and
callee.

This commit:
* Adds typed no-op stubs nullDoNothingI/II/IIII/IIIIIII for
  void-returning callbacks of various arities.
* Adds nullReturnFalseI/II/III for bool-returning callbacks and
  nullReturnZeroI for int-returning callbacks.
* Casts each pointer assignment in nullSetDisplay() to the K&R
  pointer type the public header still uses, while the underlying
  function carries the correct WASM signature.
* Fills in window-management and backing-store pointers that the
  original null driver left at NULL — many of these are called
  unconditionally by WindUpdate paths, and need at least a no-op
  to avoid traps.
* Guards the stdin watch in nullSetDisplay() with #ifndef
  __EMSCRIPTEN__: WASM has no real stdin file descriptor and
  TxAdd1InputDevice() / SigWatchFile() are POSIX-specific.

Native builds are unaffected: the K&R-loose prototype machinery
still accepts the previous and the new code identically.
This commit is contained in:
Intubun 2026-05-04 13:30:21 +02:00
parent a1639cf08b
commit 5cf7c70662
1 changed files with 107 additions and 13 deletions

View File

@ -61,6 +61,74 @@ nullDoNothing()
{ {
} }
/*
* Typed no-op stubs for WASM call_indirect type compatibility.
* WASM enforces exact type signatures at indirect call sites; assigning
* a 0-arg nullDoNothing to a pointer called with arguments causes a
* "null function or function signature mismatch" trap. These stubs
* have the correct arity so the WASM type check passes.
*/
/* 1-argument stub (int or pointer) */
static void
nullDoNothingI(int a)
{
(void) a;
}
/* 2-argument stub */
static void
nullDoNothingII(int a, int b)
{
(void) a; (void) b;
}
/* 4-argument stub */
static void
nullDoNothingIIII(int a, int b, int c, int d)
{
(void) a; (void) b; (void) c; (void) d;
}
/* 7-argument stub (for grFontTextPtr) */
static void
nullDoNothingIIIIIII(int a, int b, int c, int d, int e, int f, int g)
{
(void) a; (void) b; (void) c; (void) d; (void) e; (void) f; (void) g;
}
/* bool-returning stubs — return FALSE so callers treat backing store / window
* creation as unavailable, which is correct for the headless null driver. */
static bool
nullReturnFalseI(int a)
{
(void) a;
return FALSE;
}
static bool
nullReturnFalseII(int a, int b)
{
(void) a; (void) b;
return FALSE;
}
/* 3-argument bool-returning stub (for grDrawGridPtr) */
static bool
nullReturnFalseIII(int a, int b, int c)
{
(void) a; (void) b; (void) c;
return FALSE;
}
/* 1-argument int-returning stub (for GrWindowIdPtr) */
static int
nullReturnZeroI(int a)
{
(void) a;
return 0;
}
/* /*
*--------------------------------------------------------- *---------------------------------------------------------
* *
@ -246,8 +314,10 @@ nullSetDisplay(dispType, outFileName, mouseFileName)
{ {
TxPrintf("Using NULL graphics device.\n"); TxPrintf("Using NULL graphics device.\n");
#ifndef __EMSCRIPTEN__
TxAdd1InputDevice(fileno(stdin), nullStdin, (ClientData) NULL); TxAdd1InputDevice(fileno(stdin), nullStdin, (ClientData) NULL);
if (TxStdinIsatty) SigWatchFile(fileno(stdin), "stdin"); if (TxStdinIsatty) SigWatchFile(fileno(stdin), "stdin");
#endif
/* Set up the procedure values in the indirection table. */ /* Set up the procedure values in the indirection table. */
@ -259,25 +329,49 @@ nullSetDisplay(dispType, outFileName, mouseFileName)
GrEnableTabletPtr = nullDoNothing; GrEnableTabletPtr = nullDoNothing;
GrDisableTabletPtr = nullDoNothing; GrDisableTabletPtr = nullDoNothing;
GrSetCursorPtr = nullDoNothing; GrSetCursorPtr = (void (*)()) nullDoNothingI;
GrTextSizePtr = NullTextSize; GrTextSizePtr = NullTextSize;
GrDrawGlyphPtr = nullDoNothing; GrDrawGlyphPtr = (void (*)()) nullDoNothingII;
GrBitBltPtr = NullBitBlt; GrBitBltPtr = NullBitBlt;
GrReadPixelPtr = nullReturnZero; GrReadPixelPtr = nullReturnZero;
GrFlushPtr = nullDoNothing; GrFlushPtr = nullDoNothing;
/* Window management — null driver has no real windows; return FALSE so
* callers know the operation wasn't performed. */
GrCreateWindowPtr = NULL; /* headless: skip OS window creation, WindCreate stays OK */
GrDeleteWindowPtr = (void (*)()) nullDoNothingI;
GrConfigureWindowPtr = (void (*)()) nullDoNothingI;
GrOverWindowPtr = (void (*)()) nullDoNothingI;
GrUnderWindowPtr = (void (*)()) nullDoNothingI;
GrDamagedPtr = nullDoNothing;
GrUpdateIconPtr = (void (*)()) nullDoNothingII;
GrEventPendingPtr = (bool (*)()) nullReturnFalse;
GrWindowIdPtr = (int (*)()) nullReturnZeroI;
GrWindowNamePtr = NULL; /* protected by callers */
GrGetCursorPosPtr = (bool (*)()) nullReturnFalseII;
GrGetCursorRootPosPtr = (bool (*)()) nullReturnFalseII;
/* Backing store — not available in headless mode */
GrGetBackingStorePtr = (bool (*)()) nullReturnFalseII;
GrScrollBackingStorePtr = (bool (*)()) nullReturnFalseII;
GrPutBackingStorePtr = (void (*)()) nullDoNothingII;
GrFreeBackingStorePtr = (void (*)()) nullDoNothingI;
GrCreateBackingStorePtr = (void (*)()) nullDoNothingI;
/* local indirections */ /* local indirections */
grSetSPatternPtr = nullDoNothing; grSetSPatternPtr = (void (*)()) nullDoNothingII;
grPutTextPtr = nullDoNothing; grPutTextPtr = (void (*)()) nullDoNothingIIII;
grFontTextPtr = nullDoNothing; grFontTextPtr = (void (*)()) nullDoNothingIIIIIII;
grDefineCursorPtr = nullDoNothing; grDefineCursorPtr = (void (*)()) nullDoNothingI;
grDrawGridPtr = nullReturnFalse; grFreeCursorPtr = (void (*)()) nullDoNothingI;
grDrawLinePtr = nullDoNothing; grDrawGridPtr = (bool (*)()) nullReturnFalseIII;
grSetWMandCPtr = nullDoNothing; grDrawLinePtr = (void (*)()) nullDoNothingIIII;
grFillRectPtr = nullDoNothing; grSetWMandCPtr = (void (*)()) nullDoNothingII;
grSetStipplePtr = nullDoNothing; grFillRectPtr = (void (*)()) nullDoNothingI;
grSetLineStylePtr = nullDoNothing; grFillPolygonPtr = (void (*)()) nullDoNothingII;
grSetCharSizePtr = nullDoNothing; grSetStipplePtr = (void (*)()) nullDoNothingI;
grSetLineStylePtr = (void (*)()) nullDoNothingI;
grSetCharSizePtr = (void (*)()) nullDoNothingI;
GrScreenRect.r_xtop = 511; GrScreenRect.r_xtop = 511;
GrScreenRect.r_ytop = 483; GrScreenRect.r_ytop = 483;