[php-src] Issue #11078: PHP Fatal error triggers pointer being freed was not allocated and malloc: double free for ptr errors

From: Date: Sat, 15 Apr 2023 01:52:42 +0000
Subject: [php-src] Issue #11078: PHP Fatal error triggers pointer being freed was not allocated and malloc: double free for ptr errors
Groups: php.bugs 
Request: Send a blank email to php-bugs+get-244201@lists.php.net to get a copy of this message
Issue: https://github.com/php/php-src/issues/11078 Author: lucasnetau ### Description The following code: https://gist.github.com/lucasnetau/244ba31f321307e06177f48582273e86 Resulted in this output: ``` php(95590,0x7ff847fe5680) malloc: double free for ptr 0x7fd2c0198000 php(95560,0x7ff847fe5680) malloc: *** error for object 0x7fc2e801800a: pointer being freed was not allocated SIGABRT ``` To trigger the issue a PHP Fatal error (out of memory) needs to occur in a write to a custom streamWrapper, the test case forces this quickly (pointer issue occurs on each run, double free occurs on most runs but not all). Notably when CURLOPT_HTTPHEADER is set the double free occurs in libcurl, when CURLOPT_HTTPHEADER is not set then the point being freed error occurs. Double Free backtrace: ``` * thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGABRT frame #0: 0x00007ff80467022a libsystem_kernel.dylib`__pthread_kill + 10 libsystem_kernel.dylib`: -> 0x7ff80467022a <+10>: jae 0x7ff804670234 ; <+20> 0x7ff80467022c <+12>: movq %rax, %rdi 0x7ff80467022f <+15>: jmp 0x7ff804669ce2 ; cerror_nocancel 0x7ff804670234 <+20>: retq Target 0: (php) stopped. (lldb) bt * thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGABRT * frame #0: 0x00007ff80467022a libsystem_kernel.dylib`__pthread_kill + 10 frame #1: 0x00007ff8046a7f7b libsystem_pthread.dylib`pthread_kill + 263 frame #2: 0x00007ff8045f1ca5 libsystem_c.dylib`abort + 123 frame #3: 0x00007ff804507637 libsystem_malloc.dylib`malloc_vreport + 888 frame #4: 0x00007ff80451c897 libsystem_malloc.dylib`malloc_zone_error + 178 frame #5: 0x0000000101b920ce libcurl.4.dylib`Curl_close(datap=0x00007ff7bfefe9d0) at url.c:410:3 [opt] frame #6: 0x0000000101b565e0 libcurl.4.dylib`curl_easy_cleanup(data=0x0000000000000000) at easy.c:804:3 [opt] frame #7: 0x00000001000735dd php`curl_free_obj(object=0x0000000103bcd798) at interface.c:2839:2 [opt] frame #8: 0x000000010047b31e php`zend_objects_store_del(object=0x0000000103bcd798) at zend_objects_API.c:200:4 [opt] frame #9: 0x00000001003d26af php`zend_llist_destroy(l=0x0000000103bc70a8) at zend_llist.c:109:4 [opt] frame #10: 0x00000001003d2703 php`zend_llist_clean(l=0x0000000103bc70a8) at zend_llist.c:123:2 [opt] frame #11: 0x000000010007ab71 php`curl_multi_free_obj(object=<unavailable>) at multi.c:555:2 [opt] frame #12: 0x000000010047b167 php`zend_objects_store_free_object_storage(objects=<unavailable>, fast_shutdown=<unavailable>) at zend_objects_API.c:122:6 [opt] frame #13: 0x00000001003cf2f2 php`zend_shutdown_executor_values(fast_shutdown=<unavailable>) at zend_execute_API.c:399:2 [opt] frame #14: 0x00000001003cf3d8 php`shutdown_executor at zend_execute_API.c:416:2 [opt] frame #15: 0x00000001003df2bc php`zend_deactivate at zend.c:1258:2 [opt] frame #16: 0x000000010037a1e5 php`php_request_shutdown(dummy=0x0000000000000000) at main.c:1863:2 [opt] frame #17: 0x00000001004c41dc php`do_cli(argc=4, argv=0x0000600000c08c90) at php_cli.c:1135:3 [opt] frame #18: 0x00000001004c1e81 php`main(argc=4, argv=0x0000600000c08c90) at php_cli.c:1333:18 [opt] frame #19: 0x00007ff804375310 dyld`start + 2432 (lldb) f 5 warning: libcurl.4.dylib was compiled with optimization - stepping may behave oddly; variables may not be available. frame #5: 0x0000000101b920ce libcurl.4.dylib`Curl_close(datap=0x00007ff7bfefe9d0) at url.c:410:3 [opt] 407 up_free(data); 408 Curl_safefree(data->state.buffer); 409 Curl_dyn_free(&data->state.headerb); -> 410 Curl_safefree(data->state.ulbuf); 411 Curl_flush_cookies(data, TRUE); 412 Curl_altsvc_save(data, data->asi, data->set.str[STRING_ALTSVC]); 413 Curl_altsvc_cleanup(&data->asi); (lldb) f 6 frame #6: 0x0000000101b565e0 libcurl.4.dylib`curl_easy_cleanup(data=0x0000000000000000) at easy.c:804:3 [opt] 801 return; 802 803 sigpipe_ignore(data, &pipe_st); -> 804 Curl_close(&data); 805 sigpipe_restore(&pipe_st); 806 } 807 (lldb) f 7 warning: php was compiled with optimization - stepping may behave oddly; variables may not be available. frame #7: 0x00000001000735dd php`curl_free_obj(object=0x0000000103bcd798) at interface.c:2839:2 [opt] 2836 curl_easy_setopt(ch->cp, CURLOPT_HEADERFUNCTION, curl_write_nothing); 2837 curl_easy_setopt(ch->cp, CURLOPT_WRITEFUNCTION, curl_write_nothing); 2838 -> 2839 curl_easy_cleanup(ch->cp); 2840 2841 /* cURL destructors should be invoked only by last curl handle */ 2842 if (--(*ch->clone) == 0) { ``` Pointer being freed was not allocated: ``` * thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGABRT frame #0: 0x00007ff80467022a libsystem_kernel.dylib`__pthread_kill + 10 libsystem_kernel.dylib`: -> 0x7ff80467022a <+10>: jae 0x7ff804670234 ; <+20> 0x7ff80467022c <+12>: movq %rax, %rdi 0x7ff80467022f <+15>: jmp 0x7ff804669ce2 ; cerror_nocancel 0x7ff804670234 <+20>: retq Target 0: (php) stopped. (lldb) bt * thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGABRT * frame #0: 0x00007ff80467022a libsystem_kernel.dylib`__pthread_kill + 10 frame #1: 0x00007ff8046a7f7b libsystem_pthread.dylib`pthread_kill + 263 frame #2: 0x00007ff8045f1ca5 libsystem_c.dylib`abort + 123 frame #3: 0x00007ff804507637 libsystem_malloc.dylib`malloc_vreport + 888 frame #4: 0x00007ff80450a951 libsystem_malloc.dylib`malloc_report + 151 frame #5: 0x00007ff804595860 libsystem_c.dylib`fclose + 140 frame #6: 0x0000000100391f0b php`stream_resource_regular_dtor(rsrc=<unavailable>) at streams.c:1761:19 [opt] frame #7: 0x00000001003f539a php`zend_resource_dtor(res=<unavailable>) at zend_list.c:73:3 [opt] frame #8: 0x00000001003f56df php`zend_close_rsrc_list(ht=0x0000000100ed5c30) at zend_list.c:225:5 [opt] frame #9: 0x00000001003cf5dc php`zend_shutdown_executor_values(fast_shutdown=<unavailable>) at zend_execute_API.c:277:3 [opt] frame #10: 0x00000001003cfcd8 php`shutdown_executor at zend_execute_API.c:416:2 [opt] frame #11: 0x00000001003dfbbc php`zend_deactivate at zend.c:1258:2 [opt] frame #12: 0x000000010037aae5 php`php_request_shutdown(dummy=0x0000000000000000) at main.c:1863:2 [opt] frame #13: 0x00000001004c4adc php`do_cli(argc=2, argv=0x00006000002080e0) at php_cli.c:1135:3 [opt] frame #14: 0x00000001004c2781 php`main(argc=2, argv=0x00006000002080e0) at php_cli.c:1333:18 [opt] frame #15: 0x00007ff804375310 dyld`start + 2432 (lldb) f 6 warning: php was compiled with optimization - stepping may behave oddly; variables may not be available. frame #6: 0x0000000100391f0b php`stream_resource_regular_dtor(rsrc=<unavailable>) at streams.c:1761:19 [opt] 1758 { 1759 php_stream *stream = (php_stream*)rsrc->ptr; 1760 /* set the return value for pclose */ -> 1761 FG(pclose_ret) = php_stream_free(stream, PHP_STREAM_FREE_CLOSE | PHP_STREAM_FREE_RSRC_DTOR); 1762 } 1763 1764 static void stream_resource_persistent_dtor(zend_resource *rsrc) (lldb) f 7 frame #7: 0x00000001003f539a php`zend_resource_dtor(res=<unavailable>) at zend_list.c:73:3 [opt] 70 ZEND_ASSERT(ld && "Unknown list entry type"); 71 72 if (ld->list_dtor_ex) { -> 73 ld->list_dtor_ex(&r); 74 } 75 } 76 ``` Double free was reported to curl via https://github.com/curl/curl/issues/10964, however since a subtle change in settings (CURLOPT_HTTPHEADER) triggers a crash in PHP I am posting both here. With ext-curl compiled with PHP_CURL_DEBUG=0 I only see the DTOR being called once (DTOR CALLED, ch = *) The comments in interface.c before where the crash occurs for Curl are interesting https://github.com/php/php-src/blob/master/ext/curl/interface.c#L2829-2838 ### PHP Version PHP 8.2.5 ### Operating System MacOS / Linux

« previous php.bugs (#244201) next »