php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #80290 Double free when ASSERT_CALLBACK is used with a dynamic message
Submitted: 2020-10-28 09:11 UTC Modified: 2020-10-30 10:07 UTC
From: dev at mabe dot berlin Assigned: nikic (profile)
Status: Closed Package: Reproducible crash
PHP Version: 8.0.0RC2 OS: alpine:3.12
Private report: No CVE-ID: None
 [2020-10-28 09:11 UTC] dev at mabe dot berlin
Description:
------------
I'm using assertions and a workaround for PHP < 7 to throw AssertionError.
The code needs to work with PHP 5.6 to latest.

Now with the latest PHP-8.0-rc2 I get a segmentation fault on running the tests.

I have reduced the code to bare minimum but I wasn't able to reproduce the segv without phpunit. I guess it happens somewhere in a phpunit shutdown function but the seg-vault is still related to this test code - that's why I report it here.

PHPUnit 9.4.1

PS: I was using a docker container running on Mac - not sure if this makes any difference.

Test script:
---------------
// phpunit.xml:
<?xml version="1.0"?>
<phpunit bootstrap="./bootstrap.php">
</phpunit>


// bootstrap.php
<?php

// AssertionError has been added in PHP-7.0
if (!class_exists('AssertionError')) {
    class AssertionError extends Exception {};
}
assert_options(ASSERT_CALLBACK, function($file, $line, $code) {
    throw new AssertionError("assert(): Assertion '{$code}' failed in {$file} on line {$line}");
});

class AssertRunner
{
    final public static function runAssert()
    {
        assert(
            false,
            'Message with static::class: ' . static::class
        );
    }
}

function foo()
{
    try {
        AssertRunner::runAssert();
    } catch (AssertionError $e) {
        echo $e;
    }
}

foo();


// execute
php -d 'zend.assertions=1' ./vendor/bin/phpunit

Expected result:
----------------
No crash

Actual result:
--------------
AssertionError: assert(): Assertion '' failed in /workdir/bootstrap.php on line 17 in /workdir/bootstrap.php:8
Stack trace:
#0 [internal function]: PHPUnit\Util\FileLoader::{closure}('/workdir/bootst...', 17, NULL, 'Message with st...')
#1 /workdir/bootstrap.php(17): assert(false, 'Message with st...')
#2 /workdir/bootstrap.php(25): AssertRunner::runAssert()
#3 /workdir/bootstrap.php(31): foo()
#4 /workdir/vendor/phpunit/phpunit/src/Util/FileLoader.php(61): include_once('/workdir/bootst...')
#5 /workdir/vendor/phpunit/phpunit/src/Util/FileLoader.php(49): PHPUnit\Util\FileLoader::load('/workdir/bootst...')
#6 /workdir/vendor/phpunit/phpunit/src/TextUI/Command.php(546): PHPUnit\Util\FileLoader::checkAndLoad('/workdir/./boot...')
#7 /workdir/vendor/phpunit/phpunit/src/TextUI/Command.php(349): PHPUnit\TextUI\Command->handleBootstrap('/workdir/./boot...')
#8 /workdir/vendor/phpunit/phpunit/src/TextUI/Command.php(116): PHPUnit\TextUI\Command->handleArguments(Array)
#9 /workdir/vendor/phpunit/phpunit/src/TextUI/Command.php(101): PHPUnit\TextUI\Command->run(Array, true)
#10 /workdir/vendor/phpunit/phpunit/phpunit(61): PHPUnit\TextUI\Command::main()
#11 {main}

Next AssertionError: Message with static::class: AssertRunner in /workdir/bootstrap.php:17
Stack trace:
#0 /workdir/bootstrap.php(17): assert(false, 'Message with st...')
#1 /workdir/bootstrap.php(25): AssertRunner::runAssert()
#2 /workdir/bootstrap.php(31): foo()
#3 /workdir/vendor/phpunit/phpunit/src/Util/FileLoader.php(61): include_once('/workdir/bootst...')
#4 /workdir/vendor/phpunit/phpunit/src/Util/FileLoader.php(49): PHPUnit\Util\FileLoader::load('/workdir/bootst...')
#5 /workdir/vendor/phpunit/phpunit/src/TextUI/Command.php(546): PHPUnit\Util\FileLoader::checkAndLoad('/workdir/./boot...')
#6 /workdir/vendor/phpunit/phpunit/src/TextUI/Command.php(349): PHPUnit\TextUI\Command->handleBootstrap('/workdir/./boot...')
#7 /workdir/vendor/phpunit/phpunit/src/TextUI/Command.php(116): PHPUnit\TextUI\Command->handleArguments(Array)
#8 /workdir/vendor/phpunit/phpunit/src/TextUI/Command.php(101): PHPUnit\TextUI\Command->run(Array, true)
#9 /workdir/vendor/phpunit/phpunit/phpunit(61): PHPUnit\TextUI\Command::main()
#10 {main}Segmentation fault (core dumped)

