Skip to content

Memory out of bounds using dl() loading extension #19771

Closed

Description

@matyhtf

Description

The following code:

<?php
dl('swoole.so');

The actual script file is the temporary file run_test_info.php generated by run_tests. php. Using the dl() function to load the extension will cause memory out of bounds, but it is OK to modify the php.ini to load the extension.

$ cat run-test-info.php
    <?php
    echo str_replace("Zend OPcache", "opcache", implode(",", get_loaded_extensions()));
    $ext_dir = ini_get("extension_dir");
    foreach (scandir($ext_dir) as $file) {
        if (!preg_match('/^(?:php_)?([_a-zA-Z0-9]+)\.(?:so|dll)$/', $file, $matches)) {
            continue;
        }
        $ext = $matches[1];
        if (!extension_loaded($ext) && @dl($file)) {
            echo ",", $ext;
        }
    }
    ?>

Resulted in this output:

$ export USE_ZEND_ALLOC=0
$ cat dl.php 
<?php
dl('swoole.so');

$ php dl.php 
corrupted double-linked list
Aborted (core dumped)

But I expected this output instead:
No memory error

The swoole_client.cc:169 code is:

zend_declare_property_long(swoole_client_ce, ZEND_STRL("errCode"), 0, ZEND_ACC_PUBLIC);

Only class properties are declared here

Valgrind

