The goal of this message is to encourage and motivate a few people to give me a hand with tracking down APC bugs. There are still a few outstanding bugs that is slowing PHP 5.4 adoption and it would be really nice to plow through these instead of wasting cycles on some of the other discussions going on here.
The example bug I will use is one I just fixed. Bug http://php.net/62398 which was that with apc.stat=0 the second request (eg. the cached request) to a certain script would have include filenames replaced with an empty string. Clue #1 here is that we are dealing with string literals and those obviously changed a lot in 5.4. Clue #2 I got lucky with. I was able to reproduce it locally which makes everything much simpler because then Valgrind can do most of the thinking for us. So, knowing it has to do with string literals and taking my reproduce case, I first eliminated all non-php code by using the built-in web server in 5.4. I have a little memcheck shell script that runs Valgrind with my preferred options. It looks like this: #!/bin/bash USE_ZEND_ALLOC=0 valgrind --tool=memcheck --suppressions=/home/rasmus/.suppressions --leak-check=yes --track-origins=yes --num-callers =30 --show-reachable=yes "$@" And my .suppressions file can be found here: http://lerdorf.com/suppressions.txt Then I did: cd /var/www/docroot memcheck php -S localhost:8888 and hit port 8888 with my browser. Valgrind essentially told me exactly what was wrong: ==30123== Conditional jump or move depends on uninitialised value(s) ==30123== at 0x9B35B5: ZEND_INCLUDE_OR_EVAL_SPEC_CONST_HANDLER (zend_vm_execute.h:2535) ==30123== by 0x9AA5E1: execute (zend_vm_execute.h:410) ==30123== by 0x96F115: zend_execute_scripts (zend.c:1279) ==30123== by 0x8E050F: php_execute_script (main.c:2473) ==30123== by 0xAAFC6E: php_cli_server_dispatch_script (php_cli_server.c:1847) ==30123== by 0xAB0DA8: php_cli_server_dispatch (php_cli_server.c:2008) ==30123== by 0xAB14CE: php_cli_server_recv_event_read_request (php_cli_server.c:2189) ==30123== by 0xAB17EF: php_cli_server_do_event_for_each_fd_callback (php_cli_server.c:2275) ==30123== by 0xAACDBE: php_cli_server_poller_iter_on_active (php_cli_server.c:793) ==30123== by 0xAB18AF: php_cli_server_do_event_for_each_fd (php_cli_server.c:2301) ==30123== by 0xAB1903: php_cli_server_do_event_loop (php_cli_server.c:2311) ==30123== by 0xAB1C7D: do_cli_server (php_cli_server.c:2412) ==30123== by 0xAA68C7: main (php_cli.c:1364) ==30123== Uninitialised value was created by a client request ==30123== at 0xD750FC7: apc_realpool_alloc (apc_pool.c:307) ==30123== by 0xD74B9D6: apc_copy_op_array (apc_compile.c:1271) ==30123== by 0xD74DAF1: apc_compile_cache_entry (apc_main.c:450) ==30123== by 0xD74E414: my_compile_file (apc_main.c:610) ==30123== by 0x6FAC25: phar_compile_file (phar.c:3391) ==30123== by 0x91768D: compile_filename (zend_language_scanner.l:625) ==30123== by 0x9B394C: ZEND_INCLUDE_OR_EVAL_SPEC_CONST_HANDLER (zend_vm_execute.h:2592) ==30123== by 0x9AA5E1: execute (zend_vm_execute.h:410) ==30123== by 0x96F115: zend_execute_scripts (zend.c:1279) ==30123== by 0x8E050F: php_execute_script (main.c:2473) ==30123== by 0xAAFC6E: php_cli_server_dispatch_script (php_cli_server.c:1847) ==30123== by 0xAB0DA8: php_cli_server_dispatch (php_cli_server.c:2008) ==30123== by 0xAB14CE: php_cli_server_recv_event_read_request (php_cli_server.c:2189) ==30123== by 0xAB17EF: php_cli_server_do_event_for_each_fd_callback (php_cli_server.c:2275) ==30123== by 0xAACDBE: php_cli_server_poller_iter_on_active (php_cli_server.c:793) ==30123== by 0xAB18AF: php_cli_server_do_event_for_each_fd (php_cli_server.c:2301) ==30123== by 0xAB1903: php_cli_server_do_event_loop (php_cli_server.c:2311) ==30123== by 0xAB1C7D: do_cli_server (php_cli_server.c:2412) ==30123== by 0xAA68C7: main (php_cli.c:1364) zend_vm_execute.h:2535 looks like this: if (inc_filename->type!=IS_STRING) { and Valgrind is saying that the conditional depends on an uninitialised value. Ok, that means inc_filename->type is somehow not set here. Looking just above this line we see that inc_filename is just op1: inc_filename = _get_zval_ptr_tmp(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC); Next, Valgrind even tells us where this unitialized value is coming from: ==30123== Uninitialised value was created by a client request ==30123== at 0xD750FC7: apc_realpool_alloc (apc_pool.c:307) ==30123== by 0xD74B9D6: apc_copy_op_array (apc_compile.c:1271) Ok, so it is in memory allocated in apc_pool.c. That in itself is not that interesting. Everything is in allocated pool memory. What is more interesting is what happens to this allocated pool right after it is allocated and we see the caller is apc_compile.c line 1271. Starting at line 1270 that block of code looks like this: #ifdef ZEND_ENGINE_2_4 dzo->op1.literal = (zend_literal*) apc_pool_alloc(pool, sizeof(zend_literal)); Z_STRLEN_P(dzo->op1.zv) = strlen(fullpath); Z_STRVAL_P(dzo->op1.zv) = apc_pstrdup(fullpath, pool TSRMLS_CC); Z_SET_REFCOUNT_P(dzo->op1.zv, 2); Z_SET_ISREF_P(dzo->op1.zv); dzo->op1.literal->hash_value = zend_hash_func(Z_STRVAL_P(dzo->op1.zv), Z_STRLEN_P(dzo->op1.zv)+1); #else dzo->op1.u.constant.value.str.len = strlen(fullpath); dzo->op1.u.constant.value.str.val = apc_pstrdup(fullpath, pool TSRMLS_CC); #endif So we can see from the ifdef that what used to just be a simple op1 string initialization before the new string literal optimization in 5.4 is now much more complicated. We generate op1 and calculate the hash. But since we are now working with a naked zv instead of a string constant, we need to set the type as Valgrind illustrated: Z_TYPE_P(dzo->op1.zv) = IS_STRING; and that indeed fixes the bug. Running memcheck again there are no complaints from Valgrind (except for on server-shutdown, but those are normal). Usually these APC bugs are trickier than this. I got lucky on this one. But the steps are similar, you may need to spend some time in gdb as well to figure out why a certain variable ends up in a certain state or why a section of code is or isn't being run. -Rasmus -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php