Skip to content

Assertion failure in normalize_value() when parsing malformed INI input via parse_ini_string() #20695

Closed

Description

@vi3tL0u1s

Description

The following code:

<?php
class a {
    function __destruct() {
        try {
            array_merge([' ' => [PHP_INT_MAX => null]], ['foo' == str_repeat('a', 2)],);
        } catch (Throwable $e) {}
        var_dump(parse_ini_string(<<<INI
            8 [[$obj] = !!$]
            INI, TRUE, INI_SCANNER_TYPED));
        }
}
new a;

Resulted in this output:

php: /path/to/php-src/Zend/zend_ini_parser.y:317: normalize_value: Assertion `(*(zv)).u2.extra == 0 || (*(zv)).u2.extra == 1' failed.
Aborted

Commit:

2ee5e6b432c7ed51ff7296522c123551975be95b

Configurations:

CC="clang" CXX="clang++" CFLAGS="-fsanitize=address -g -O0" CXXFLAGS="-fsanitize=address -g -O0" ./configure --enable-debug --enable-address-sanitizer --disable-shared --with-pic

PHP Version

PHP 8.6.0-dev (cli) (built: Dec 13 2025 16:51:10) (NTS DEBUG)
Copyright (c) The PHP Group
Zend Engine v4.6.0-dev, Copyright (c) Zend Technologies
    with Zend OPcache v8.6.0-dev, Copyright (c), by Zend Technologies

Operating System

Ubuntu 22.04

Activity

  1. ndossche commented on Dec 13, 2025

    @ndossche
    Member

    This doesn't reproduce for me. I get:

    Warning: Undefined variable $obj in x.php on line 8
    array(1) {
      [8]=>
      array(1) {
        ["["]=>
        int(0)
      }
    }
    

    Even under Valgrind I get no errors.

  2. ndossche commented on Dec 13, 2025

    @ndossche
    Member

    Ah under Valgrind I get:

    ==238248== Conditional jump or move depends on uninitialised value(s)
    ==238248==    at 0x4A81F04: normalize_value (zend_ini_parser.y:317)
    ==238248==    by 0x4A833A0: ini_parse (zend_ini_parser.y:403)
    ==238248==    by 0x4A81D9C: zend_parse_ini_string (zend_ini_parser.y:267)
    ==238248==    by 0x476E06D: zif_parse_ini_string (basic_functions.c:2539)
    ==238248==    by 0x49D0BAC: ZEND_DO_ICALL_SPEC_RETVAL_USED_HANDLER (zend_vm_execute.h:1421)
    ==238248==    by 0x4A5170B: execute_ex (zend_vm_execute.h:116441)
    ==238248==    by 0x49B8FF0: zend_call_function (zend_execute_API.c:1014)
    ==238248==    by 0x49B94E0: zend_call_known_function (zend_execute_API.c:1108)
    ==238248==    by 0x4AD19FC: zend_call_known_instance_method (zend_API.h:860)
    ==238248==    by 0x4AD1A36: zend_call_known_instance_method_with_0_params (zend_API.h:866)
    ==238248==    by 0x4AD204E: zend_objects_destroy_object (zend_objects.c:172)
    ==238248==    by 0x4AD0ECB: zend_objects_store_del (zend_objects_API.c:181)
    ==238248== 
    ==238248== Conditional jump or move depends on uninitialised value(s)
    ==238248==    at 0x4A81F41: normalize_value (zend_ini_parser.y:318)
    ==238248==    by 0x4A833A0: ini_parse (zend_ini_parser.y:403)
    ==238248==    by 0x4A81D9C: zend_parse_ini_string (zend_ini_parser.y:267)
    ==238248==    by 0x476E06D: zif_parse_ini_string (basic_functions.c:2539)
    ==238248==    by 0x49D0BAC: ZEND_DO_ICALL_SPEC_RETVAL_USED_HANDLER (zend_vm_execute.h:1421)
    ==238248==    by 0x4A5170B: execute_ex (zend_vm_execute.h:116441)
    ==238248==    by 0x49B8FF0: zend_call_function (zend_execute_API.c:1014)
    ==238248==    by 0x49B94E0: zend_call_known_function (zend_execute_API.c:1108)
    ==238248==    by 0x4AD19FC: zend_call_known_instance_method (zend_API.h:860)
    ==238248==    by 0x4AD1A36: zend_call_known_instance_method_with_0_params (zend_API.h:866)
    ==238248==    by 0x4AD204E: zend_objects_destroy_object (zend_objects.c:172)
    ==238248==    by 0x4AD0ECB: zend_objects_store_del (zend_objects_API.c:181)
    ==238248== 
    
    
  3. ndossche commented on Dec 13, 2025

    @ndossche
    Member

    I think there's simply a reasoning error about when which scanner state can cause which parser component to invoke later on.
    Probably this suffices:

    diff --git a/Zend/zend_ini_scanner.l b/Zend/zend_ini_scanner.l
    index d3f71ba8bc3..5f9b77e6a3d 100644
    --- a/Zend/zend_ini_scanner.l
    +++ b/Zend/zend_ini_scanner.l
    @@ -145,10 +145,10 @@ ZEND_API zend_ini_scanner_globals ini_scanner_globals;
     	if (SCNG(scanner_mode) == ZEND_INI_SCANNER_TYPED &&            \
     		(YYSTATE == STATE(ST_VALUE) || YYSTATE == STATE(ST_RAW))) {\
     		zend_ini_copy_typed_value(ini_lval, type, str, len);       \
    -		Z_EXTRA_P(ini_lval) = 0;                                   \
     	} else {                                                       \
     		zend_ini_copy_value(ini_lval, str, len);                   \
     	}                                                              \
    +	Z_EXTRA_P(ini_lval) = 0;                                       \
     	return type;                                                   \
     }
     
    
  4. ndossche commented on Dec 13, 2025

    @ndossche
    Member

    This was previously an issue but was (incompletely) fixed via #11092 (introduced in #11014)

  5. added a commit that references this issue on Dec 13, 2025
    ce01fb5
  6. added 3 commits that reference this issue on Dec 15, 2025
    85cb6e4
    9cf6f87
    21fe714
  7. added a commit that references this issue on Dec 15, 2025
    2ef60d0
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