php / php/php-src

zend_compile_file use of uninitialized memory on second request

Offen
#9,536 3 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

Bug Status: Needs Triage
Vorherrschende Sprache
C
Sterne
40.4k
Forks
8.2k
Ø Merge
2 T. 13 Std.
Gemergte PRs (30 T.)
96

Beschreibung

Description

I'm using the zend_compile_file function for require a file in my extension.
Here is the code:

int requireFile(zval *result, char *path) {
    zend_file_handle file_handle;
    zend_op_array *new_op_array;
    zval dummy, output;
    int ret;

    ret = php_stream_open_for_zend_ex(path, &file_handle, USE_PATH|STREAM_OPEN_FOR_INCLUDE);

    if (ret != SUCCESS) {
        return FAILURE;
    }

    zend_string *filename = zend_string_init(path, strlen(path), 0);

    if (!file_handle.opened_path) {
        file_handle.opened_path = zend_string_copy(filename);
    }

    zend_string *opened_path = zend_string_copy(file_handle.opened_path);

    ZVAL_NULL(&dummy);
    if (zend_hash_add(&EG(included_files), opened_path, &dummy)) {
        new_op_array = zend_compile_file(&file_handle, ZEND_REQUIRE);
    } else {
        new_op_array = NULL;
    }
    zend_string_release_ex(opened_path, 0);

    if (new_op_array) {
        ZVAL_UNDEF(&output);
        zend_execute(new_op_array, &output);

        ZVAL_COPY_VALUE(result, &output);

        if (!EG(exception)) {
            zval_ptr_dtor(&output);
        }
    }

    zend_string_release(filename);

    destroy_op_array(new_op_array);
    efree(new_op_array);

    zend_destroy_file_handle(&file_handle);

    return SUCCESS;
}

Use the function:

zval exist, source;

ZVAL_NULL(&source);

char *basePath, *module, *filename;

size_t basePathLength = 0, moduleLength = 0, filenameLength = 0;

ZEND_PARSE_PARAMETERS_START(3, 3)
    Z_PARAM_STRING(basePath, basePathLength)
    Z_PARAM_STRING(module, moduleLength)
    Z_PARAM_STRING(filename, filenameLength)
ZEND_PARSE_PARAMETERS_END();

char *jsFilePath[] = {basePath, "/resource/", module, "/js/", filename, ".php"};

char jsFile[basePathLength + moduleLength + filenameLength + 18];

globalString(jsFile, jsFilePath, 6);

php_stat(jsFile, strlen(jsFile), FS_EXISTS, &exist);

if (Z_TYPE(exist) == IS_TRUE) {
    requireFile(&source, jsFile);

    zend_update_static_property(i18nCe, ZEND_STRL("source"), &source);

    zval_ptr_dtor(&source);
}

zval_ptr_dtor(&exist);

The globalString function:

void globalString(char result[], char *strs[], int size) {
    strcpy(result, strs[0]);

    for (int i = 1; i < size; i++) {
        strcat(result, strs[i]);
    }
}

However, when I try with the valgrind, it show Conditional jump or move depends on uninitialised value(s)