$ valgrind --num-callers=64 php dl.php 
==4137170== Memcheck, a memory error detector
==4137170== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==4137170== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==4137170== Command: php dl.php
==4137170== 
==4137170== Invalid read of size 8
==4137170==    at 0x941867: destroy_zend_class (zend_opcode.c:439)
==4137170==    by 0x971613: _zend_hash_del_el_ex (zend_hash.c:1425)
==4137170==    by 0x97170E: _zend_hash_del_el (zend_hash.c:1452)
==4137170==    by 0x973987: zend_hash_apply_with_argument (zend_hash.c:2065)
==4137170==    by 0x963DE0: clean_module_classes (zend_API.c:3021)
==4137170==    by 0x963EAF: module_destructor (zend_API.c:3058)
==4137170==    by 0x9644FC: zend_post_deactivate_modules (zend_API.c:3184)
==4137170==    by 0x8AC518: php_request_shutdown (main.c:1906)
==4137170==    by 0xAD9CD7: do_cli (php_cli.c:1136)
==4137170==    by 0xADA179: main (php_cli.c:1334)
==4137170==  Address 0x907f6d0 is 32 bytes inside a block of size 56 free'd
==4137170==    at 0x484B27F: free (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==4137170==    by 0x9418B4: destroy_zend_class (zend_opcode.c:442)
==4137170==    by 0x971613: _zend_hash_del_el_ex (zend_hash.c:1425)
==4137170==    by 0x97170E: _zend_hash_del_el (zend_hash.c:1452)
==4137170==    by 0x973987: zend_hash_apply_with_argument (zend_hash.c:2065)
==4137170==    by 0x963DE0: clean_module_classes (zend_API.c:3021)
==4137170==    by 0x963EAF: module_destructor (zend_API.c:3058)
==4137170==    by 0x9644FC: zend_post_deactivate_modules (zend_API.c:3184)
==4137170==    by 0x8AC518: php_request_shutdown (main.c:1906)
==4137170==    by 0xAD9CD7: do_cli (php_cli.c:1136)
==4137170==    by 0xADA179: main (php_cli.c:1334)
==4137170==  Block was alloc'd at
==4137170==    at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==4137170==    by 0x915E04: __zend_malloc (zend_alloc.c:3123)
==4137170==    by 0x968008: zend_declare_typed_property (zend_API.c:4219)
==4137170==    by 0x96903C: zend_declare_property_ex (zend_API.c:4463)
==4137170==    by 0x9690A6: zend_declare_property (zend_API.c:4470)
==4137170==    by 0x969200: zend_declare_property_long (zend_API.c:4498)
==4137170==    by 0x96A9680: php_swoole_client_minit (swoole_client.cc:169)
==4137170==    by 0x97743EF: zm_startup_swoole(int, int) (php_swoole.cc:871)
==4137170==    by 0x960E05: zend_startup_module_ex (zend_API.c:2236)
==4137170==    by 0x77669F: php_load_extension (dl.c:257)
==4137170==    by 0x776772: php_dl (dl.c:300)
==4137170==    by 0x775F69: zif_dl (dl.c:69)
==4137170==    by 0x99A241: ZEND_DO_ICALL_SPEC_RETVAL_UNUSED_HANDLER (zend_vm_execute.h:1250)
==4137170==    by 0xA13293: execute_ex (zend_vm_execute.h:56101)
==4137170==    by 0xA18AE5: zend_execute (zend_vm_execute.h:60469)
==4137170==    by 0x957399: zend_execute_scripts (zend.c:1844)
==4137170==    by 0x8AD935: php_execute_script (main.c:2579)
==4137170==    by 0xAD9472: do_cli (php_cli.c:964)
==4137170==    by 0xADA179: main (php_cli.c:1334)
==4137170== 
==4137170== Invalid read of size 4
==4137170==    at 0x93FD07: zend_string_release (zend_string.h:322)
==4137170==    by 0x941886: destroy_zend_class (zend_opcode.c:440)
==4137170==    by 0x971613: _zend_hash_del_el_ex (zend_hash.c:1425)
==4137170==    by 0x97170E: _zend_hash_del_el (zend_hash.c:1452)
==4137170==    by 0x9734F7: zend_hash_graceful_reverse_destroy (zend_hash.c:1977)
==4137170==    by 0x95525E: zend_shutdown (zend.c:1110)
==4137170==    by 0x8AD5BF: php_module_shutdown (main.c:2454)
==4137170==    by 0xADA1E2: main (php_cli.c:1347)
==4137170==  Address 0x906f3a4 is 4 bytes inside a block of size 40 free'd
==4137170==    at 0x484B27F: free (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==4137170==    by 0x91492D: _efree_custom (zend_alloc.c:2487)
==4137170==    by 0x914A84: _efree (zend_alloc.c:2607)
==4137170==    by 0xA37537: _str_dtor (zend_string.c:68)
==4137170==    by 0x97238F: zend_hash_destroy (zend_hash.c:1701)
==4137170==    by 0xA37F55: zend_interned_strings_deactivate (zend_string.c:348)
==4137170==    by 0x8AC5D0: php_request_shutdown (main.c:1926)
==4137170==    by 0xAD9CD7: do_cli (php_cli.c:1136)
==4137170==    by 0xADA179: main (php_cli.c:1334)
==4137170==  Block was alloc'd at
==4137170==    at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==4137170==    by 0x915E04: __zend_malloc (zend_alloc.c:3123)
==4137170==    by 0x9148BC: _malloc_custom (zend_alloc.c:2478)
==4137170==    by 0x914A06: _emalloc (zend_alloc.c:2597)
==4137170==    by 0xA36DC1: zend_string_alloc (zend_string.h:152)
==4137170==    by 0xA36E34: zend_string_init (zend_string.h:174)
==4137170==    by 0xA37BAE: zend_new_interned_string_request (zend_string.c:253)
==4137170==    by 0x968655: zend_declare_typed_property (zend_API.c:4291)
==4137170==    by 0x96903C: zend_declare_property_ex (zend_API.c:4463)
==4137170==    by 0x9690A6: zend_declare_property (zend_API.c:4470)
==4137170==    by 0x96917E: zend_declare_property_bool (zend_API.c:4489)
==4137170==    by 0x994EC1D: curl_multi_register_class (multi.cc:613)
==4137170==    by 0x9940068: swoole_native_curl_minit (interface.cc:240)
==4137170==    by 0x96D4F98: php_swoole_runtime_minit (swoole_runtime.cc:279)
==4137170==    by 0x97743D5: zm_startup_swoole(int, int) (php_swoole.cc:868)
==4137170==    by 0x960E05: zend_startup_module_ex (zend_API.c:2236)
==4137170==    by 0x77669F: php_load_extension (dl.c:257)
==4137170==    by 0x776772: php_dl (dl.c:300)
==4137170==    by 0x775F69: zif_dl (dl.c:69)
==4137170==    by 0x99A241: ZEND_DO_ICALL_SPEC_RETVAL_UNUSED_HANDLER (zend_vm_execute.h:1250)
==4137170==    by 0xA13293: execute_ex (zend_vm_execute.h:56101)
==4137170==    by 0xA18AE5: zend_execute (zend_vm_execute.h:60469)
==4137170==    by 0x957399: zend_execute_scripts (zend.c:1844)
==4137170==    by 0x8AD935: php_execute_script (main.c:2579)
==4137170==    by 0xAD9472: do_cli (php_cli.c:964)
==4137170==    by 0xADA179: main (php_cli.c:1334)
==4137170== 
==4137170== Invalid read of size 4
==4137170==    at 0xA19F8A: zend_string_release_ex (zend_string.h:331)
==4137170==    by 0xA1A4B8: free_ini_entry (zend_ini.c:85)
==4137170==    by 0x9723CD: zend_hash_destroy (zend_hash.c:1706)
==4137170==    by 0xA1A59C: zend_ini_dtor (zend_ini.c:118)
==4137170==    by 0xA1A57D: zend_ini_shutdown (zend_ini.c:112)
==4137170==    by 0x8AD5E7: php_module_shutdown (main.c:2471)
==4137170==    by 0xADA1E2: main (php_cli.c:1347)
==4137170==  Address 0x9020964 is 4 bytes inside a block of size 48 free'd
==4137170==    at 0x484B27F: free (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==4137170==    by 0xA37512: _str_dtor (zend_string.c:68)
==4137170==    by 0x97238F: zend_hash_destroy (zend_hash.c:1701)
==4137170==    by 0xA37F55: zend_interned_strings_deactivate (zend_string.c:348)
==4137170==    by 0x8AC5D0: php_request_shutdown (main.c:1926)
==4137170==    by 0xAD9CD7: do_cli (php_cli.c:1136)
==4137170==    by 0xADA179: main (php_cli.c:1334)
==4137170==  Block was alloc'd at
==4137170==    at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==4137170==    by 0x915E04: __zend_malloc (zend_alloc.c:3123)
==4137170==    by 0xA36D94: zend_string_alloc (zend_string.h:152)
==4137170==    by 0xA36E34: zend_string_init (zend_string.h:174)
==4137170==    by 0xA37E07: zend_string_init_interned_request (zend_string.c:315)
==4137170==    by 0xA1A845: zend_register_ini_entries_ex (zend_ini.c:228)
==4137170==    by 0x97714AC: zm_startup_swoole(int, int) (php_swoole.cc:490)
==4137170==    by 0x960E05: zend_startup_module_ex (zend_API.c:2236)
==4137170==    by 0x77669F: php_load_extension (dl.c:257)
==4137170==    by 0x776772: php_dl (dl.c:300)
==4137170==    by 0x775F69: zif_dl (dl.c:69)
==4137170==    by 0x99A241: ZEND_DO_ICALL_SPEC_RETVAL_UNUSED_HANDLER (zend_vm_execute.h:1250)
==4137170==    by 0xA13293: execute_ex (zend_vm_execute.h:56101)
==4137170==    by 0xA18AE5: zend_execute (zend_vm_execute.h:60469)
==4137170==    by 0x957399: zend_execute_scripts (zend.c:1844)
==4137170==    by 0x8AD935: php_execute_script (main.c:2579)
==4137170==    by 0xAD9472: do_cli (php_cli.c:964)
==4137170==    by 0xADA179: main (php_cli.c:1334)
==4137170== 
==4137170== Invalid read of size 4
==4137170==    at 0xA19F09: zend_string_release (zend_string.h:322)
==4137170==    by 0xA1A4D5: free_ini_entry (zend_ini.c:87)
==4137170==    by 0x9723CD: zend_hash_destroy (zend_hash.c:1706)
==4137170==    by 0xA1A59C: zend_ini_dtor (zend_ini.c:118)
==4137170==    by 0xA1A57D: zend_ini_shutdown (zend_ini.c:112)
==4137170==    by 0x8AD5E7: php_module_shutdown (main.c:2471)
==4137170==    by 0xADA1E2: main (php_cli.c:1347)
==4137170==  Address 0x90209d4 is 4 bytes inside a block of size 32 free'd
==4137170==    at 0x484B27F: free (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==4137170==    by 0xA37512: _str_dtor (zend_string.c:68)
==4137170==    by 0x97238F: zend_hash_destroy (zend_hash.c:1701)
==4137170==    by 0xA37F55: zend_interned_strings_deactivate (zend_string.c:348)
==4137170==    by 0x8AC5D0: php_request_shutdown (main.c:1926)
==4137170==    by 0xAD9CD7: do_cli (php_cli.c:1136)
==4137170==    by 0xADA179: main (php_cli.c:1334)
==4137170==  Block was alloc'd at
==4137170==    at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==4137170==    by 0x915E04: __zend_malloc (zend_alloc.c:3123)
==4137170==    by 0xA36D94: zend_string_alloc (zend_string.h:152)
==4137170==    by 0xA36E34: zend_string_init (zend_string.h:174)
==4137170==    by 0xA37E07: zend_string_init_interned_request (zend_string.c:315)
==4137170==    by 0xA1A9FD: zend_register_ini_entries_ex (zend_ini.c:256)
==4137170==    by 0x97714AC: zm_startup_swoole(int, int) (php_swoole.cc:490)
==4137170==    by 0x960E05: zend_startup_module_ex (zend_API.c:2236)
==4137170==    by 0x77669F: php_load_extension (dl.c:257)
==4137170==    by 0x776772: php_dl (dl.c:300)
==4137170==    by 0x775F69: zif_dl (dl.c:69)
==4137170==    by 0x99A241: ZEND_DO_ICALL_SPEC_RETVAL_UNUSED_HANDLER (zend_vm_execute.h:1250)
==4137170==    by 0xA13293: execute_ex (zend_vm_execute.h:56101)
==4137170==    by 0xA18AE5: zend_execute (zend_vm_execute.h:60469)
==4137170==    by 0x957399: zend_execute_scripts (zend.c:1844)
==4137170==    by 0x8AD935: php_execute_script (main.c:2579)
==4137170==    by 0xAD9472: do_cli (php_cli.c:964)
==4137170==    by 0xADA179: main (php_cli.c:1334)
==4137170== 
==4137170== 
==4137170== HEAP SUMMARY:
==4137170==     in use at exit: 36,562 bytes in 31 blocks
==4137170==   total heap usage: 57,098 allocs, 57,067 frees, 12,624,109 bytes allocated
==4137170== 
==4137170== LEAK SUMMARY:
==4137170==    definitely lost: 0 bytes in 0 blocks
==4137170==    indirectly lost: 0 bytes in 0 blocks
==4137170==      possibly lost: 0 bytes in 0 blocks
==4137170==    still reachable: 36,562 bytes in 31 blocks
==4137170==         suppressed: 0 bytes in 0 blocks
==4137170== Rerun with --leak-check=full to see details of leaked memory
==4137170== 
==4137170== For lists of detected and suppressed errors, rerun with: -s
==4137170== ERROR SUMMARY: 112 errors from 4 contexts (suppressed: 0 from 0)

PHP Version

PHP 8.2.29 (cli) (built: Sep  2 2025 19:22:09) (NTS DEBUG)
Copyright (c) The PHP Group
Zend Engine v4.2.29, Copyright (c) Zend Technologies

Operating System

Ubuntu 22.04

Activity

  1. changed the title [-]Memory out of range using `dl()` loading extension[/-] [+]Memory out of bounds using `dl()` loading extension[/+] on Sep 9, 2025
  2. iluuu1994 commented on Sep 9, 2025

    @iluuu1994
    Member

    Does this also happen on newer versions? I know there were some dl() fixes, but not sure if they were all backported.

  3. krakjoe commented on Sep 9, 2025

    @krakjoe
    Member

    For maximum confidence, it seems like we could add a similar test to zend_test, but there is a comment about observers and dl() being incompatible in the source (no concrete idea why, or if relevant, I glanced), it might be worth looking at getting this tested in CI though, so it doesn't potentially fall behind again.

  4. iluuu1994 commented on Sep 9, 2025

    @iluuu1994
    Member

    /cc @arnaud-lb, as you've made most of the latest dl() improvements.

  5. arnaud-lb commented on Sep 9, 2025

    @arnaud-lb
    Member

    @krakjoe I added a dl_test extension as part of #8435. It's used in a few tests: https://github.com/search?q=repo%3Aphp%2Fphp-src+dl_test+path%3A**%2F*.phpt&type=code

  6. arnaud-lb commented on Sep 9, 2025

    @arnaud-lb
    Member

    @matyhtf I believe this was fixed in #17961, but only in PHP 8.3 and up. Unfortunately, PHP 8.2 is in security fixes only mode: https://www.php.net/supported-versions.php

  7. krakjoe commented on Sep 9, 2025

    @krakjoe
    Member

    @arnaud-lb cool, I missed that, so we're confident this is okay, I guess this can be closed then ?

  8. arnaud-lb commented on Sep 9, 2025

    @arnaud-lb
    Member

    @krakjoe I would prefer having a confirmation from @matyhtf that it doesn't crash with newer versions, in case it's actually another issue

  9. nask0 commented on Sep 10, 2025

    @nask0

    @krakjoe I would prefer having a confirmation from @matyhtf that it doesn't crash with newer versions, in case it's actually another issue

    @krakjoe I just run the test with provided code from @matyhtf and there is no issue with 8.4.X version of PHP.

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

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions