Bug #11990 Updated: defined constants getting corrupted

From: Date: Fri, 20 Jul 2001 14:18:02 +0000
Subject: Bug #11990 Updated: defined constants getting corrupted
References: 1  Groups: php.dev 
Request: Send a blank email to php-dev+get-60399@lists.php.net to get a copy of this message
ID: 11990 Updated by: zeev Reported By: blalor@insight.com Status: Closed Bug Type: Scripting Engine problem Operating System: RedHat Linux 6.2 PHP Version: 4.0.5, 4.0.6 New Comment: BTW, the crash had nothing to do with the test case, which was causing an out-of-memory problem. It's not very possible to handle this situation, other than enabling memory_limit. Previous Comments: ------------------------------------------------------------------------ [2001-07-20 10:17:20] zeev@php.net Fixed in the CVS! ------------------------------------------------------------------------ [2001-07-17 12:33:59] blalor@insight.com free -m reports 251MB total on our production box, and 125MB on my dev box. If it is running out of memory, a more gracelful handling of it is necessary... ------------------------------------------------------------------------ [2001-07-17 12:27:58] stas@php.net I get a crash too, but in different place. I fear it might be just you getting out of memory. The script like this has pretty aggressive memory requirements. How much memory do you have? ------------------------------------------------------------------------ [2001-07-16 19:08:56] blalor@insight.com I've spent a better part of the last week trying to dig into this problem. What I've come up with is rather interesting. The source of the problem seems to be that after the first request handled by an Apache child process, PHP doesn't properly clean up, and much of the memory space is polluted. I don't know enough about the Zend internals to be able to figure out exactly happens, but I've deduced that after the first request handled by a process, some defines (entries in the zend_constants hash table) already have some data associated with them. When zend_register_constant() is called, it finds data for a given key and doesn't reassign it. Typically, when a process starts having problems with defines, it segfaults after processing the script. The following is a snippet from /var/log/httpd/error_log with the patch below applied: [11074] Registering string constant HREF_SEC_BASE: https://webtech13.hq.insight.com/web [11074] Constant HREF_SEC_BASE already defined: gnome-terminal [11074] Constant href_sec_base already defined [11074] Beginning compare of data [11074] data1: https://webtech13.hq.insight.com/web [11074] pData(...).val: gnome-terminal [11074] *** Match failed! Data for HREF_SEC_BASE corrupted! As the script is invoked, HREF_SEC_BASE already has (bad) data, in this case "gnome-terminal". diff -urb php-4.0.6.orig/Zend/zend_constants.c php-4.0.6/Zend/zend_constants.c --- php-4.0.6.orig/Zend/zend_constants.c Sun Feb 25 22:43:26 2001 +++ php-4.0.6/Zend/zend_constants.c Mon Jul 16 13:29:21 2001 @@ -23,7 +23,7 @@ #include "zend_variables.h" #include "zend_operators.h" #include "zend_globals.h" - +#include <unistd.h> void free_zend_constant(zend_constant *c) { @@ -243,17 +243,82 @@ { char *lowercase_name = zend_strndup(c->name, c->name_len); int ret = SUCCESS; + zend_constant *pData = NULL; + char *data1 = NULL; + int data1_len; #if 0 printf("Registering constant for module %d\n",c->module_number); #endif zend_str_tolower(lowercase_name, c->name_len); + + switch(c->value.type) { + case IS_STRING: + data1_len = c->value.value.str.len; + data1 = zend_strndup(c->value.value.str.val, data1_len); + + fprintf(stderr, "[%d] Registering string constant %s: %s\n", + getpid(), c->name, c->value.value.str.val); + + if(zend_hash_find(EG(zend_constants), lowercase_name, c->name_len, (void *)&pData) == SUCCESS) { + fprintf(stderr, "[%d] Constant %s already defined: %s\n", + getpid(), + c->name, + pData->value.value.str.val); + + pData = NULL; + } + break; + + default: + if(zend_hash_find(EG(zend_constants), lowercase_name, c->name_len, (void *)&pData) == SUCCESS) { + fprintf(stderr, "[%d] Constant %s already defined\n", + getpid(), + c->name); + + pData = NULL; + } + break; + } + if (zend_hash_add(EG(zend_constants), lowercase_name, c->name_len, (void *) c, sizeof(zend_constant), NULL)==FAILURE) { zval_dtor(&c->value); zend_error(E_NOTICE,"Constant %s already defined",lowercase_name); ret = FAILURE; } + + // retrieve data and compare data + if(c->value.type == IS_STRING) { + if(data1 != NULL) { + if(zend_hash_find(EG(zend_constants), lowercase_name, c->name_len, (void *)&pData) == SUCCESS) { + // compare data + fprintf(stderr, "[%d] Beginning compare of data\n", getpid()); + fprintf(stderr, "[%d] data1: %s\n", getpid(), data1); + fprintf(stderr, "[%d] pData(...).val: %s\n", getpid(), pData->value.value.str.val); + + if(pData->value.value.str.len != data1_len) + fprintf(stderr, "[%d] *** String lengths different!\n", getpid()); + else { + int ind; + char *data2 = pData->value.value.str.val; + + for(ind = 0; ind < pData->value.value.str.len; ind++) { + if(data1[ind] != data2[ind]) { + fprintf(stderr, "[%d] *** Match failed! Data for %s corrupted!\n", + getpid(), c->name); + break; + } + } + } + } else { + fprintf(stderr, "[%d] Couldn't retrieve data for %s\n", getpid(), c->name); + } + + free(data1); + } + } + free(lowercase_name); return ret; } ------------------------------------------------------------------------ [2001-07-10 17:45:20] blalor@insight.com Well, I haven't succeeded yet in reproducing the corrupted define, but I have managed to repeatably kill PHP with a 200002 line script generated by the following shell script: echo "<?php" define="this is a very long define, indeed! asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf" count=0 while [ $count -lt 100000 ]; do echo "define(\"DEF_${count}\", \"$define\");" echo "if(DEF_${count} != \"$define\") { print(\"bad\"); }" count=$(($count + 1)) done echo "?>" I redirected that to a file and ran php through gdb. here's the resulting stack trace: (gdb) run Starting program: /home/blalor/redhat/BUILD/php-4.0.6/php_standalone ../test.php Program received signal SIGSEGV, Segmentation fault. 0x812770b in execute (op_array=0x81dc6c4) at ./zend_execute.c:1639 (gdb) bt #0 0x812770b in execute (op_array=0x81dc6c4) at ./zend_execute.c:1639 #1 0x80ee58b in zend_execute_scripts (type=8, file_count=3) at zend.c:752 #2 0x80635a1 in php_execute_script (primary_file=0xbffff554) at main.c:1206 #3 0x80615c9 in main (argc=2, argv=0xbffff5b4) at cgi_main.c:718 [snip] (gdb) print valptr->value $1 = {lval = 136194132, dval = 1.067726779661273e-313, str = { val = 0x81e2854 "DEF_0", len = 5}, ht = 0x81e2854, obj = {ce = 0x81e2854, properties = 0x5}} Note that it appears that PHP is trying to access the data for DEF_0 at zend_execute.c:1639. Note that I did this with php 4.0.6, not 4.0.5. *Some* kind of problem still exists there... ------------------------------------------------------------------------ The remainder of the comments for this report are too long. To view the rest of the comments, please view the bug report online at http://bugs.php.net/?id=11990 Edit this bug report at http://bugs.php.net/?id=11990&edit=1

« previous php.dev (#60399) next »