-
Notifications
You must be signed in to change notification settings - Fork 7
220 lines (203 loc) · 8.63 KB
/
debug-bugfix.yml
File metadata and controls
220 lines (203 loc) · 8.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
name: Debug Bugfix (manual)
# Manually-triggered, focused workflow for iterating on the CI failures
# tracked in the bug-fix issue. Runs only the handful of failing tests across
# the platform/build combos that reproduce them, so a fix can be verified
# without waiting on the full build matrix.
#
# Trigger: gh workflow run "Debug Bugfix (manual)" --repo true-async/php-async --ref main
on:
workflow_dispatch:
inputs:
php_async_ref:
description: "php-async ref to test (branch/tag/sha; blank = this workflow's ref)"
default: ""
php_src_ref:
description: "php-src branch/tag/sha to build against"
default: "true-async-stable"
jobs:
bugfix:
strategy:
fail-fast: false
matrix:
include:
# #2 — cancel_during_io getaddrinfo struct leak (NTS only). ASAN on.
- name: LINUX_NTS_ASAN
os: ubuntu-latest
zts: false
asan: true
jit: false
# #1 — thread_pool/cancel wild-pointer SEGV, JIT-specific (ZTS).
# Runs the test under no-JIT / function-JIT / tracing-JIT to pin
# which JIT mode triggers it (tracing patches opline->handler at
# runtime; function patches at compile time).
- name: LINUX_ZTS_JIT
os: ubuntu-latest
zts: true
asan: false
jit: true
# #3 — curl progress-callback exception (macOS NTS).
- name: MACOS_NTS
os: macos-latest
zts: false
asan: false
jit: false
name: ${{ matrix.name }}
runs-on: ${{ matrix.os }}
timeout-minutes: ${{ matrix.asan && 180 || 60 }}
steps:
- name: Checkout php-async repo
uses: actions/checkout@v4
with:
path: async
ref: ${{ github.event.inputs.php_async_ref || github.ref }}
- name: Clone php-src
run: |
git clone https://github.com/true-async/php-src php-src
git -C php-src checkout "${{ github.event.inputs.php_src_ref }}"
echo "php-src at: $(git -C php-src rev-parse --short HEAD)"
- name: Copy php-async extension into php-src
run: |
mkdir -p php-src/ext/async
cp -r async/* php-src/ext/async/
- name: Install build dependencies (Linux)
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y \
gcc g++ autoconf bison re2c \
libsqlite3-dev libonig-dev libcurl4-openssl-dev \
libxml2-dev libreadline-dev libsodium-dev libargon2-dev \
cmake
- name: Install build dependencies (macOS)
if: runner.os == 'macOS'
run: |
brew install autoconf bison re2c libuv curl oniguruma openssl@3 libiconv || true
# bison is keg-only on macOS; the system bison (2.3) is too old.
echo "$(brew --prefix bison)/bin" >> "$GITHUB_PATH"
- name: Install LibUV >= 1.45.0 (Linux)
if: runner.os == 'Linux'
run: |
if pkg-config --exists libuv && pkg-config --atleast-version=1.45.0 libuv; then
sudo apt-get install -y libuv1-dev
else
wget https://github.com/libuv/libuv/archive/v1.45.0.tar.gz
tar -xzf v1.45.0.tar.gz
cd libuv-1.45.0 && mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE=Release && make -j"$(nproc)" && sudo make install && sudo ldconfig
fi
- name: Configure PHP
working-directory: php-src
run: |
./buildconf -f
ASAN_FLAGS=""
if [ "${{ matrix.asan }}" = "true" ]; then
ASAN_FLAGS="--enable-address-sanitizer"
export CFLAGS="-fsanitize=address -DZEND_TRACK_ARENA_ALLOC -g -O0"
export LDFLAGS="-fsanitize=address"
fi
ICONV=""
if [ "${{ runner.os }}" = "macOS" ]; then
ICONV="--with-iconv=$(brew --prefix)/opt/libiconv"
fi
./configure \
--${{ matrix.zts && 'enable' || 'disable' }}-zts \
--enable-debug \
--enable-async \
--enable-pdo --with-pdo-sqlite \
--enable-sockets --enable-pcntl --enable-opcache \
--enable-mbstring --enable-tokenizer --enable-filter --enable-session \
--with-curl --with-openssl \
$ICONV $ASAN_FLAGS
- name: Build PHP
working-directory: php-src
run: make -j"$(getconf _NPROCESSORS_ONLN)"
- name: Generate chaos tests
working-directory: php-src/ext/async/fuzzy-tests
run: ../../../sapi/cli/php _harness/generate.php
- name: Enable core dumps (Linux)
if: runner.os == 'Linux'
run: |
sudo mkdir -p /tmp/cores && sudo chmod 1777 /tmp/cores
echo '/tmp/cores/core.%e.%p' | sudo tee /proc/sys/kernel/core_pattern
sudo sysctl -w kernel.core_uses_pid=0 || true
ulimit -c unlimited
sudo apt-get install -y --no-install-recommends gdb
- name: Run the failing tests
working-directory: php-src
env:
# abort_on_error=1 → glibc dumps a core on the ASAN report too.
ASAN_OPTIONS: detect_leaks=1:abort_on_error=1:halt_on_error=1
# Route every alloc/free through ASAN's allocator instead of Zend's
# pool, so a use-after-free is reported at the real site.
USE_ZEND_ALLOC: 0
run: |
ulimit -c unlimited
PHP=sapi/cli/php
$PHP -v
TESTS="ext/async/fuzzy-tests/_generated/cross_topic/cancel_during_io__00_cancel_a_coroutine_blocked_on_tcp_accept.phpt
ext/async/fuzzy-tests/_generated/thread_pool/cancel__00_submit_then_cancel_every_future_settles_cleanly.phpt
ext/async/tests/curl/035-progress_exception.phpt
ext/async/tests/curl/056-multi_progress_exception.phpt"
rc=0
run_pass() {
echo "########## pass: $1 ##########"
$PHP run-tests.php -q -p $PHP $2 \
-g FAIL,BORK,LEAK,XLEAK \
--no-progress --offline --show-diff --set-timeout 120 --repeat 30 \
$TESTS || rc=1
}
# off / function / tracing — pins which JIT mode triggers #1.
run_pass "NO JIT" ""
if [ "${{ matrix.jit }}" = "true" ]; then
run_pass "FUNCTION JIT" "-d opcache.enable_cli=1 -d opcache.jit=function -d opcache.jit_buffer_size=64M"
# tracing ON but hot thresholds maxed → traces almost never form.
# Still crashes → bug is in hot-counting; clean → in trace record/compile.
run_pass "TRACING JIT (hot-maxed)" "-d opcache.enable_cli=1 -d opcache.jit=tracing -d opcache.jit_buffer_size=64M -d opcache.jit_hot_loop=255 -d opcache.jit_hot_func=255 -d opcache.jit_hot_return=255 -d opcache.jit_hot_side_exit=255"
run_pass "TRACING JIT" "-d opcache.enable_cli=1 -d opcache.jit=tracing -d opcache.jit_buffer_size=64M"
fi
exit $rc
- name: Backtrace core dumps (Linux)
if: always() && runner.os == 'Linux'
working-directory: php-src
run: |
shopt -s nullglob
cores=(/tmp/cores/core.*)
if [ ${#cores[@]} -eq 0 ]; then
echo "no core dumps — no crash this run"
exit 0
fi
for core in "${cores[@]}"; do
echo "===================== $core ====================="
gdb -batch -nx \
-ex 'set pagination off' \
-ex 'thread apply all bt 60' \
-ex 'frame 1' \
-ex 'p (void*)ex' \
-ex 'p *ex' \
-ex 'p *ex->func' \
-ex 'set $oa = &ex->func->op_array' \
-ex 'p $oa->last' \
-ex 'p $oa->opcodes' \
-ex 'echo --- opcodes[0..last] with handlers ---\n' \
-ex 'p *$oa->opcodes@$oa->last' \
-ex 'echo --- JIT buffer range (dasm_buf) ---\n' \
-ex 'p (void*)dasm_buf' \
-ex 'p (void*)((char*)dasm_buf + dasm_size)' \
-ex 'echo --- is the op_array in opcache SHM? ---\n' \
-ex 'p (void*)$oa' \
-ex 'p accel_shared_globals' \
-ex 'frame 3' \
-ex 'p *coroutine' \
sapi/cli/php "$core" 2>&1 || true
done
- name: Show diffs of failed tests
if: always()
working-directory: php-src
run: |
found=0
for d in $(find ext/async -name '*.diff' 2>/dev/null); do
found=1
echo "===== $d ====="
cat "$d"
done
[ "$found" = "0" ] && echo "no .diff files — all target tests passed"