Fix GH-21639: Protect frameless args during __toString() reentry#21815
Fix GH-21639: Protect frameless args during __toString() reentry#21815prateekbhujel wants to merge 4 commits intophp:PHP-8.4from
Conversation
|
Thanks for the PR.
I'm afraid this will need a more general solution. My hope was to avoid overhead in the VM, but it might be unavoidable for a proper fix, even if this is a largely artificial issue. |
35148db to
15ec47b
Compare
15ec47b to
c818fa7
Compare
c818fa7 to
08cc08f
Compare
08cc08f to
38e2314
Compare
|
The other alternative would be checking inside the tostring handler whether the parent frame is currently at a frameless opcode and then safely copy its CV args to a buffer, set EG(vm_interrupt) and free them on the next EG(vm_interrupt), completely moving the overhead off the main paths and be a truly generic solution. Obviously comes at a small tostring handler cost, but I'd really rather see overhead there...? |
38e2314 to
163b9ef
Compare
163b9ef to
9ae220f
Compare
28d83f6 to
2671fc4
Compare
2671fc4 to
28d83f6
Compare
|
@bwoebi I pushed the It only creates copies when So normal frameless calls only keep the cold pending-copy check after the handler. |
|
Pushed one small cleanup on top. The copies are now only cleaned up from the frameless handler cleanup point, with executor shutdown as the fallback. I dropped the extra vm_interrupt cleanup path because it made the lifetime rules harder to follow and wasn't needed for the normal handler return path. I also updated the PR body with the exact local test commands I ran. |
Fixes GH-21639.
Frameless internal calls borrow CV operands from the caller frame. If an argument is converted through
__toString(), that call can re-enter userland and change those CVs while the frameless handler is still using them.This keeps copies only when
__toString()is entered from an active frameless opcode, and releases them at the frameless handler cleanup point. The JIT frameless path uses the same cleanup point.Normal frameless calls only keep the cold pending-copy check after the handler.
Tests run: