diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 3af0d6e4607..395e0045253 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -80,7 +80,7 @@ static inline uint32_t zend_alloc_cache_slot(void) { } ZEND_API zend_op_array *(*zend_compile_file)(zend_file_handle *file_handle, int type); -ZEND_API zend_op_array *(*zend_compile_string)(zend_string *source_string, const char *filename); +ZEND_API zend_op_array *(*zend_compile_string)(zend_string *source_string, const char *filename, zend_compile_position position); #ifndef ZTS ZEND_API zend_compiler_globals compiler_globals; diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 95d7984fdc9..1a4d3afcac0 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -740,6 +740,12 @@ struct _zend_execute_data { #include "zend_globals.h" +typedef enum _zend_compile_position { + ZEND_COMPILE_POSITION_AT_SHEBANG = 0, + ZEND_COMPILE_POSITION_AT_OPEN_TAG, + ZEND_COMPILE_POSITION_AFTER_OPEN_TAG +} zend_compile_position; + BEGIN_EXTERN_C() void init_compiler(void); @@ -752,7 +758,7 @@ void zend_file_context_begin(zend_file_context *prev_context); void zend_file_context_end(zend_file_context *prev_context); extern ZEND_API zend_op_array *(*zend_compile_file)(zend_file_handle *file_handle, int type); -extern ZEND_API zend_op_array *(*zend_compile_string)(zend_string *source_string, const char *filename); +extern ZEND_API zend_op_array *(*zend_compile_string)(zend_string *source_string, const char *filename, zend_compile_position position); ZEND_API int ZEND_FASTCALL lex_scan(zval *zendlval, zend_parser_stack_elem *elem); void startup_scanner(void); @@ -805,7 +811,7 @@ zend_string *zval_make_interned_string(zval *zv); struct _zend_arena; ZEND_API zend_op_array *compile_file(zend_file_handle *file_handle, int type); -ZEND_API zend_op_array *compile_string(zend_string *source_string, const char *filename); +ZEND_API zend_op_array *compile_string(zend_string *source_string, const char *filename, zend_compile_position position); ZEND_API zend_op_array *compile_filename(int type, zend_string *filename); ZEND_API zend_ast *zend_compile_string_to_ast( zend_string *code, struct _zend_arena **ast_arena, zend_string *filename); diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index e59642292ba..a4f8657a9b3 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -4394,7 +4394,7 @@ static zend_never_inline zend_op_array* ZEND_FASTCALL zend_include_or_eval(zval break; case ZEND_EVAL: { char *eval_desc = zend_make_compiled_string_description("eval()'d code"); - new_op_array = zend_compile_string(inc_filename, eval_desc); + new_op_array = zend_compile_string(inc_filename, eval_desc, ZEND_COMPILE_POSITION_AFTER_OPEN_TAG); efree(eval_desc); } break; diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 481105d14c3..4c3d1fe2b5e 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -1223,7 +1223,7 @@ ZEND_API zend_result zend_eval_stringl(const char *str, size_t str_len, zval *re original_compiler_options = CG(compiler_options); CG(compiler_options) = ZEND_COMPILE_DEFAULT_FOR_EVAL; - new_op_array = zend_compile_string(code_str, string_name); + new_op_array = zend_compile_string(code_str, string_name, ZEND_COMPILE_POSITION_AFTER_OPEN_TAG); CG(compiler_options) = original_compiler_options; if (new_op_array) { diff --git a/Zend/zend_language_scanner.l b/Zend/zend_language_scanner.l index 56c57a5a085..ff70ff2282f 100644 --- a/Zend/zend_language_scanner.l +++ b/Zend/zend_language_scanner.l @@ -782,7 +782,7 @@ ZEND_API size_t zend_get_scanned_file_offset(void) return offset; } -zend_op_array *compile_string(zend_string *source_string, const char *filename) +zend_op_array *compile_string(zend_string *source_string, const char *filename, zend_compile_position position) { zend_lex_state original_lex_state; zend_op_array *op_array = NULL; @@ -799,7 +799,19 @@ zend_op_array *compile_string(zend_string *source_string, const char *filename) filename_str = zend_string_init(filename, strlen(filename), 0); zend_prepare_string_for_scanning(&tmp, filename_str); zend_string_release(filename_str); - BEGIN(ST_IN_SCRIPTING); + + switch (position) { + case ZEND_COMPILE_POSITION_AT_SHEBANG: + BEGIN(SHEBANG); + break; + case ZEND_COMPILE_POSITION_AT_OPEN_TAG: + BEGIN(INITIAL); + break; + case ZEND_COMPILE_POSITION_AFTER_OPEN_TAG: + BEGIN(ST_IN_SCRIPTING); + break; + } + op_array = zend_compile(ZEND_EVAL_CODE); zend_restore_lexical_state(&original_lex_state); diff --git a/ext/zend_test/test.c b/ext/zend_test/test.c index 4746787b916..677061998d5 100644 --- a/ext/zend_test/test.c +++ b/ext/zend_test/test.c @@ -199,6 +199,41 @@ static ZEND_FUNCTION(zend_string_or_stdclass) } } +static ZEND_FUNCTION(zend_test_compile_string) +{ + zend_string *source_string = NULL; + zend_string *filename = NULL; + zend_long position = ZEND_COMPILE_POSITION_AT_OPEN_TAG; + + ZEND_PARSE_PARAMETERS_START(3, 3) + Z_PARAM_STR(source_string) + Z_PARAM_STR(filename) + Z_PARAM_LONG(position) + ZEND_PARSE_PARAMETERS_END(); + + zend_op_array *op_array = NULL; + + op_array = compile_string(source_string, ZSTR_VAL(filename), position); + + if (op_array) { + zval retval; + + zend_try { + ZVAL_UNDEF(&retval); + zend_execute(op_array, &retval); + } zend_catch { + destroy_op_array(op_array); + efree_size(op_array, sizeof(zend_op_array)); + zend_bailout(); + } zend_end_try(); + + destroy_op_array(op_array); + efree_size(op_array, sizeof(zend_op_array)); + } + + return; +} + /* Tests Z_PARAM_OBJ_OF_CLASS_OR_STR_OR_NULL */ static ZEND_FUNCTION(zend_string_or_stdclass_or_null) { diff --git a/ext/zend_test/test.stub.php b/ext/zend_test/test.stub.php index d8363269114..f8b8b7f1115 100644 --- a/ext/zend_test/test.stub.php +++ b/ext/zend_test/test.stub.php @@ -62,6 +62,8 @@ namespace { function zend_test_void_return(): void {} + function zend_test_compile_string(string $source_string, string $filename, int $position): void {} + /** @deprecated */ function zend_test_deprecated(mixed $arg = null): void {} diff --git a/ext/zend_test/test_arginfo.h b/ext/zend_test/test_arginfo.h index a77bf0d60b2..e1f9b72e7d4 100644 --- a/ext/zend_test/test_arginfo.h +++ b/ext/zend_test/test_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 53832c784e59195e8ef41710c1e4e778f396c99b */ + * Stub hash: 91ffc3205c6ac7b07953c9446e9cb9988d893dd4 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_array_return, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO() @@ -10,6 +10,12 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_void_return, 0, 0, IS_VOID, 0) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_compile_string, 0, 3, IS_VOID, 0) + ZEND_ARG_TYPE_INFO(0, source_string, IS_STRING, 0) + ZEND_ARG_TYPE_INFO(0, filename, IS_STRING, 0) + ZEND_ARG_TYPE_INFO(0, position, IS_LONG, 0) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_deprecated, 0, 0, IS_VOID, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, arg, IS_MIXED, 0, "null") ZEND_END_ARG_INFO() @@ -84,6 +90,7 @@ ZEND_END_ARG_INFO() static ZEND_FUNCTION(zend_test_array_return); static ZEND_FUNCTION(zend_test_nullable_array_return); static ZEND_FUNCTION(zend_test_void_return); +static ZEND_FUNCTION(zend_test_compile_string); static ZEND_FUNCTION(zend_test_deprecated); static ZEND_FUNCTION(zend_create_unterminated_string); static ZEND_FUNCTION(zend_terminate_string); @@ -111,6 +118,7 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(zend_test_array_return, arginfo_zend_test_array_return) ZEND_FE(zend_test_nullable_array_return, arginfo_zend_test_nullable_array_return) ZEND_FE(zend_test_void_return, arginfo_zend_test_void_return) + ZEND_FE(zend_test_compile_string, arginfo_zend_test_compile_string) ZEND_DEP_FE(zend_test_deprecated, arginfo_zend_test_deprecated) ZEND_FE(zend_create_unterminated_string, arginfo_zend_create_unterminated_string) ZEND_FE(zend_terminate_string, arginfo_zend_terminate_string) diff --git a/ext/zend_test/tests/zend_test_compile_string.phpt b/ext/zend_test/tests/zend_test_compile_string.phpt new file mode 100644 index 00000000000..f2449d86ffa --- /dev/null +++ b/ext/zend_test/tests/zend_test_compile_string.phpt @@ -0,0 +1,55 @@ +--TEST-- +Zend: Test compile string +--EXTENSIONS-- +zend_test +--FILE-- + +--EXPECT-- +string(3) "php" +#!/path/to/php +string(3) "php" +string(3) "php" +string(3) "php" + +Parse error: syntax error, unexpected token "<", expecting end of file in Source string on line 1 diff --git a/sapi/fuzzer/fuzzer-execute-common.h b/sapi/fuzzer/fuzzer-execute-common.h index 16834e30383..3189d514c02 100644 --- a/sapi/fuzzer/fuzzer-execute-common.h +++ b/sapi/fuzzer/fuzzer-execute-common.h @@ -60,15 +60,17 @@ static void fuzzer_execute_ex(zend_execute_data *execute_data) { } } -static zend_op_array *(*orig_compile_string)(zend_string *source_string, const char *filename); +static zend_op_array *(*orig_compile_string)( + zend_string *source_string, const char *filename, zend_compile_position position); -static zend_op_array *fuzzer_compile_string(zend_string *str, const char *filename) { +static zend_op_array *fuzzer_compile_string( + zend_string *str, const char *filename, zend_compile_position position) { if (ZSTR_LEN(str) > MAX_SIZE) { /* Avoid compiling huge inputs via eval(). */ fuzzer_bailout(); } - return orig_compile_string(str, filename); + return orig_compile_string(str, filename, position); } static void (*orig_execute_internal)(zend_execute_data *execute_data, zval *return_value); diff --git a/sapi/phpdbg/phpdbg.h b/sapi/phpdbg/phpdbg.h index 789abecc9e7..45c5eb0593b 100644 --- a/sapi/phpdbg/phpdbg.h +++ b/sapi/phpdbg/phpdbg.h @@ -270,7 +270,7 @@ ZEND_BEGIN_MODULE_GLOBALS(phpdbg) zend_op_array *(*compile_file)(zend_file_handle *file_handle, int type); zend_op_array *(*init_compile_file)(zend_file_handle *file_handle, int type); - zend_op_array *(*compile_string)(zend_string *source_string, const char *filename); + zend_op_array *(*compile_string)(zend_string *source_string, const char *filename, zend_compile_position position); HashTable file_sources; zend_arena *oplog_arena; /* arena for storing oplog */ diff --git a/sapi/phpdbg/phpdbg_bp.c b/sapi/phpdbg/phpdbg_bp.c index e48ed5ceba2..3780c890335 100644 --- a/sapi/phpdbg/phpdbg_bp.c +++ b/sapi/phpdbg/phpdbg_bp.c @@ -878,7 +878,7 @@ static inline void phpdbg_create_conditional_break(phpdbg_breakcond_t *brake, co bp_code = zend_string_concat3( "return ", sizeof("return ")-1, expr, expr_len, ";", sizeof(";")-1); - new_break.ops = zend_compile_string(bp_code, "Conditional Breakpoint Code"); + new_break.ops = zend_compile_string(bp_code, "Conditional Breakpoint Code", ZEND_COMPILE_POSITION_AFTER_OPEN_TAG); zend_string_release(bp_code); if (new_break.ops) { diff --git a/sapi/phpdbg/phpdbg_list.c b/sapi/phpdbg/phpdbg_list.c index 2c4d3bbe0ba..00ef995d897 100644 --- a/sapi/phpdbg/phpdbg_list.c +++ b/sapi/phpdbg/phpdbg_list.c @@ -309,7 +309,7 @@ zend_op_array *phpdbg_init_compile_file(zend_file_handle *file, int type) { return op_array; } -zend_op_array *phpdbg_compile_string(zend_string *source_string, const char *filename) { +zend_op_array *phpdbg_compile_string(zend_string *source_string, const char *filename, zend_compile_position position) { zend_string *fake_name; zend_op_array *op_array; phpdbg_file_source *dataptr; @@ -317,7 +317,7 @@ zend_op_array *phpdbg_compile_string(zend_string *source_string, const char *fil char *bufptr, *endptr; if (PHPDBG_G(flags) & PHPDBG_IN_EVAL) { - return PHPDBG_G(compile_string)(source_string, filename); + return PHPDBG_G(compile_string)(source_string, filename, position); } dataptr = emalloc(sizeof(phpdbg_file_source) + sizeof(uint32_t) * ZSTR_LEN(source_string)); @@ -332,7 +332,7 @@ zend_op_array *phpdbg_compile_string(zend_string *source_string, const char *fil dataptr->lines = ++line; dataptr->line[line] = endptr - dataptr->buf; - op_array = PHPDBG_G(compile_string)(source_string, filename); + op_array = PHPDBG_G(compile_string)(source_string, filename, position); if (op_array == NULL) { efree(dataptr->buf); diff --git a/sapi/phpdbg/phpdbg_prompt.c b/sapi/phpdbg/phpdbg_prompt.c index 6597f5fe42c..dfdac95cae5 100644 --- a/sapi/phpdbg/phpdbg_prompt.c +++ b/sapi/phpdbg/phpdbg_prompt.c @@ -514,7 +514,7 @@ exec_code: } /* }}} */ int phpdbg_compile_stdin(zend_string *code) { - PHPDBG_G(ops) = zend_compile_string(code, "Standard input code"); + PHPDBG_G(ops) = zend_compile_string(code, "Standard input code", ZEND_COMPILE_POSITION_AFTER_OPEN_TAG); zend_string_release(code); if (EG(exception)) {