(gdb) bt
#0  0x000055a3aa1652e9 in ?? ()
#1  0x000055a3aa165f51 in ?? ()
#2  0x000055a3aa1683c0 in _erealloc ()
#3  0x000055a3aa16acae in ?? ()
#4  0x000055a3aa16bf87 in ?? ()
#5  0x000055a3aa177b1b in ?? ()
#6  0x000055a3aa184d2c in ?? ()
#7  0x000055a3aa17a455 in ?? ()
#8  0x000055a3aa184c60 in ?? ()
#9  0x000055a3aa177d7f in ?? ()
#10 0x000055a3aa184d2c in ?? ()
#11 0x000055a3aa17a455 in ?? ()
#12 0x000055a3aa184c60 in ?? ()
#13 0x000055a3aa17d951 in ?? ()
#14 0x000055a3aa184d8b in ?? ()
#15 0x000055a3aa17a455 in ?? ()
#16 0x000055a3aa184c60 in ?? ()
#17 0x000055a3aa17ec10 in ?? ()
#18 0x000055a3aa184a4e in ?? ()
#19 0x000055a3aa1849ca in ?? ()
#20 0x000055a3aa141dfa in ?? ()
#21 0x000055a3aa141f66 in compile_file ()
#22 0x000055a3a9f09eef in ?? ()
#23 0x000055a3aa142211 in compile_filename ()
#24 0x000055a3aa1d7878 in ?? ()
#25 0x000055a3aa22d3dd in ?? ()
#26 0x000055a3aa24e345 in execute_ex ()
#27 0x000055a3aa18b9c8 in zend_call_function ()
#28 0x000055a3aa18bd76 in zend_call_known_function ()
#29 0x000055a3a9f617c5 in ?? ()
#30 0x000055a3aa18c2ab in zend_lookup_class_ex ()
#31 0x000055a3aa18ce45 in zend_fetch_class_by_name ()
#32 0x000055a3aa1eed0c in ?? ()
#33 0x000055a3aa24bbad in execute_ex ()
#34 0x000055a3aa24f2ee in zend_execute ()
#35 0x000055a3aa1a3482 in zend_execute_scripts ()
#36 0x000055a3aa106590 in php_execute_script ()
#37 0x000055a3aa28f10a in ?? ()
#38 0x000055a3aa290143 in ?? ()
#39 0x00007f0afb5d01ef in ?? () from /lib/ld-musl-x86_64.so.1
#40 0x00007f0afb5d01c8 in ?? () from /lib/ld-musl-x86_64.so.1
#41 0x00007ffdbddbd6c0 in ?? ()
#42 0x0000000000000000 in ?? ()

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2020-10-30 09:18 UTC] nikic@php.net
-Status: Open +Status: Verified
 [2020-10-30 10:02 UTC] nikic@php.net
-Assigned To: +Assigned To: nikic
 [2020-10-30 10:02 UTC] nikic@php.net
Reduced (under valgrind):

<?php 
assert_options(ASSERT_CALLBACK, function($file, $line, $unused, $message) {
    var_dump($message);
});
$x = 'x'; 
assert(false, 'Dynamic message: ' . $x);
 [2020-10-30 10:07 UTC] nikic@php.net
-Summary: SegV on assert with phpunit +Summary: Double free when ASSERT_CALLBACK is used with a dynamic message
 [2020-10-30 10:13 UTC] nikic@php.net
Automatic comment on behalf of nikita.ppv@gmail.com
Revision: http://git.php.net/?p=php-src.git;a=commit;h=3bd3651bcc3d374586b291195d1b3471f3f7287d
Log: Fixed bug #80290
 [2020-10-30 10:13 UTC] nikic@php.net
-Status: Verified +Status: Closed
 
PHP Copyright © 2001-2021 The PHP Group
All rights reserved.
Last updated: Mon Jul 26 02:01:23 2021 UTC