From 1d21222dff4db7132111f702fb7b6cabfe0eeace Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= Date: Thu, 11 Sep 2025 12:43:58 +0200 Subject: [PATCH 1/3] zend_vm_gen: Track line numbers on a per-file basis php/php-src#19789 fixed the line number references for `zend_vm_def.h`, when generating with line number information some of them are also specific to `zend_vm_execute.h` and thus should reference that file instead with the correct line numbers. The line number tracking was broken, because it was tracked in a single global variable, instead of being tracked on a per-file basis. Fix this by making the line numbers an array indexed by the resource ID and consistently using the `out()` functions to write into the files. --- Zend/zend_vm_gen.php | 86 ++++++++++++++++++++++++-------------------- 1 file changed, 48 insertions(+), 38 deletions(-) diff --git a/Zend/zend_vm_gen.php b/Zend/zend_vm_gen.php index 6ae8f17144d26..6d84f98304265 100755 --- a/Zend/zend_vm_gen.php +++ b/Zend/zend_vm_gen.php @@ -545,13 +545,18 @@ $helpers = array(); // opcode helpers by name $params = array(); // parameters of helpers $opnames = array(); // opcode name to code mapping -$line_no = 1; +$line_nos = []; $used_extra_spec = array(); // Writes $s into resulting executor function out($f, $s) { - global $line_no; + global $line_nos; + + $line_no = &$line_nos[(int)$f]; + if ($line_no === null) { + $line_no = 1; + } fputs($f,$s); $line_no += substr_count($s, "\n"); @@ -559,7 +564,12 @@ function out($f, $s) { // Resets #line directives in resulting executor function out_line($f) { - global $line_no, $executor_file; + global $line_nos, $executor_file; + + $line_no = &$line_nos[(int)$f]; + if ($line_no === null) { + $line_no = 1; + } fputs($f,"#line ".($line_no+1)." \"".$executor_file."\"\n"); ++$line_no; @@ -2839,46 +2849,46 @@ function gen_vm($def, $skel) { // Insert header out($f, HEADER_TEXT); - fputs($f,"#include \n"); - fputs($f,"#include \n"); - fputs($f,"#include \n\n"); + out($f,"#include \n"); + out($f,"#include \n"); + out($f,"#include \n\n"); - fputs($f,"static const char *zend_vm_opcodes_names[".($max_opcode + 1)."] = {\n"); + out($f,"static const char *zend_vm_opcodes_names[".($max_opcode + 1)."] = {\n"); for ($i = 0; $i <= $max_opcode; $i++) { - fputs($f,"\t".(isset($opcodes[$i]["op"])?'"'.$opcodes[$i]["op"].'"':"NULL").",\n"); + out($f,"\t".(isset($opcodes[$i]["op"])?'"'.$opcodes[$i]["op"].'"':"NULL").",\n"); } - fputs($f, "};\n\n"); + out($f, "};\n\n"); - fputs($f,"static uint32_t zend_vm_opcodes_flags[".($max_opcode + 1)."] = {\n"); + out($f,"static uint32_t zend_vm_opcodes_flags[".($max_opcode + 1)."] = {\n"); for ($i = 0; $i <= $max_opcode; $i++) { - fprintf($f, "\t0x%08x,\n", isset($opcodes[$i]["flags"]) ? $opcodes[$i]["flags"] : 0); - } - fputs($f, "};\n\n"); - - fputs($f, "ZEND_API const char* ZEND_FASTCALL zend_get_opcode_name(uint8_t opcode) {\n"); - fputs($f, "\tif (UNEXPECTED(opcode > ZEND_VM_LAST_OPCODE)) {\n"); - fputs($f, "\t\treturn NULL;\n"); - fputs($f, "\t}\n"); - fputs($f, "\treturn zend_vm_opcodes_names[opcode];\n"); - fputs($f, "}\n"); - - fputs($f, "ZEND_API uint32_t ZEND_FASTCALL zend_get_opcode_flags(uint8_t opcode) {\n"); - fputs($f, "\tif (UNEXPECTED(opcode > ZEND_VM_LAST_OPCODE)) {\n"); - fputs($f, "\t\topcode = ZEND_NOP;\n"); - fputs($f, "\t}\n"); - fputs($f, "\treturn zend_vm_opcodes_flags[opcode];\n"); - fputs($f, "}\n"); - - fputs($f, "ZEND_API uint8_t zend_get_opcode_id(const char *name, size_t length) {\n"); - fputs($f, "\tuint8_t opcode;\n"); - fputs($f, "\tfor (opcode = 0; opcode < (sizeof(zend_vm_opcodes_names) / sizeof(zend_vm_opcodes_names[0])) - 1; opcode++) {\n"); - fputs($f, "\t\tconst char *opcode_name = zend_vm_opcodes_names[opcode];\n"); - fputs($f, "\t\tif (opcode_name && strncmp(opcode_name, name, length) == 0) {\n"); - fputs($f, "\t\t\treturn opcode;\n"); - fputs($f, "\t\t}\n"); - fputs($f, "\t}\n"); - fputs($f, "\treturn ZEND_VM_LAST_OPCODE + 1;\n"); - fputs($f, "}\n"); + out($f, sprintf("\t0x%08x,\n", isset($opcodes[$i]["flags"]) ? $opcodes[$i]["flags"] : 0)); + } + out($f, "};\n\n"); + + out($f, "ZEND_API const char* ZEND_FASTCALL zend_get_opcode_name(uint8_t opcode) {\n"); + out($f, "\tif (UNEXPECTED(opcode > ZEND_VM_LAST_OPCODE)) {\n"); + out($f, "\t\treturn NULL;\n"); + out($f, "\t}\n"); + out($f, "\treturn zend_vm_opcodes_names[opcode];\n"); + out($f, "}\n"); + + out($f, "ZEND_API uint32_t ZEND_FASTCALL zend_get_opcode_flags(uint8_t opcode) {\n"); + out($f, "\tif (UNEXPECTED(opcode > ZEND_VM_LAST_OPCODE)) {\n"); + out($f, "\t\topcode = ZEND_NOP;\n"); + out($f, "\t}\n"); + out($f, "\treturn zend_vm_opcodes_flags[opcode];\n"); + out($f, "}\n"); + + out($f, "ZEND_API uint8_t zend_get_opcode_id(const char *name, size_t length) {\n"); + out($f, "\tuint8_t opcode;\n"); + out($f, "\tfor (opcode = 0; opcode < (sizeof(zend_vm_opcodes_names) / sizeof(zend_vm_opcodes_names[0])) - 1; opcode++) {\n"); + out($f, "\t\tconst char *opcode_name = zend_vm_opcodes_names[opcode];\n"); + out($f, "\t\tif (opcode_name && strncmp(opcode_name, name, length) == 0) {\n"); + out($f, "\t\t\treturn opcode;\n"); + out($f, "\t\t}\n"); + out($f, "\t}\n"); + out($f, "\treturn ZEND_VM_LAST_OPCODE + 1;\n"); + out($f, "}\n"); fclose($f); echo "zend_vm_opcodes.c generated successfully.\n"; From 7e076223750dd3ebbf01fa5d246e71773fd4a34c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= Date: Thu, 11 Sep 2025 13:30:31 +0200 Subject: [PATCH 2/3] zend_vm_gen: Simplify line number tracking logic Co-authored-by: Arnaud Le Blanc <365207+arnaud-lb@users.noreply.github.com> --- Zend/zend_vm_gen.php | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/Zend/zend_vm_gen.php b/Zend/zend_vm_gen.php index 6d84f98304265..bbacd54255940 100755 --- a/Zend/zend_vm_gen.php +++ b/Zend/zend_vm_gen.php @@ -553,23 +553,17 @@ function out($f, $s) { global $line_nos; - $line_no = &$line_nos[(int)$f]; - if ($line_no === null) { - $line_no = 1; - } - fputs($f,$s); - $line_no += substr_count($s, "\n"); + + $line_nos[(int)$f] ??= 1; + $line_nos[(int)$f] += substr_count($s, "\n"); } // Resets #line directives in resulting executor function out_line($f) { global $line_nos, $executor_file; - $line_no = &$line_nos[(int)$f]; - if ($line_no === null) { - $line_no = 1; - } + $line_no = $line_nos[(int)$f] ??= 1; fputs($f,"#line ".($line_no+1)." \"".$executor_file."\"\n"); ++$line_no; From 190cd5ef3ebbab9c4a3f918470c6a2ec44e4935e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= Date: Thu, 11 Sep 2025 13:35:55 +0200 Subject: [PATCH 3/3] zend_vm_gen: Fix out_line() implementation --- Zend/zend_vm_gen.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Zend/zend_vm_gen.php b/Zend/zend_vm_gen.php index bbacd54255940..01fe2999ab4aa 100755 --- a/Zend/zend_vm_gen.php +++ b/Zend/zend_vm_gen.php @@ -563,10 +563,10 @@ function out($f, $s) { function out_line($f) { global $line_nos, $executor_file; - $line_no = $line_nos[(int)$f] ??= 1; + $line_nos[(int)$f] ??= 1; + $line_nos[(int)$f]++; - fputs($f,"#line ".($line_no+1)." \"".$executor_file."\"\n"); - ++$line_no; + fputs($f,"#line ".$line_nos[(int)$f]." \"".$executor_file."\"\n"); } function is_hot_helper($name) {