Skip to content

ci: disable opcache.protect_memory for phpt suite — incompatible with threaded workers (#93)#108

Merged
EdmondDantes merged 1 commit into
mainfrom
ci-disable-opcache-protect-memory
Jul 7, 2026
Merged

ci: disable opcache.protect_memory for phpt suite — incompatible with threaded workers (#93)#108
EdmondDantes merged 1 commit into
mainfrom
ci-disable-opcache-protect-memory

Conversation

@EdmondDantes

Copy link
Copy Markdown
Contributor

Root cause of the 053-hot-reload-watcher macOS flake

opcache.protect_memory=1 (a run-tests default) protects the opcache SHM with process-global mprotect, toggled via SHM_UNPROTECT/SHM_PROTECT outside the compile lock (persistent_compile_file, ZendAccelerator.c).

The true-async worker pool runs workers as threads in one address space. On hot-reload rotation, fresh workers concurrently recompile the changed file into the shared SHM. One worker's SHM_PROTECT flips the page read-only process-wide while another worker is mid-write → SIGBUS (KERN_PROTECTION_FAILURE). Backtrace (captured via the new crash-report CI step):

SIGBUS  persistent_compile_file  ZendAccelerator.c:2222   (write to SHM)
        thread_pool_worker_handler  thread_pool.c:259       (worker thread)

opcache itself acknowledges this: "mprotect() is process-global and races" (ZendAccelerator.c).

Why this is safe

  • Production is unaffectedopcache.protect_memory defaults to 0; then SHM_(UN)PROTECT are no-ops.
  • The actual compilation is serialized across threads by zend_shared_alloc_lock (a tsrm_mutex_lock under ZTS), so no SHM corruption.
  • The only cross-thread write left outside the lock is the last_used timestamp — a benign torn write.

So protect_memory=1 is a debug/CI diagnostic that is architecturally incompatible with the threaded-worker model; it produces false crashes, not real ones.

Change

Pass -d opcache.protect_memory=0 to every phpt run (linux, macos, windows, debug-macos-workers, chaos). Verified locally that run-tests appends the user -d after its hardcoded protect_memory=1, so the last one wins → child gets 0.

…ith threaded workers) (#93)

opcache.protect_memory=1 (a run-tests default) guards the SHM with process-global
mprotect toggled OUTSIDE the compile lock. The true-async worker pool runs workers
as threads in one address space, so one worker's SHM_PROTECT flips the page
read-only under another worker's in-flight SHM write during concurrent
compilation on pool rotation — an intermittent SIGBUS (seen as the 053 flake on
macOS ARM64). opcache itself notes "mprotect() is process-global and races"
(ZendAccelerator.c). Not a production concern: the directive defaults off and the
actual compilation is serialized by zend_shared_alloc_lock; only a benign
last_used timestamp write is left unlocked. Override it to 0 in every phpt run.
@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Coverage

Total lines: 75.45% → 75.44% (-0.01 pp)

File Baseline Current Δ Touched
src/core/http_connection_tls.c 73.67% 73.39% -0.28 pp

@EdmondDantes EdmondDantes merged commit baeabeb into main Jul 7, 2026
8 checks 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.

1 participant