From: Dmitry Stogov Date: Thu, 22 Nov 2007 13:33:53 +0000 (+0000) Subject: Fixed bug #43128 (Very long class name causes segfault) X-Git-Tag: RELEASE_2_0_0a1~1306 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=47dc82ecb99f45b6757fd2de5559fcc94e1da49f;p=php Fixed bug #43128 (Very long class name causes segfault) --- diff --git a/TSRM/tsrm_config_common.h b/TSRM/tsrm_config_common.h index 0c6a2a183f..d2b9bfc994 100644 --- a/TSRM/tsrm_config_common.h +++ b/TSRM/tsrm_config_common.h @@ -52,9 +52,17 @@ char *alloca (); #endif #if (HAVE_ALLOCA || (defined (__GNUC__) && __GNUC__ >= 2)) -# define tsrm_do_alloca(p) alloca(p) -# define tsrm_free_alloca(p) +# define TSRM_ALLOCA_MAX_SIZE 4096 +# define TSRM_ALLOCA_FLAG(name) \ + int name; +# define tsrm_do_alloca_ex(size, limit, use_heap) \ + ((use_heap = ((size) > (limit))) ? malloc(size) : alloca(size)) +# define tsrm_do_alloca(size, use_heap) \ + tsrm_do_alloca_ex(size, TSRM_ALLOCA_MAX_SIZE, use_heap) +# define tsrm_free_alloca(p, use_heap) \ + do { if (use_heap) free(p); } while (0) #else +# define TSRM_ALLOCA_FLAG(name) # define tsrm_do_alloca(p) malloc(p) # define tsrm_free_alloca(p) free(p) #endif diff --git a/TSRM/tsrm_virtual_cwd.c b/TSRM/tsrm_virtual_cwd.c index 6918fe3b53..36747810d8 100644 --- a/TSRM/tsrm_virtual_cwd.c +++ b/TSRM/tsrm_virtual_cwd.c @@ -777,6 +777,7 @@ CWD_API int virtual_chdir_file(const char *path, int (*p_chdir)(const char *path int length = strlen(path); char *temp; int retval; + TSRM_ALLOCA_FLAG(use_heap) if (length == 0) { return 1; /* Can't cd to empty string */ @@ -793,14 +794,14 @@ CWD_API int virtual_chdir_file(const char *path, int (*p_chdir)(const char *path if (length == COPY_WHEN_ABSOLUTE(path) && IS_ABSOLUTE_PATH(path, length+1)) { /* Also use trailing slash if this is absolute */ length++; } - temp = (char *) tsrm_do_alloca(length+1); + temp = (char *) tsrm_do_alloca(length+1, use_heap); memcpy(temp, path, length); temp[length] = 0; #if VIRTUAL_CWD_DEBUG fprintf (stderr, "Changing directory to %s\n", temp); #endif retval = p_chdir(temp TSRMLS_CC); - tsrm_free_alloca(temp); + tsrm_free_alloca(temp, use_heap); return retval; } /* }}} */ diff --git a/Zend/tests/bug43128.phpt b/Zend/tests/bug43128.phpt new file mode 100755 index 0000000000..4ee676a0a4 --- /dev/null +++ b/Zend/tests/bug43128.phpt @@ -0,0 +1,17 @@ +--TEST-- +Bug #43128 Very long class name causes segfault +--FILE-- +$a(); // Fatal error + +if ($a instanceof $a); // Segmentation fault +new $a; // Segmentation fault +echo "ok\n"; +--EXPECT-- +ok diff --git a/Zend/zend.h b/Zend/zend.h index 6147c31013..22b083ba5e 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -178,11 +178,19 @@ char *alloca (); #endif #if (HAVE_ALLOCA || (defined (__GNUC__) && __GNUC__ >= 2)) && !(defined(ZTS) && defined(ZEND_WIN32)) && !(defined(ZTS) && defined(NETWARE)) && !(defined(ZTS) && defined(HPUX)) && !defined(DARWIN) -# define do_alloca(p) alloca(p) -# define free_alloca(p) +# define ZEND_ALLOCA_MAX_SIZE (32 * 1024) +# define ALLOCA_FLAG(name) \ + zend_bool name; +# define do_alloca_ex(size, limit, use_heap) \ + ((use_heap = (UNEXPECTED((size) > (limit)))) ? emalloc(size) : alloca(size)) +# define do_alloca(size, use_heap) \ + do_alloca_ex(size, ZEND_ALLOCA_MAX_SIZE, use_heap) +# define free_alloca(p, use_heap) \ + do { if (UNEXPECTED(use_heap)) efree(p); } while (0) #else +# define ALLOCA_FLAG(name) # define do_alloca(p) emalloc(p) -# define free_alloca(p) efree(p) +# define free_alloca(p) efree(p) #endif #if ZEND_DEBUG diff --git a/Zend/zend_API.c b/Zend/zend_API.c index 40472de744..c9b474555d 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -2195,11 +2195,10 @@ ZEND_API int zend_register_functions(zend_class_entry *scope, const zend_functio } } fname_len = strlen(ptr->fname); - lowercase_name = do_alloca(fname_len+1); - zend_str_tolower_copy(lowercase_name, ptr->fname, fname_len); + lowercase_name = zend_str_tolower_dup(ptr->fname, fname_len); if (zend_ascii_hash_add(target_function_table, lowercase_name, fname_len+1, &function, sizeof(zend_function), (void**)®_function) == FAILURE) { unload=1; - free_alloca(lowercase_name); + efree(lowercase_name); break; } if (scope) { @@ -2245,7 +2244,7 @@ ZEND_API int zend_register_functions(zend_class_entry *scope, const zend_functio } ptr++; count++; - free_alloca(lowercase_name); + efree(lowercase_name); } if (unload) { /* before unloading, display all remaining bad function in the module */ if (scope) { @@ -3270,11 +3269,12 @@ ZEND_API int zend_declare_property_ex(zend_class_entry *ce, char *name, int name if (UG(unicode)) { zstr uname; int ret; + ALLOCA_FLAG(use_heap) - uname.u = do_alloca(UBYTES(name_length+1)); + uname.u = do_alloca(UBYTES(name_length+1), use_heap); u_charsToUChars(name, uname.u, name_length+1); ret = zend_u_declare_property_ex(ce, IS_UNICODE, uname, name_length, property, access_type, doc_comment, doc_comment_len TSRMLS_CC); - free_alloca(uname.u); + free_alloca(uname.u, use_heap); return ret; } else { return zend_u_declare_property_ex(ce, IS_STRING, ZSTR(name), name_length, property, access_type, doc_comment, doc_comment_len TSRMLS_CC); @@ -3293,11 +3293,12 @@ ZEND_API int zend_declare_property(zend_class_entry *ce, char *name, int name_le if (UG(unicode)) { zstr uname; int ret; + ALLOCA_FLAG(use_heap) - uname.u = do_alloca(UBYTES(name_length+1)); + uname.u = do_alloca(UBYTES(name_length+1), use_heap); u_charsToUChars(name, uname.u, name_length+1); ret = zend_u_declare_property_ex(ce, IS_UNICODE, uname, name_length, property, access_type, NULL_ZSTR, 0 TSRMLS_CC); - free_alloca(uname.u); + free_alloca(uname.u, use_heap); return ret; } else { return zend_u_declare_property_ex(ce, IS_STRING, ZSTR(name), name_length, property, access_type, NULL_ZSTR, 0 TSRMLS_CC); diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 1a11224495..6f71b4bb95 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -304,6 +304,7 @@ struct _zend_execute_data { union _temp_variable *Ts; zval ***CVs; zend_bool original_in_execution; + ALLOCA_FLAG(use_heap) HashTable *symbol_table; struct _zend_execute_data *prev_execute_data; zval *old_error_reporting; diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 69bf58fca6..7d44ecd8ef 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -1447,12 +1447,7 @@ ZEND_API void execute_internal(zend_execute_data *execute_data_ptr, int return_v } #define ZEND_VM_EXIT_FROM_EXECUTE_LOOP() \ - free_alloca(EX(CVs)); \ - if (EX(op_array)->T < TEMP_VAR_STACK_LIMIT) { \ - free_alloca(EX(Ts)); \ - } else { \ - efree(EX(Ts)); \ - } \ + free_alloca(EX(CVs), EX(use_heap)); \ EG(in_execution) = EX(original_in_execution); \ EG(current_execute_data) = EX(prev_execute_data); \ EG(opline_ptr) = NULL; diff --git a/Zend/zend_strtod.c b/Zend/zend_strtod.c index fad9594105..78dc79be98 100644 --- a/Zend/zend_strtod.c +++ b/Zend/zend_strtod.c @@ -2603,6 +2603,7 @@ ZEND_API double zend_u_strtod(const UChar *nptr, UChar **endptr) /* {{{ */ const UChar *u = nptr, *nstart; UChar c = *u; int any = 0; + ALLOCA_FLAG(use_heap) while (u_isspace(c)) { c = *++u; @@ -2653,7 +2654,7 @@ ZEND_API double zend_u_strtod(const UChar *nptr, UChar **endptr) /* {{{ */ if (length < sizeof(buf)) { numbuf = buf; } else { - numbuf = (char *) do_alloca(length + 1); + numbuf = (char *) do_alloca(length + 1, use_heap); } bufpos = numbuf; @@ -2666,7 +2667,7 @@ ZEND_API double zend_u_strtod(const UChar *nptr, UChar **endptr) /* {{{ */ value = zend_strtod(numbuf, NULL); if (numbuf != buf) { - free_alloca(numbuf); + free_alloca(numbuf, use_heap); } if (endptr != NULL) { diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 3ba21f1a94..99a2bf4a37 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -45,12 +45,13 @@ ZEND_API void execute(zend_op_array *op_array TSRMLS_DC) EX(called_scope) = NULL; EX(object) = NULL; EX(old_error_reporting) = NULL; - if (op_array->T < TEMP_VAR_STACK_LIMIT) { - EX(Ts) = (temp_variable *) do_alloca(sizeof(temp_variable) * op_array->T); + if (EXPECTED(op_array->T < TEMP_VAR_STACK_LIMIT && op_array->last_var < TEMP_VAR_STACK_LIMIT)) { + EX(CVs) = (zval***)do_alloca(sizeof(zval**) * op_array->last_var + sizeof(temp_variable) * op_array->T, EX(use_heap)); } else { - EX(Ts) = (temp_variable *) safe_emalloc(sizeof(temp_variable), op_array->T, 0); + EX(use_heap) = 1; + EX(CVs) = (zval***)safe_emalloc(sizeof(temp_variable), op_array->T, sizeof(zval**) * op_array->last_var); } - EX(CVs) = (zval***)do_alloca(sizeof(zval**) * op_array->last_var); + EX(Ts) = (temp_variable *)(EX(CVs) + op_array->last_var); memset(EX(CVs), 0, sizeof(zval**) * op_array->last_var); EX(op_array) = op_array; EX(original_in_execution) = EG(in_execution); diff --git a/Zend/zend_vm_execute.skl b/Zend/zend_vm_execute.skl index 5076e5ee8b..b4366b80ee 100644 --- a/Zend/zend_vm_execute.skl +++ b/Zend/zend_vm_execute.skl @@ -16,12 +16,13 @@ ZEND_API void {%EXECUTOR_NAME%}(zend_op_array *op_array TSRMLS_DC) EX(called_scope) = NULL; EX(object) = NULL; EX(old_error_reporting) = NULL; - if (op_array->T < TEMP_VAR_STACK_LIMIT) { - EX(Ts) = (temp_variable *) do_alloca(sizeof(temp_variable) * op_array->T); + if (EXPECTED(op_array->T < TEMP_VAR_STACK_LIMIT && op_array->last_var < TEMP_VAR_STACK_LIMIT)) { + EX(CVs) = (zval***)do_alloca(sizeof(zval**) * op_array->last_var + sizeof(temp_variable) * op_array->T, EX(use_heap)); } else { - EX(Ts) = (temp_variable *) safe_emalloc(sizeof(temp_variable), op_array->T, 0); + EX(use_heap) = 1; + EX(CVs) = (zval***)safe_emalloc(sizeof(temp_variable), op_array->T, sizeof(zval**) * op_array->last_var); } - EX(CVs) = (zval***)do_alloca(sizeof(zval**) * op_array->last_var); + EX(Ts) = (temp_variable *)(EX(CVs) + op_array->last_var); memset(EX(CVs), 0, sizeof(zval**) * op_array->last_var); EX(op_array) = op_array; EX(original_in_execution) = EG(in_execution); diff --git a/ext/interbase/ibase_query.c b/ext/interbase/ibase_query.c index 3e2a0fe35f..09b39d6240 100644 --- a/ext/interbase/ibase_query.c +++ b/ext/interbase/ibase_query.c @@ -1836,6 +1836,7 @@ PHP_FUNCTION(ibase_execute) zval *query, ***args = NULL; ibase_query *ib_query; ibase_result *result = NULL; + ALLOCA_FLAG(use_heap) RESET_ERRMSG; @@ -1859,7 +1860,7 @@ PHP_FUNCTION(ibase_execute) } } else if (bind_n > 0) { /* have variables to bind */ - args = (zval ***) do_alloca(ZEND_NUM_ARGS() * sizeof(zval **)); + args = (zval ***) do_alloca(ZEND_NUM_ARGS() * sizeof(zval **), use_heap); if (FAILURE == zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args)) { break; @@ -1900,7 +1901,7 @@ PHP_FUNCTION(ibase_execute) } while (0); if (args) { - free_alloca(args); + free_alloca(args, use_heap); } } /* }}} */ diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 37ca021614..55114b2134 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -1065,14 +1065,15 @@ static void reflection_extension_factory(zval *object, const char *name_str TSRM int name_len = strlen(name_str); char *lcname; struct _zend_module_entry *module; + ALLOCA_FLAG(use_heap) - lcname = do_alloca(name_len + 1); + lcname = do_alloca(name_len + 1, use_heap); zend_str_tolower_copy(lcname, name_str, name_len); if (zend_hash_find(&module_registry, lcname, name_len + 1, (void **)&module) == FAILURE) { - free_alloca(lcname); + free_alloca(lcname, use_heap); return; } - free_alloca(lcname); + free_alloca(lcname, use_heap); reflection_instantiate(reflection_extension_ptr, object TSRMLS_CC); intern = (reflection_object *) zend_object_store_get_object(object TSRMLS_CC); @@ -4240,6 +4241,7 @@ ZEND_METHOD(reflection_extension, __construct) zend_module_entry *module; char *name_str; int name_len; + ALLOCA_FLAG(use_heap) if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name_str, &name_len) == FAILURE) { return; @@ -4250,15 +4252,15 @@ ZEND_METHOD(reflection_extension, __construct) if (intern == NULL) { return; } - lcname = do_alloca(name_len + 1); + lcname = do_alloca(name_len + 1, use_heap); zend_str_tolower_copy(lcname, name_str, name_len); if (zend_hash_find(&module_registry, lcname, name_len + 1, (void **)&module) == FAILURE) { - free_alloca(lcname); + free_alloca(lcname, use_heap); zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Extension %s does not exist", name_str); return; } - free_alloca(lcname); + free_alloca(lcname, use_heap); MAKE_STD_ZVAL(name); ZVAL_ASCII_STRING(name, module->name, 1); zend_ascii_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL); diff --git a/main/main.c b/main/main.c index 998e351eeb..c6816b8b94 100644 --- a/main/main.c +++ b/main/main.c @@ -2090,6 +2090,7 @@ PHPAPI int php_execute_script(zend_file_handle *primary_file TSRMLS_DC) int old_cwd_fd = -1; #else char *old_cwd; + ALLOCA_FLAG(use_heap) #endif int retval = 0; @@ -2100,7 +2101,7 @@ PHPAPI int php_execute_script(zend_file_handle *primary_file TSRMLS_DC) } #ifndef HAVE_BROKEN_GETCWD # define OLD_CWD_SIZE 4096 - old_cwd = do_alloca(OLD_CWD_SIZE); + old_cwd = do_alloca(OLD_CWD_SIZE, use_heap); old_cwd[0] = '\0'; #endif @@ -2177,7 +2178,7 @@ PHPAPI int php_execute_script(zend_file_handle *primary_file TSRMLS_DC) if (old_cwd[0] != '\0') { VCWD_CHDIR(old_cwd); } - free_alloca(old_cwd); + free_alloca(old_cwd, use_heap); #endif return retval; } @@ -2188,10 +2189,11 @@ PHPAPI int php_execute_script(zend_file_handle *primary_file TSRMLS_DC) PHPAPI int php_execute_simple_script(zend_file_handle *primary_file, zval **ret TSRMLS_DC) { char *old_cwd; + ALLOCA_FLAG(use_heap) EG(exit_status) = 0; #define OLD_CWD_SIZE 4096 - old_cwd = do_alloca(OLD_CWD_SIZE); + old_cwd = do_alloca(OLD_CWD_SIZE, use_heap); old_cwd[0] = '\0'; zend_try { @@ -2212,7 +2214,7 @@ PHPAPI int php_execute_simple_script(zend_file_handle *primary_file, zval **ret VCWD_CHDIR(old_cwd); } - free_alloca(old_cwd); + free_alloca(old_cwd, use_heap); return EG(exit_status); } /* }}} */