Skip to content

Claude/upgrade ape c library mm z gd - #719

Merged
staalmannen merged 4 commits into
mainfrom
claude/upgrade-ape-c-library-mmZGd
Nov 5, 2026
Merged

staalmannen merged 4 commits into
mainfrom
claude/upgrade-ape-c-library-mmZGd

Conversation

@staalmannen

Copy link
Copy Markdown
Owner

No description provided.

pcc answered `conversion of pointer to shorter integer' five times in
makecontext.c.  The casts read (unsigned long long)(unsigned long)ptr
and unsigned long is four bytes here, so the stack address,
_ctxreturn and func would all have been truncated.  uintptr_t now,
and stack_t's ss_size is size_t rather than long, which is POSIX's
type and avoids narrowing what php assigns to it.

The host cross-check could not have caught it and never will:
unsigned long is eight bytes under glibc, so the conversion is
lossless there.  That is the second long-width bug in this one port
that gcc was structurally blind to, after ucontext-test's section 5,
so the comment in place says to read anything that moves a pointer
through an integer for it specifically rather than leave it to the
host.

The second error, `duplicate text symbol: _ctxreturn', is not the
code at all: renaming mcontext.s to ucontext.s left mcontext.6 in
libap.a.  mksyslib's clean is `rm -f *.[$OS] ...', which touches the
directory and never $LIB, and `ar vu' replaces members by name, so an
object whose source is gone is never revisited.  `ar d' on the stale
member clears it.  Recorded as a build-system rule, with the point
that the collision was the lucky outcome: a stale object that does
not collide stays linked into every program in the tree with no
diagnostic from anyone.

makectx-xcheck still 0, and its two frame controls still 3 and 1.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WGAwvvTwDg2yknFkmZ3qzs
All six sections, including section 0 printing its PASS line twice --
the resumed path re-entering at getcontext's return, which is the
thing the C wrapper could not do.  php blocker 1 is closed; what
remains is pointing php at it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WGAwvvTwDg2yknFkmZ3qzs
kencc defines no architecture macro, and php needs one.
Zend/zend_long.h:26 selects zend_long from __x86_64__ || __LP64__ ||
_LP64 || _WIN64 rather than from SIZEOF_LONG, so without it php's
integer type is 32 bits; ext/date/lib/timelib.h:112 has the identical
test.  And five arms in Zend/zend_float.h read !defined(__x86_64__),
selecting x87 control-word code that is wrong for an SSE machine --
so not defining it is itself a positive, wrong choice, which is what
settles it.  __LP64__ is the available alternative and is a lie,
since kencc is LLP64.

What else it switches on was measured rather than assumed: of the 30
files mentioning it, every site emitting GCC inline assembly is
separately gated on __GNUC__, on HAVE_ASM_GOTO, on an absent
intrinsics header, or on the HYBRID VM kind.  The three that do turn
on are a plain C hash loop, unaligned-access shortcuts that are true
here, and cpuinfo, whose two helpers both have a non-GCC fallback
that returns zero.  It goes on the compile line rather than in the
config.h, because timelib.h is reached by files that have not
included php_config.h yet.

The header inventory is mechanical and now resolved: 39 of the 91
HAVE_*_H names exist under sys/include/ape or amd64/include/ape,
including everything structural.  The 52 absent are ODBC, tidy,
linux/*, the SSE intrinsics, Windows and crypt.h -- php bundles its
own crypt, which is why four crypt_* files are already in the object
list.

And one of the 39 is a trap worth the note: HAVE_DLFCN_H resolves to
yes and the answer is no, because apfunc-sweep reports dlopen and
dlerror as declared-only.  A file-existence check answers that one
confidently and wrongly, which is the clearest argument in this port
for hand-answering rather than deriving.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WGAwvvTwDg2yknFkmZ3qzs
sys/src/ape/cmd/php/ holds six files and nothing in external/php is
touched: the mkfile (513 objects), php_config.h, zend_config.h,
timelib_config.h, build-defs.h and internal_functions_cli.c.  The
mkfile puts -I. first so our copies win over anything configure would
have generated into the vendored tree.

The object list is derived from upstream's own configure rather than
transcribed, the clisp precedent.  The objects keep their paths, and
that is not cosmetic: sixteen basenames collide across the 43 source
directories -- array.c is both ext/standard/array.c and
ext/lexbor/lexbor/core/array.c, and hash, parser, state, token, url
and ten more are the same -- so a flat OFILES would build one and
link it twice, silently.  php is a program rather than a library, so
there is no archive member to collide and nested paths cost only a
mkdir in the rule.

Each comment inside OFILES ends with a backslash, which is
mkcont-sweep's rule, and HFILES names the four hand-kept headers,
because mk does not scan #includes and editing a config.h that
nothing depends on rebuilds nothing.  mkcont-sweep and rceq-sweep
both pass; apehdr-sweep is identical with and without the new
<ucontext.h>, which is a control rather than a reading.

Two macros are answered no for capabilities that are present, link,
and return success -- clisp's mprotect rule, twice.  HAVE_MPROTECT,
because plan9/mman.c:44 is `return 0'.  And HAVE_MREMAP, which is
worse: APExp's mremap allocates and copies, while
zend_mm_chunk_extend calls it without MREMAP_MAYMOVE precisely
because it needs the chunk to stay put, and treats anything that is
not MAP_FAILED as success.  Zend would record a chunk as extended in
place while the memory had moved.  A probe that compiles and links
cannot tell either from the real thing.

STRERROR_R_CHAR_P is unset, and copying the host answer would have
been a real bug: glibc's strerror_r returns char *, APE's is POSIX's
returning int, so php would have used an int as a pointer.
ZEND_CHECK_STACK_LIMIT is unset with the cost recorded rather than
hidden -- deep recursion will fault instead of raising an error --
and HAVE_IPV6 is unset as a choice rather than a finding, since the
types exist and nothing here has ever exercised them.

And one question answered itself: the sweep found 37 functions APE
has that the host configure left undef, which looked like a judgement
call about enabling paths upstream never compiles on Linux.  grep
says all 37 are referenced in 0 files of what this port builds.

php is deliberately not in sys/src/ape/cmd/mkfile: one failing entry
aborts the whole tree's mk, and this has never been built.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WGAwvvTwDg2yknFkmZ3qzs
@staalmannen
staalmannen merged commit 9102b11 into main Nov 5, 2026
1 check passed
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