Skip to content

PHP Fatal error triggers pointer being freed was not allocated and malloc: double free for ptr errors #11078

Closed

Description

@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 curl/curl#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

Activity

  1. cgzones commented on Apr 17, 2023

    @cgzones

    Might be a duplicate of #10670

  2. iluuu1994 commented on Apr 17, 2023

    @iluuu1994
    Member

    Might be a duplicate of #10670

    This isn't trying to use custom allocators.

    I'm unable to trigger a crash, ASAN is also not showing anything. What CURL version are you using? I'm trying this on Linux.

  3. lucasnetau commented on Apr 17, 2023

    @lucasnetau
    ContributorAuthor

    Latest Curl 8.0.1 is used. So far I've triggered the crash on both MacOS and Linux (Docker). The crash is timing dependant so the rate of filling the buffer may need to change depending on your network, it does appear that Curl needs to be past a certain point in the transfer stage for the issue to occur.

    I'm away from my main computer for a week, I'll come back the. with a code dump from Linux.

    Is there any other flags I should use for building or running php to help?

  4. iluuu1994 commented on Apr 18, 2023

    @iluuu1994
    Member

    That would be great, thank you!

    Is there any other flags I should use for building or running php to help?

    You could try the --enable-address-sanitizer and --enable-undefined-sanitizer flags.

  5. lucasnetau commented on Apr 24, 2023

    @lucasnetau
    ContributorAuthor

    Additional address sanitiser output on MacOS

    Double free output

    DTOR CALLED, ch = 1b06c000
    =================================================================
    ==51504==ERROR: AddressSanitizer: attempting double-free on 0x631000014800 in thread T0:
        #0 0x1169e7019 in wrap_free+0xa9 (libclang_rt.asan_osx_dynamic.dylib:x86_64h+0x4b019)
        #1 0x115b6cee2 in Curl_close url.c:432
        #2 0x115b31ae8 in curl_easy_cleanup easy.c:804
        #3 0x10e8657ca in curl_free_obj interface.c:2840
        #4 0x111c2b3cb in zend_objects_store_del zend_objects_API.c:200
        #5 0x1111f28b1 in rc_dtor_func zend_variables.c:57
        #6 0x1111f2b3c in i_zval_ptr_dtor zend_variables.h:44
        #7 0x1111f28f4 in zval_ptr_dtor zend_variables.c:84
        #8 0x10e8b81fc in _php_curl_multi_cleanup_list multi.c:109
        #9 0x11115a2be in zend_llist_destroy zend_llist.c:109
        #10 0x11115a5d4 in zend_llist_clean zend_llist.c:123
        #11 0x10e8c8748 in curl_multi_free_obj multi.c:555
        #12 0x111c28d5b in zend_objects_store_free_object_storage zend_objects_API.c:122
        #13 0x111129469 in zend_shutdown_executor_values zend_execute_API.c:399
        #14 0x11112a9ab in shutdown_executor zend_execute_API.c:416
        #15 0x111203029 in zend_deactivate zend.c:1258
        #16 0x110d77981 in php_request_shutdown main.c:1863
        #17 0x11218b810 in do_cli php_cli.c:1135
        #18 0x11218573d in main php_cli.c:1333
        #19 0x7ff80437530f  (<unknown module>)
    
    0x631000014800 is located 0 bytes inside of 65536-byte region [0x631000014800,0x631000024800)
    freed by thread T0 here:
        #0 0x1169e7019 in wrap_free+0xa9 (libclang_rt.asan_osx_dynamic.dylib:x86_64h+0x4b019)
        #1 0x7ff80459585f in fclose+0x8b (libsystem_c.dylib:x86_64+0x2585f)
        #2 0x1169d8a4f in wrap_fclose+0x8f (libclang_rt.asan_osx_dynamic.dylib:x86_64h+0x3ca4f)
        #3 0x110e336d2 in _php_stream_free streams.c:475
        #4 0x110e4a609 in stream_resource_regular_dtor streams.c:1761
        #5 0x111318ddb in zend_resource_dtor zend_list.c:73
        #6 0x11131b09c in zend_close_rsrc_list zend_list.c:225
        #7 0x111122434 in zend_shutdown_executor_values zend_execute_API.c:277
        #8 0x11112a9ab in shutdown_executor zend_execute_API.c:416
        #9 0x111203029 in zend_deactivate zend.c:1258
        #10 0x110d77981 in php_request_shutdown main.c:1863
        #11 0x11218b810 in do_cli php_cli.c:1135
        #12 0x11218573d in main php_cli.c:1333
        #13 0x7ff80437530f  (<unknown module>)
    
    previously allocated by thread T0 here:
        #0 0x1169e6ed0 in wrap_malloc+0xa0 (libclang_rt.asan_osx_dynamic.dylib:x86_64h+0x4aed0)
        #1 0x115b6b95a in Curl_readwrite transfer.c:1120
        #2 0x115b54b91 in multi_runsingle multi.c:2436
        #3 0x115b54186 in curl_multi_perform multi.c:2714
        #4 0x10e8bde53 in zif_curl_multi_exec multi.c:225
        #5 0x111852da5 in ZEND_DO_ICALL_SPEC_RETVAL_UNUSED_HANDLER zend_vm_execute.h:1250
        #6 0x1113c4462 in execute_ex zend_vm_execute.h:55823
        #7 0x1113c5820 in zend_execute zend_vm_execute.h:60396
        #8 0x11120e4c9 in zend_execute_scripts zend.c:1826
        #9 0x110d8218b in php_execute_script main.c:2542
        #10 0x11218944f in do_cli php_cli.c:964
        #11 0x11218573d in main php_cli.c:1333
        #12 0x7ff80437530f  (<unknown module>)
    
    SUMMARY: AddressSanitizer: double-free (libclang_rt.asan_osx_dynamic.dylib:x86_64h+0x4b019) in wrap_free+0xa9
    ==51504==ABORTING
    Abort trap: 6
    

    pointer being freed was not allocated output

    =================================================================
    ==51699==ERROR: AddressSanitizer: attempting free on address which was not malloc()-ed: 0x63100001480a in thread T0
        #0 0x116e93019 in wrap_free+0xa9 (libclang_rt.asan_osx_dynamic.dylib:x86_64h+0x4b019)
        #1 0x7ff80459585f in fclose+0x8b (libsystem_c.dylib:x86_64+0x2585f)
        #2 0x116e84a4f in wrap_fclose+0x8f (libclang_rt.asan_osx_dynamic.dylib:x86_64h+0x3ca4f)
        #3 0x1112df6d2 in _php_stream_free streams.c:475
        #4 0x1112f6609 in stream_resource_regular_dtor streams.c:1761
        #5 0x1117c4ddb in zend_resource_dtor zend_list.c:73
        #6 0x1117c709c in zend_close_rsrc_list zend_list.c:225
        #7 0x1115ce434 in zend_shutdown_executor_values zend_execute_API.c:277
        #8 0x1115d69ab in shutdown_executor zend_execute_API.c:416
        #9 0x1116af029 in zend_deactivate zend.c:1258
        #10 0x111223981 in php_request_shutdown main.c:1863
        #11 0x112637810 in do_cli php_cli.c:1135
        #12 0x11263173d in main php_cli.c:1333
        #13 0x7ff80437530f  (<unknown module>)
    
    0x63100001480a is located 10 bytes inside of 65536-byte region [0x631000014800,0x631000024800)
    allocated by thread T0 here:
        #0 0x116e92ed0 in wrap_malloc+0xa0 (libclang_rt.asan_osx_dynamic.dylib:x86_64h+0x4aed0)
        #1 0x11601795a in Curl_readwrite transfer.c:1120
        #2 0x116000b91 in multi_runsingle multi.c:2436
        #3 0x116000186 in curl_multi_perform multi.c:2714
        #4 0x10ed69e53 in zif_curl_multi_exec multi.c:225
        #5 0x111cfeda5 in ZEND_DO_ICALL_SPEC_RETVAL_UNUSED_HANDLER zend_vm_execute.h:1250
        #6 0x111870462 in execute_ex zend_vm_execute.h:55823
        #7 0x111871820 in zend_execute zend_vm_execute.h:60396
        #8 0x1116ba4c9 in zend_execute_scripts zend.c:1826
        #9 0x11122e18b in php_execute_script main.c:2542
        #10 0x11263544f in do_cli php_cli.c:964
        #11 0x11263173d in main php_cli.c:1333
        #12 0x7ff80437530f  (<unknown module>)
    
    SUMMARY: AddressSanitizer: bad-free (libclang_rt.asan_osx_dynamic.dylib:x86_64h+0x4b019) in wrap_free+0xa9
    ==51699==ABORTING
    Abort trap: 6
    
  6. lucasnetau commented on Apr 25, 2023

    @lucasnetau
    ContributorAuthor

    Alpine Linux produces a different error:

    Thread 1 "php" received signal SIGSEGV, Segmentation fault.
    0x000056407cf66486 in _php_stream_seek (stream=<error reading variable: Cannot access memory at address 0x7ffdf5351c68>, offset=<error reading variable: Cannot access memory at address 0x7ffdf5351c60>, whence=<error reading variable: Cannot access memory at address 0x7ffdf5351c5c>) at /usr/src/php/main/streams/streams.c:1295
    1295	/usr/src/php/main/streams/streams.c: No such file or directory.
    (gdb) bt
    #0  0x000056407cf66486 in _php_stream_seek (stream=<error reading variable: Cannot access memory at address 0x7ffdf5351c68>, offset=<error reading variable: Cannot access memory at address 0x7ffdf5351c60>, whence=<error reading variable: Cannot access memory at address 0x7ffdf5351c5c>) at /usr/src/php/main/streams/streams.c:1295
    #1  0x000056407cf69926 in stream_cookie_seeker (cookie=0x7ff82d077800, position=0x7ffdf53520d8, whence=1) at /usr/src/php/main/streams/cast.c:109
    #2  0x00007ff82de108fc in ?? () from /lib/ld-musl-x86_64.so.1
    #3  0x0000000000000000 in ?? ()
    

    From Debian leaks are detected

    =================================================================
    ==414==ERROR: LeakSanitizer: detected memory leaks
    
    Indirect leak of 32480 byte(s) in 3 object(s) allocated from:
        #0 0x7f05b994ce8f in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:145
        #1 0x7f05b8fdc3c8  (/usr/lib/x86_64-linux-gnu/libcurl.so.4+0x2d3c8)
    
    Indirect leak of 6440 byte(s) in 1 object(s) allocated from:
        #0 0x7f05b994d037 in __interceptor_calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:154
        #1 0x7f05b8fd5d6f  (/usr/lib/x86_64-linux-gnu/libcurl.so.4+0x26d6f)
    
    Indirect leak of 2736 byte(s) in 1 object(s) allocated from:
        #0 0x7f05b994d037 in __interceptor_calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:154
        #1 0x7f05b8fd704f  (/usr/lib/x86_64-linux-gnu/libcurl.so.4+0x2804f)
    
    Indirect leak of 416 byte(s) in 1 object(s) allocated from:
        #0 0x7f05b994d037 in __interceptor_calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:154
        #1 0x7f05b8ff2ec8  (/usr/lib/x86_64-linux-gnu/libcurl.so.4+0x43ec8)
        #2 0x558e286c53dc in ZEND_DO_ICALL_SPEC_RETVAL_USED_HANDLER /usr/src/php/Zend/zend_vm_execute.h:1312
        #3 0x558e28966226 in execute_ex /usr/src/php/Zend/zend_vm_execute.h:56032
        #4 0x558e2898214d in zend_execute /usr/src/php/Zend/zend_vm_execute.h:60396
        #5 0x558e285a1598 in zend_execute_scripts /usr/src/php/Zend/zend.c:1826
        #6 0x558e282d8a32 in php_execute_script /usr/src/php/main/main.c:2542
        #7 0x558e28d39862 in do_cli /usr/src/php/sapi/cli/php_cli.c:964
        #8 0x558e28d3c2bb in main /usr/src/php/sapi/cli/php_cli.c:1333
        #9 0x7f05b83f4d09 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x23d09)
    
    Indirect leak of 256 byte(s) in 4 object(s) allocated from:
        #0 0x7f05b994ce8f in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:145
        #1 0x7f05b8fc85ec  (/usr/lib/x86_64-linux-gnu/libcurl.so.4+0x195ec)
    
    Indirect leak of 127 byte(s) in 2 object(s) allocated from:
        #0 0x7f05b994ce8f in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:145
        #1 0x7f05b8fdc4c1  (/usr/lib/x86_64-linux-gnu/libcurl.so.4+0x2d4c1)
    
    Indirect leak of 100 byte(s) in 4 object(s) allocated from:
        #0 0x7f05b98fa817 in __interceptor_strdup ../../../../src/libsanitizer/asan/asan_interceptors.cpp:452
        #1 0x7f05b8fffba1  (/usr/lib/x86_64-linux-gnu/libcurl.so.4+0x50ba1)
    
    Indirect leak of 96 byte(s) in 1 object(s) allocated from:
        #0 0x7f05b994d037 in __interceptor_calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:154
        #1 0x7f05b8fd707a  (/usr/lib/x86_64-linux-gnu/libcurl.so.4+0x2807a)
    
    Indirect leak of 70 byte(s) in 2 object(s) allocated from:
        #0 0x7f05b98fa817 in __interceptor_strdup ../../../../src/libsanitizer/asan/asan_interceptors.cpp:452
        #1 0x7f05b901f975  (/usr/lib/x86_64-linux-gnu/libcurl.so.4+0x70975)
    
    Indirect leak of 48 byte(s) in 1 object(s) allocated from:
        #0 0x7f05b994ce8f in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:145
        #1 0x7f05b8fc2265  (/usr/lib/x86_64-linux-gnu/libcurl.so.4+0x13265)
    
    Indirect leak of 30 byte(s) in 2 object(s) allocated from:
        #0 0x7f05b98fa817 in __interceptor_strdup ../../../../src/libsanitizer/asan/asan_interceptors.cpp:452
        #1 0x7f05b901f956  (/usr/lib/x86_64-linux-gnu/libcurl.so.4+0x70956)
    
    Indirect leak of 24 byte(s) in 1 object(s) allocated from:
        #0 0x7f05b994d037 in __interceptor_calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:154
        #1 0x7f05b8fdd1ef  (/usr/lib/x86_64-linux-gnu/libcurl.so.4+0x2e1ef)
    
    Indirect leak of 16 byte(s) in 1 object(s) allocated from:
        #0 0x7f05b994d037 in __interceptor_calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:154
        #1 0x7f05b8fc1276  (/usr/lib/x86_64-linux-gnu/libcurl.so.4+0x12276)
    
    Indirect leak of 12 byte(s) in 1 object(s) allocated from:
        #0 0x7f05b98fa817 in __interceptor_strdup ../../../../src/libsanitizer/asan/asan_interceptors.cpp:452
        #1 0x7f05b8fda46a  (/usr/lib/x86_64-linux-gnu/libcurl.so.4+0x2b46a)
    
    Indirect leak of 12 byte(s) in 1 object(s) allocated from:
        #0 0x7f05b98fa817 in __interceptor_strdup ../../../../src/libsanitizer/asan/asan_interceptors.cpp:452
        #1 0x7f05b8fd7d24  (/usr/lib/x86_64-linux-gnu/libcurl.so.4+0x28d24)
    
    Indirect leak of 1 byte(s) in 1 object(s) allocated from:
        #0 0x7f05b98fa817 in __interceptor_strdup ../../../../src/libsanitizer/asan/asan_interceptors.cpp:452
        #1 0x7f05b8fd7de2  (/usr/lib/x86_64-linux-gnu/libcurl.so.4+0x28de2)
    
    Indirect leak of 1 byte(s) in 1 object(s) allocated from:
        #0 0x7f05b98fa817 in __interceptor_strdup ../../../../src/libsanitizer/asan/asan_interceptors.cpp:452
        #1 0x7f05b8fd8366  (/usr/lib/x86_64-linux-gnu/libcurl.so.4+0x29366)
    
    SUMMARY: AddressSanitizer: 42865 byte(s) leaked in 28 allocation(s).
    
  7. lucasnetau commented on Apr 26, 2023

    @lucasnetau
    ContributorAuthor

    Depending on where the out of memory error occurs it appears a different order of shutdown. With STREAM_DEBUG enabled.

    No crash occurs when the Curl handle is closed first (DTOR CALLED before stream_free):

    stream_alloc: STDIO:0x112a68100 persistent=(null)
    stream_alloc: STDIO:0x112a68300 persistent=(null)
    stream_alloc: STDIO:0x112a68500 persistent=(null)
    stream_alloc: user-space:0x112a68700 persistent=(null)
    stream_alloc: user-space:0x112a68800 persistent=(null)
    *   Trying 34.193.132.77:80...
    * Connected to httpbin.org (34.193.132.77) port 80 (#0)
    > POST /post HTTP/1.1
    Host: httpbin.org
    Accept: */*
    content-length: 100000000
    user-agent:TestClient/1
    Expect: 100-continue
    
    PHP Fatal error:  Allowed memory size of 16777216 bytes exhausted at Zend/zend_string.h:249 (tried to allocate 7766032 bytes) in /tests/killcurl.php on line 75
    
    Fatal error: Allowed memory size of 16777216 bytes exhausted at Zend/zend_string.h:249 (tried to allocate 7766032 bytes) in /tests/killcurl.php on line 75
    * Closing connection 0
    DTOR CALLED, ch = 12a6c000
    stream_free: user-space:0x112a68800[fifo://113] in_free=0 opts=CALL_DTOR, RELEASE_STREAM, RSRC_DTOR
    stream_free: user-space:0x112a68800[fifo://113] preserve_handle=0 release_cast=1 remove_rsrc=0
    stream_free: user-space:0x112a68800[fifo://113] in_free=0 opts=CALL_DTOR, RELEASE_STREAM, RSRC_DTOR
    stream_free: user-space:0x112a68800[fifo://113] preserve_handle=0 release_cast=1 remove_rsrc=0
    closed stream reader
    stream_free: user-space:0x112a68700[fifo://113] in_free=0 opts=CALL_DTOR, RELEASE_STREAM, RSRC_DTOR
    stream_free: user-space:0x112a68700[fifo://113] preserve_handle=0 release_cast=1 remove_rsrc=0
    closed stream writer
    stream_free: STDIO:0x112a68500[php://stderr] in_free=0 opts=CALL_DTOR, RELEASE_STREAM, RSRC_DTOR
    stream_free: STDIO:0x112a68500[php://stderr] preserve_handle=1 release_cast=0 remove_rsrc=0
    stream_free: STDIO:0x112a68300[php://stdout] in_free=0 opts=CALL_DTOR, RELEASE_STREAM, RSRC_DTOR
    stream_free: STDIO:0x112a68300[php://stdout] preserve_handle=1 release_cast=0 remove_rsrc=0
    stream_free: STDIO:0x112a68100[php://stdin] in_free=0 opts=CALL_DTOR, RELEASE_STREAM, RSRC_DTOR
    stream_free: STDIO:0x112a68100[php://stdin] preserve_handle=1 release_cast=0 remove_rsrc=0
    

    Crash occurs if the input file stream is closed before the curl connection is closed (DTOR CALLED after stream_free)

    stream_alloc: STDIO:0x110468100 persistent=(null)
    stream_alloc: STDIO:0x110468300 persistent=(null)
    stream_alloc: STDIO:0x110468500 persistent=(null)
    stream_alloc: user-space:0x110468700 persistent=(null)
    stream_alloc: user-space:0x110468800 persistent=(null)
    *   Trying 34.193.132.77:80...
    * Connected to httpbin.org (34.193.132.77) port 80 (#0)
    > POST /post HTTP/1.1
    Host: httpbin.org
    Accept: */*
    content-length: 100000000
    user-agent:TestClient/1
    Expect: 100-continue
    
    < HTTP/1.1 100 Continue
    PHP Fatal error:  Allowed memory size of 16777216 bytes exhausted at Zend/zend_string.h:152 (tried to allocate 6939768 bytes) in /tests/killcurl.php on line 57
    
    Fatal error: Allowed memory size of 16777216 bytes exhausted at Zend/zend_string.h:152 (tried to allocate 6939768 bytes) in /tests/killcurl.php on line 57
    stream_free: user-space:0x110468800[fifo://321] in_free=0 opts=CALL_DTOR, RELEASE_STREAM, RSRC_DTOR
    stream_free: user-space:0x110468800[fifo://321] preserve_handle=0 release_cast=1 remove_rsrc=0
    stream_free: user-space:0x110468800[fifo://321] in_free=0 opts=CALL_DTOR, RELEASE_STREAM, RSRC_DTOR
    stream_free: user-space:0x110468800[fifo://321] preserve_handle=0 release_cast=1 remove_rsrc=0
    closed stream reader
    stream_free: user-space:0x110468700[fifo://321] in_free=0 opts=CALL_DTOR, RELEASE_STREAM, RSRC_DTOR
    stream_free: user-space:0x110468700[fifo://321] preserve_handle=0 release_cast=1 remove_rsrc=0
    closed stream writer
    stream_free: STDIO:0x110468500[php://stderr] in_free=0 opts=CALL_DTOR, RELEASE_STREAM, RSRC_DTOR
    stream_free: STDIO:0x110468500[php://stderr] preserve_handle=1 release_cast=0 remove_rsrc=0
    stream_free: STDIO:0x110468300[php://stdout] in_free=0 opts=CALL_DTOR, RELEASE_STREAM, RSRC_DTOR
    stream_free: STDIO:0x110468300[php://stdout] preserve_handle=1 release_cast=0 remove_rsrc=0
    stream_free: STDIO:0x110468100[php://stdin] in_free=0 opts=CALL_DTOR, RELEASE_STREAM, RSRC_DTOR
    stream_free: STDIO:0x110468100[php://stdin] preserve_handle=1 release_cast=0 remove_rsrc=0
    DTOR CALLED, ch = 1046c000
    =================================================================
    ==37427==ERROR: AddressSanitizer: attempting double-free on 0x631000014800 in thread T0:
    ...
    
  8. lucasnetau commented on Apr 26, 2023

    @lucasnetau
    ContributorAuthor

    @iluuu1994 please let me know if you need anything additional. I haven't been able to crash reliably on Linux after compiling with debug enabled (Alpine Linux SIGSEGV, Debian I get leaks but no crash). MacOS version crashes reliably every 2-3 invocations of the script with SIGABRT.

  9. 41 remaining items

  10. ndossche commented on Jun 9, 2024

    @ndossche
    Member

    Thanks, I've managed to create an isolated test and opened a PR, let's hope CI agrees too.

  11. lucasnetau commented on Jun 10, 2024

    @lucasnetau
    ContributorAuthor

    In doing some benchmark testing with curl uploads via the stream I also discovered that this patch also fixed an issue I was seeing where cURL stopped uploading after stream_read() returned false on MacOS (Since returning an empty string causes cURL to think the upload is complete so you need to instead send a read error) [Note: I also use curl pause to stop and resume uploads as a flow control method if the buffer drains], now the upload works correctly even if the upload buffer gets drained.

    In the testing I was able to do, cURL would resume however it never called the stream_read() leading to no data being transferred.

    Performance wise, I don't see an variance between old and patched version POSTing a large file to a localhost server, both sat at around 1350 MB/s throughput

  12. added 2 commits that reference this issue on Jun 10, 2024
    bc558bf
    ccdd1c4
  13. added a commit that references this issue on Jun 10, 2024
    bcecbb5
  14. ndossche commented on Jun 10, 2024

    @ndossche
    Member

    @lucasnetau Thanks for the results, fix will be in the next release.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions