]> granicus.if.org Git - php/commitdiff
Fixed bug #43128 (Very long class name causes segfault)
authorDmitry Stogov <dmitry@php.net>
Thu, 22 Nov 2007 13:33:53 +0000 (13:33 +0000)
committerDmitry Stogov <dmitry@php.net>
Thu, 22 Nov 2007 13:33:53 +0000 (13:33 +0000)
13 files changed:
TSRM/tsrm_config_common.h
TSRM/tsrm_virtual_cwd.c
Zend/tests/bug43128.phpt [new file with mode: 0755]
Zend/zend.h
Zend/zend_API.c
Zend/zend_compile.h
Zend/zend_execute.c
Zend/zend_strtod.c
Zend/zend_vm_execute.h
Zend/zend_vm_execute.skl
ext/interbase/ibase_query.c
ext/reflection/php_reflection.c
main/main.c

index 0c6a2a183fc0b9725c97134a1e7ac62e971abe01..d2b9bfc99404835b14080d32c7720376a2665d3d 100644 (file)
@@ -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
index 6918fe3b534336098a8e0e153872b74903a05fa2..36747810d850f42576aefb36c29112507d22de25 100644 (file)
@@ -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 (executable)
index 0000000..4ee676a
--- /dev/null
@@ -0,0 +1,17 @@
+--TEST--
+Bug #43128 Very long class name causes segfault 
+--FILE--
+<?php
+
+$a = str_repeat("a", 10 * 1024 * 1024);
+
+eval("class $a {}");
+
+# call_user_func($a); // Warning
+# $a->$a();           // Fatal error
+
+if ($a instanceof $a); // Segmentation fault
+new $a;                // Segmentation fault
+echo "ok\n";
+--EXPECT--
+ok
index 6147c3101345b4c6a406c26213dd77805fe08c29..22b083ba5e6eefed27f94b922fc5c05555cfd4c6 100644 (file)
@@ -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
index 40472de744028e11313dad7bd1df7ac559c3923f..c9b474555db1d94f146ac806d774016ddf4b3dd2 100644 (file)
@@ -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**)&reg_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);
index 1a11224495b17151e6fc12a66ea2590a2790a5a8..6f71b4bb95498c251320b6d9c3d5c7071bdc05ec 100644 (file)
@@ -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;
index 69bf58fca67d21f93343ce7148877d7d664f09af..7d44ecd8ef6c431643d81c4b89a2ffb5ed12db37 100644 (file)
@@ -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;
index fad9594105916e0826dbc3d1348eab821e511397..78dc79be98e9883f72890ed964076433e66990cd 100644 (file)
@@ -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) {
index 3ba21f1a94c2cc029cb9388198f810245c3a60b0..99a2bf4a37ab67fe3c82414a1054acb69e4d4580 100644 (file)
@@ -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);
index 5076e5ee8b87aad57ec343b3e1d7aad1277c455c..b4366b80ee1cbf4f5bc1286b7ea17624f358b20d 100644 (file)
@@ -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);
index 3e2a0fe35f139194acb3267fbba17149852408e0..09b39d6240693a452fb5d95f2edecfda173ef757 100644 (file)
@@ -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);
        }
 }
 /* }}} */
index 37ca021614f8710f77b79556fb2887257ad3ec56..55114b2134317d77d1d86c7ba54fdd37d8be9e30 100644 (file)
@@ -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);
index 998e351eeb68da1ea6a1d3f9e31bec0d7c93671f..c6816b8b94ae62dd73c0314bb45bcd11b7e80dca 100644 (file)
@@ -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);
 }
 /* }}} */