opcache: smm_shared_globals left pointing to a dead stack frame when there is no SHM backend
Maintainer thường phản hồi trong vòng 1 ngày
Chưa có ai nhận issue này.
Đánh giá
- Độ khó
- 2/5
- Thời gian dự kiến
- 1-3 giờ
- Mức phù hợp với người mới
- 72/100
- Loại issue
- Lỗi
- Độ rõ ràng
- Đặc tả rõ ràng
- Mức độ hoạt động
- Sôi nổi
- Lĩnh vực
- backend, performance
Hướng nghiên cứu
Bắt đầu tại ext/opcache/zend_shared_alloc.c, ở zend_shared_alloc_startup(), tập trung vào lệnh trả về sớm khi handler_table == NULL và cách các lệnh trả về sớm khác đặt lại smm_shared_globals. Tái hiện lỗi bằng chương trình embed SAPI và thiết lập AddressSanitizer được cung cấp, hoặc kiểm tra các đường dẫn khởi động hiện có. Công việc hoàn tất khi đường dẫn không dùng SHM không còn để lại con trỏ tới biến cục bộ trên ngăn xếp và chương trình tái hiện chạy xong mà không có báo cáo stack-use-after-return.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
Description
When opcache has no shared memory backend (handler_table is empty), zend_shared_alloc_startup() returns NO_SHM_BACKEND with smm_shared_globals still pointing to its local tmp_shared_globals. The other early returns (FAILED_REATTACHED, ALLOC_FALLBACK) reset it to NULL; this one does not.
Nothing reads it while opcache is disabled. But if the engine is started again in the same process (embed SAPI: php_embed_init() / php_embed_shutdown()), with opcache.file_cache_only=1, zend_shared_alloc_startup() is not called. zend_accel_in_shm() then reads ZSMMG(shared_segments_count) and ZSMMG(shared_segments) from that dead frame, and zend_persist uses its answer to decide what is already persisted.
We hit it with PHP compiled to WebAssembly (emscripten), which has no SHM backend, as a memory corruption ("memory access out of bounds") when opcache later compiled some files to its file cache. Here is a native reproducer, with the SHM backends disabled at configure time:
php_cv_shm_ipc=no php_cv_shm_mmap_anon=no php_cv_shm_mmap_posix=no \
./configure --enable-embed --disable-all --disable-opcache-jit --enable-address-sanitizer
make && make install
gcc -fsanitize=address repro.c -o repro $(php-config --includes) -L/usr/local/lib -lphp
mkdir /tmp/opcache
USE_ZEND_ALLOC=0 ASAN_OPTIONS=detect_leaks=0:detect_stack_use_after_return=1 ./repro
repro.c:
#include <sapi/embed/php_embed.h>
#include <stdlib.h>
static void start(const char *phprc, const char *code)
{
setenv("PHPRC", phprc, 1);
php_embed_init(0, NULL);
zend_first_try {
zend_eval_string((char *) code, NULL, "repro");
} zend_end_try();
php_embed_shutdown();
}
int main(void)
{
start("/repro/first", "var_dump(opcache_get_status(false));");
start("/repro/second", "var_dump(opcache_compile_file('/repro/script.php'));");
return 0;
}
/repro/first/php.ini:
opcache.enable=1
opcache.log_verbosity_level=4
/repro/second/php.ini:
opcache.enable=1
opcache.file_cache=/tmp/opcache
opcache.file_cache_only=1
/repro/script.php:
<?php
const PRIMES = [2, 3, 5, 7];
function primes(): array
{
static $calls = [];
$calls[] = true;
return PRIMES;
}
Resulted in this output:
Message Opcode Caching is disabled: No available SHM backend. Set opcache.enable=0 to hide this message.
bool(false)
==1==ERROR: AddressSanitizer: stack-use-after-return on address 0x7f1327702a38 at pc 0x7f1329e77995 bp 0x7ffe0f741820 sp 0x7ffe0f741818
READ of size 4 at 0x7f1327702a38 thread T0
#0 0x7f1329e77994 in zend_accel_in_shm /php-src/ext/opcache/zend_shared_alloc.c:701
#1 0x7f1329e598f4 in zend_persist_op_array_calc_ex /php-src/ext/opcache/zend_persist_calc.c:244
#2 0x7f1329e61c73 in zend_accel_script_persist_calc /php-src/ext/opcache/zend_persist_calc.c:665
#3 0x7f1329e797c2 in store_script_in_file_cache /php-src/ext/opcache/ZendAccelerator.c:1520
#4 0x7f1329e8da01 in cache_script_in_file_cache /php-src/ext/opcache/ZendAccelerator.c:1571
#5 0x7f1329e8da01 in file_cache_compile_file /php-src/ext/opcache/ZendAccelerator.c:1962
#6 0x7f1329e9396d in persistent_compile_file /php-src/ext/opcache/ZendAccelerator.c:2017
#7 0x7f1329e3e564 in zif_opcache_compile_file /php-src/ext/opcache/zend_accelerator_module.c:1013
Address 0x7f1327702a38 is located in stack of thread T0 at offset 56 in frame
#0 0x7f1329e75c2f in zend_shared_alloc_startup /php-src/ext/opcache/zend_shared_alloc.c:185
This frame has 1 object(s):
[48, 128) 'tmp_shared_globals' (line 188) <== Memory access at offset 56 is inside this variable
But I expected this output instead:
Message Opcode Caching is disabled: No available SHM backend. Set opcache.enable=0 to hide this message.
bool(false)
bool(true)
Resetting it before that return gives the expected output, with no ASan report:
if (handler_table->name == NULL) {
+ smm_shared_globals = NULL;
return NO_SHM_BACKEND;
}
I can open a PR with this fix.
PHP Version
PHP 8.5.12, and master (d15160d5)
Operating System
Debian trixie, x86_64, gcc 14.2 (ASan). First seen with emscripten 6.0.13 (WebAssembly).
- Ngôn ngữ chính
- C
- Star
- 41.7k
- Fork
- 8.5k
- Merge trung bình
- 2 ngày 18 giờ
- Pull request đã merge (30 ngày)
- 145
Chuẩn bị môi trường
- Không có Dockerfile hay tệp Docker Compose
- Không có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của php/php-src
-
SNMP accepts malformed remote portsCó thể đã có người làm Có pull request liên kết đang mở hoặc đã được merge. Đang mở
Độ khó 2/5 Nửa ngày Mức phù hợp với người mới 62/100
php/php-src#25137 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Bug Status: Needs Triage
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 64/100
Maintainer thường phản hồi trong vòng 1 ngày
-
quoted_printable_encode() produces lines longer than 76 characters for bytes 0xF5 to 0xFFCó thể đã có người làm Có pull request liên kết đang mở hoặc đã được merge. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 76/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Bug Status: Needs Triage
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 62/100
php/php-src#24196 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Feature Status: Needs Triage
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 73/100
php/php-src#24183 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
Issue tương tự
-
[compiler-rt] Rtsan-aarch64-NoInstTest: error: no such file or directory: 'NOTFOUND' (libatomic)Đang mởbuild-problem compiler-rt:rtsan platform:linux
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 63/100
llvm/llvm-project#239039 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
component:obi contribfest go test
Độ khó 2/5 Dưới một giờ Mức phù hợp với người mới 83/100
open-telemetry/opentelemetry-ebpf-instrumentation#4143 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 64/100
checkpoint-restore/criu#3304 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Bug :bug:
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
sonic-net/sonic-buildimage#30541 ·
Maintainer thường phản hồi trong vòng 1 ngày