php / php/php-src

zend_compile_file use of uninitialized memory on second request

オープン
#9,536 コメント 3 件 リアクション 0 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

Bug Status: Needs Triage
主要言語
C
スター
40.4k
フォーク
8.2k
平均マージ
2日 13時間
マージ済み PR(30日)
96

説明

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

コントリビューションガイド

コントリビューションガイドを開く

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

調査の方向性

まず、拡張機能のコードを使って2回目のリクエストの Valgrind レポートを再現し、次にスタックトレースにある require.c:26 と ZendAccelerator.c:2217 を調べます。リクエスト間でファイルハンドルとコンパイル済み op 配列の状態を比較し、未初期化の値が PHP に由来するのか、拡張機能の使用に由来するのかを判断します。警告の原因が特定され、焦点を絞った回帰テスト、またはユーザーコードの問題であることの確認が文書化されれば完了です。

索引モデルが issue の本文から書いたものです。

評価

技術スタック
c, php
領域
backend
issue の種類
バグ
難易度
4/5
見積もり時間
3〜5日
活発さ
停滞
明瞭さ
説明が足りない
初心者へのやさしさ
28/100

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。