==35079== Memcheck, a memory error detector
==35079== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==35079== Using Valgrind-3.17.0 and LibVEX; rerun with -h for copyright info
==35079== Command: /root/php-bin/DEBUG/bin/php -S localhost:8000 test/index.php
==35079== Parent PID: 8
==35079== 
==35079== Conditional jump or move depends on uninitialised value(s)
==35079==    at 0x71B4220: persistent_compile_file (ZendAccelerator.c:2217)
==35079==    by 0x72A4E9F: requireFile (require.c:26)
==35079==    by 0x72A8CE3: zim_I18n_init (i18n.c:42)
==35079==    by 0x76651B: ZEND_DO_FCALL_SPEC_RETVAL_UNUSED_HANDLER (zend_vm_execute.h:1755)
==35079==    by 0x7E8E9F: execute_ex (zend_vm_execute.h:55172)
==35079==    by 0x7ED5A7: zend_execute (zend_vm_execute.h:59499)
==35079==    by 0x725AAB: zend_execute_scripts (zend.c:1694)
==35079==    by 0x83DF3F: php_cli_server_dispatch_router (php_cli_server.c:2168)
==35079==    by 0x83E153: php_cli_server_dispatch (php_cli_server.c:2208)
==35079==    by 0x83ED67: php_cli_server_recv_event_read_request (php_cli_server.c:2529)
==35079==    by 0x83F15B: php_cli_server_do_event_for_each_fd_callback (php_cli_server.c:2615)
==35079==    by 0x83A913: php_cli_server_poller_iter_on_active (php_cli_server.c:869)
==35079==  Uninitialised value was created by a heap allocation
==35079==    at 0x484EFC8: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-arm64-linux.so)
==35079==    by 0x6E79C7: __zend_malloc (zend_alloc.c:3056)
==35079==    by 0x6E649B: _malloc_custom (zend_alloc.c:2418)
==35079==    by 0x6E660F: _emalloc (zend_alloc.c:2537)
==35079==    by 0x753D07: zend_vm_stack_new_page (zend_execute.c:184)
==35079==    by 0x753D6B: zend_vm_stack_init (zend_execute.c:195)
==35079==    by 0x709BE7: init_executor (zend_execute_API.c:148)
==35079==    by 0x7240EF: zend_activate (zend.c:1212)
==35079==    by 0x67510B: php_request_startup (main.c:1725)
==35079==    by 0x83DDEB: php_cli_server_request_startup (php_cli_server.c:2130)
==35079==    by 0x83E0FF: php_cli_server_dispatch (php_cli_server.c:2199)
==35079==    by 0x83ED67: php_cli_server_recv_event_read_request (php_cli_server.c:2529)
==35079== 
==35079== 
==35079== HEAP SUMMARY:
==35079==     in use at exit: 5,032 bytes in 14 blocks
==35079==   total heap usage: 15,982 allocs, 15,968 frees, 3,843,232 bytes allocated
==35079== 
==35079== LEAK SUMMARY:
==35079==    definitely lost: 0 bytes in 0 blocks
==35079==    indirectly lost: 0 bytes in 0 blocks
==35079==      possibly lost: 0 bytes in 0 blocks
==35079==    still reachable: 5,032 bytes in 14 blocks
==35079==         suppressed: 0 bytes in 0 blocks
==35079== Reachable blocks (those to which a pointer was found) are not shown.
==35079== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==35079== 
==35079== For lists of detected and suppressed errors, rerun with: -s
==35079== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

PHP 8.0.21-dev (cli) (built: Sep 12 2022 14:44:12) ( NTS DEBUG )
Copyright (c) The PHP Group
Zend Engine v4.0.21-dev, Copyright (c) Zend Technologies
with Zend OPcache v8.0.21-dev, Copyright (c), by Zend Technologies

PHP Version

PHP 8.0.21-dev

Operating System

No response

Beitragsleitfaden

Beitragsleitfaden öffnen

Erste Schritte

  1. Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
  3. Forke das Repository und arbeite in einem Branch.
  4. Öffne einen Pull Request, der die Issue-Nummer nennt.

Rechercherichtung

Beginne damit, den Valgrind-Bericht für die zweite Anfrage mit dem Erweiterungscode zu reproduzieren, und untersuche anschließend require.c:26 und ZendAccelerator.c:2217 aus dem Stack Trace. Vergleiche den Zustand des Datei-Handles und des kompilierten Op-Arrays zwischen den Anfragen und ermittle, ob der nicht initialisierte Wert aus PHP oder aus der Verwendung der Erweiterung stammt. Fertig ist die Aufgabe, wenn die Quelle der Warnung festgestellt und entweder ein fokussierter Regressionstest oder ein bestätigtes Problem im Benutzercode dokumentiert ist.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
c, php
Bereich
backend
Issue-Typ
Bug
Schwierigkeit
4/5
Geschätzter Aufwand
3-5 Tage
Aktivitätsstatus
Veraltet
Klarheit
Muss geklärt werden
Anfängerfreundlichkeit
28/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.