Forgive my ignorance, what is APC?
On Jul 19, 2012 7:15 PM, "Rasmus Lerdorf" <ras...@lerdorf.com> wrote:

> 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
>
>

Reply via email to