Bug #80959 [Ver]: infinite loop in building cfg during JIT compilation

From: Date: Fri, 16 Apr 2021 09:25:52 +0000
Subject: Bug #80959 [Ver]: infinite loop in building cfg during JIT compilation
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-233465@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=80959&edit=1 ID: 80959 Updated by: nikic@php.net Reported by: zengyhkyle at asu dot edu Summary: infinite loop in building cfg during JIT compilation Status: Verified Type: Bug Package: JIT Operating System: Linux PHP Version: 8.0.4RC1 Block user comment: N Private report: N New Comment: Though it would be great if we could not run loop identification in the first place if a function has try/catch. In that case we don't perform SSA construction or register allocation, which need this for correctness. It seems like the only places that use the information in that case is timeout checks and hot loop counters. Maybe we just want to pessimize those in the presence of try/catch? Previous Comments: ------------------------------------------------------------------------ [2021-04-16 09:12:46] nikic@php.net CFG for reference: https://gist.github.com/nikic/84d11192df4d7b6cc42f971c7d15920b The core problem here is that BB5 and BB6 are not reachable from entry through normal edges (they have domtree level 0 and will be processed last). They are reachable in the reverse graph though, which is traversed when loop headers are assigned. We end up with BB3 having BB6 as loop header, and BB6 having BB3 as loop header, causing an infinite loop. There's probably two separate problems here: We should be treating unreachable code more gracefully, and we should not be treating this code as unreachable in the first place, though I'm not sure what the right way to handle unwind edges would be right now. ------------------------------------------------------------------------ [2021-04-16 08:23:48] nikic@php.net Nice find! Here's a somewhat reduced version: <?php function test($a, $b) { echo "Start\n"; do { $i++; try { continue; } catch (Exception $e) { } do { $j++; } while ($j < $b); } while ($i < $a); echo "Done\n"; } test(); ------------------------------------------------------------------------ [2021-04-15 22:34:42] zengyhkyle at asu dot edu in our experiment, the execution is stuck at function zend_cfg_identify_loops ------------------------------------------------------------------------ [2021-04-15 22:32:33] zengyhkyle at asu dot edu Description: ------------ if JIT compilation is enabled, PHP will get stuck in infinitely during loop identification when building the cfg for some code. the configuration we use is listed as follow: ~~~ opcache.jit_debug=263 opcache.enable_cli=1 opcache.jit=1205 opcache.jit_buffer_size=1G zend_extension=/home/user/php-src-php-8.0.3/modules/opcache.so ~~~ This vulnerability is found by Yihui Zeng, Jayakrishna Menon, Steven Wirsz, and Gokul Krishna P from Arizona State University for class CSE598 Applied Vulnerability Research a poc is attached. Test script: --------------- <?php $v0 = -815; $v1 = True; $v2 = $v0; if($v1){ $v3 = [5, 5]; $v2 = $v3; }else{ $v4 = False; $v5 = $v0; if($v4){ $v6 = $v4|$v0; $v5 = $v6; }else{ $v5 = $v5 + 1; $v7 = $v5 + 1; $v5 = $v7; } $v2 = $v5; } $v8 = 0; $v9 = 4; $v10 = $v8; do{ $v10 = $v10 + 1; $v11 = $v10 + 1; $v12 = $v10; try{ continue; $v10 = $v12; }catch(Exception $e){ $v2 = $v12; } $v13 = False; $v14 = $v13; if($v13){ $v15 = $v12/$v14; $v14 = $v15; }else{ $v16 = 0; $v17 = 9; $v18 = $v16; do{ $v18 = $v18 + 1; $v19 = $v18 + 1; $v19 = $v19 - 1; $v20 = $v19 - 1; }while($v18<$v17); $v21 = "kBBqSjjO63"; $v21[0] = $v12; $v14 = $v21; } }while($v10<$v9); $v22 = [3.055141489223973, 5.118032201755781, 1.6115282496633003, 2.796353888054253, 1.607762036181039, 5.52005061408927, 2.4609577104054896]; $v23 = [4, 1, 4, 4]; echo "Done"; ?> ------------------------------------------------------------------------ -- Edit this bug report at https://bugs.php.net/bug.php?id=80959&edit=1

« previous php.bugs (#233465) next »