Skip to content

php: a smoke test, and correct the PLAS stack write-up - #730

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

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

Conversation

@staalmannen

Copy link
Copy Markdown
Owner

The port had run `php -v' and nothing else. A version string is printed before the engine evaluates an opcode, so it cannot tell an interpreter that works from one that computes nothing right -- and the first real program put on it, the Phoronix Test Suite, died with

Hard memory limit of 2147483648 bytes exhausted
(tried to allocate 4294971392 bytes)

4294971392 is 2**32 + 4096: a 64-bit quantity whose low half is sane and whose high half holds a 1, page-rounded by the allocator. The 2GB limit is Phoronix's own memory_limit, so only the second number is ours. The line it names is `display_text_table', printing the table of missing extensions that appears just above it, and that loop is

$m = max($min, 1 + $extra + $widths[$c]) - strlen($cell);
if ($m > 0) $line .= str_repeat(' ', $m);

so `$m' came out near 2**32 and str_repeat was the victim. The suspect is the integer width: zend_long is 64 bits because this port defines x86_64, while kencc's long is 32 and php_config.h answers SIZEOF_LONG 4. Both are correct and they disagree.

sys/lib/tests/php-smoke.php asks that in order -- PHP_INT_SIZE and PHP_INT_MAX, then strlen, then the exact padding expression, then str_repeat, then the whole failing loop reduced to the table php had printed -- and it has a real reference implementation, the build host's own php, with nothing newer than PHP 8.0 used. Its first host run found a fault in the test (expected padding 14, answer 15); 0 failures on 8.3.6 now.

plas_stack_readme.md is rewritten against the tree. Three of its claims were wrong and one was inverted:

  • it describes a binary with an embedded SQLite engine. There is no PDO and no sqlite3 extension in this build; the Phoronix run says so itself. SQLite 3.53.4 IS ported as libsqlite.a and is in the default build, along with libxml2, libzip, zlib, curl, LibreSSL and oniguruma, so the extensions are mkfile work.

  • it claims 9P guarantees coherent locking, so several machines can write one database file safely. The opposite holds: lib/ap/fcntl/fcntl.c:180 answers EINVAL to F_GETLK, F_SETLK and F_SETLKW, and SQLite's default unix VFS takes byte-range locks on every write transaction. Answering EINVAL is the safe answer -- a lock stub returning success is how a database gets corrupted -- but it means the open question is whether a SINGLE writer works, and `sqlite3 /tmp/t.db 'create table t(a);'' settles that in one command. If it is the blocker, the remedy is SQLITE_ENABLE_LOCKING_STYLE and the dot-file VFS, which is at 0 in the vendored amalgamation and unset in lib/sqlite/mkfile.

  • static linking is presented as a property of the stack. Plan 9 has no dynamic linker at all, which is also why ZEND_EXTENSIONS_SUPPORT is 0, why dl() cannot work, and what caused the opcache shutdown crash fixed in the previous commit.

  • a forked namespace is not a restricted one; rfork gives a private copy, and the restricting is work the handler script must do.

The CGI section is marked unverified, because this build is --disable-cgi, header() is a no-op under the CLI SAPI, and I cannot check 9front's rc-httpd layout from the source tree. The /net and /dev reading script -- the half that needs no extension at all -- is corrected and kept.

Claude-Session: https://claude.ai/code/session_01WGAwvvTwDg2yknFkmZ3qzs

claude and others added 2 commits November 5, 2026 17:04
The port had run `php -v' and nothing else.  A version string is
printed before the engine evaluates an opcode, so it cannot tell an
interpreter that works from one that computes nothing right -- and
the first real program put on it, the Phoronix Test Suite, died with

	Hard memory limit of 2147483648 bytes exhausted
	(tried to allocate 4294971392 bytes)

4294971392 is 2**32 + 4096: a 64-bit quantity whose low half is sane
and whose high half holds a 1, page-rounded by the allocator.  The 2GB
limit is Phoronix's own memory_limit, so only the second number is
ours.  The line it names is `display_text_table', printing the table
of missing extensions that appears just above it, and that loop is

	$m = max($min, 1 + $extra + $widths[$c]) - strlen($cell);
	if ($m > 0) $line .= str_repeat(' ', $m);

so `$m' came out near 2**32 and str_repeat was the victim.  The
suspect is the integer width: zend_long is 64 bits because this port
defines __x86_64__, while kencc's long is 32 and php_config.h answers
SIZEOF_LONG 4.  Both are correct and they disagree.

sys/lib/tests/php-smoke.php asks that in order -- PHP_INT_SIZE and
PHP_INT_MAX, then strlen, then the exact padding expression, then
str_repeat, then the whole failing loop reduced to the table php had
printed -- and it has a real reference implementation, the build
host's own php, with nothing newer than PHP 8.0 used.  Its first host
run found a fault in the test (expected padding 14, answer 15); 0
failures on 8.3.6 now.

plas_stack_readme.md is rewritten against the tree.  Three of its
claims were wrong and one was inverted:

  * it describes a binary with an embedded SQLite engine.  There is
    no PDO and no sqlite3 extension in this build; the Phoronix run
    says so itself.  SQLite 3.53.4 IS ported as libsqlite.a and is in
    the default build, along with libxml2, libzip, zlib, curl,
    LibreSSL and oniguruma, so the extensions are mkfile work.

  * it claims 9P guarantees coherent locking, so several machines can
    write one database file safely.  The opposite holds:
    lib/ap/fcntl/fcntl.c:180 answers EINVAL to F_GETLK, F_SETLK and
    F_SETLKW, and SQLite's default unix VFS takes byte-range locks on
    every write transaction.  Answering EINVAL is the safe answer --
    a lock stub returning success is how a database gets corrupted --
    but it means the open question is whether a SINGLE writer works,
    and `sqlite3 /tmp/t.db 'create table t(a);'' settles that in one
    command.  If it is the blocker, the remedy is
    SQLITE_ENABLE_LOCKING_STYLE and the dot-file VFS, which is at 0 in
    the vendored amalgamation and unset in lib/sqlite/mkfile.

  * static linking is presented as a property of the stack.  Plan 9
    has no dynamic linker at all, which is also why
    ZEND_EXTENSIONS_SUPPORT is 0, why dl() cannot work, and what
    caused the opcache shutdown crash fixed in the previous commit.

  * a forked namespace is not a restricted one; rfork gives a private
    copy, and the restricting is work the handler script must do.

The CGI section is marked unverified, because this build is
--disable-cgi, header() is a no-op under the CLI SAPI, and I cannot
check 9front's rc-httpd layout from the source tree.  The /net and
/dev reading script -- the half that needs no extension at all -- is
corrected and kept.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WGAwvvTwDg2yknFkmZ3qzs
@staalmannen
staalmannen merged commit 1900744 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