Skip to content

PHP 8.2.0 access violation while executing a 'foreach' loop #10067

Open

Description

@mdrmdrmdr

Description

Encountered an access violation bug in PHP 8.2.0 while executing a foreach loop on an array. It's inside a complex PHP application. Unfortunateley, I cannot reproduce the error with a small extract of the code just with the loop. Using the extract, it works :-\

I added the extract also to here. But, might not help much as it works. I assigned the variables for the loop with the same values just before the loop which crashes. Background: Application is a house automation server. Loop creates the commands for an i2c command.

What I see:

  • The loop just stops before all array elements are executed and PHP exits immediately without calling any error- or exit-handler. The last command in the loop is executed. The next element is not retrieved. The loop is successfully executed ~10 times. In the next attempt, PHP crashes
  • No message is written to the prompt
  • No entry in the PHP error log is created (all error reporting is enabled)
  • A windows access violation event is created. See attachment (partly in German; hope thats not a problem)
  • It workes without errors in PHP 8.1.13 (cli) (built: Nov 22 2022 15:49:14) (ZTS Visual C++ 2019 x64)

If I can provide more information, just advise me.

PHP_8.2.0_Crash.txt
PHP_8.2.0_Crash_php.txt

PHP Version

PHP 8.2.0 (cli) (built: Dec 6 2022 15:31:23) (ZTS Visual C++ 2019 x64) - from windows.php.net

Operating System

Windows 10 22H2 Build 19045.2311

Activity

  1. cmb69 commented on Dec 8, 2022

    @cmb69
    Member

    Can you please try to generate a stack backtrace?

    Also, do you have OPcache enabled? If so, is JIT enabled? If so, please provide the settings (opcache.jit*). And try without JIT and even without OPcache.

  2. mdrmdrmdr commented on Dec 8, 2022

    @mdrmdrmdr
    Author

    Seems to work for 8.2.0 with OPcache disabled 😉
    Had this settings in 8.2.0 and 8.1.13:

    [opcache]
    opcache.enable=1
    opcache.jit_buffer_size=100M
    opcache.jit=1255
    opcache.enable_cli=1
    

    Stack backtrace analysis is attached.
    MultipleDumps_MultipleRules.zip

    Update:
    Works also with OPcache enabled but JIT disabled!

  3. mdrmdrmdr commented on Dec 10, 2022

    @mdrmdrmdr
    Author

    Anything more I can provide?

  4. cmb69 commented on Dec 10, 2022

    @cmb69
    Member

    Stack backtrace analysis is attached. MultipleDumps_MultipleRules.zip

    That's not really helpful.

    Works also with OPcache enabled but JIT disabled!

    Okay, so this is obviously a JIT issue, and as such a stack backtrace may not be helpful anyway.

    PHP 8.2.0 (cli) (built: Dec 6 2022 15:31:23) (ZTS Visual C++ 2019 x64)

    Do you have a particular reason to use a ZTS version? Are you actually using some multi-threading capabilities (such as provided by ext/parallel)? If not, please try an NTS build of PHP.

  5. mdrmdrmdr commented on Dec 10, 2022

    @mdrmdrmdr
    Author

    NTS 8.2.0 shows same behaviour as ZTS. Crashes in the 'foreach' loop with JIT enabled. Works with JIT disabled. Do you think the original crash dumps help? ~330 MB each.

    And no, no specific reason why I use ZTS. I use it since ever. Reason possibly is that "thread safe" sounds better than "non thread safe" :-)

  6. cmb69 commented on Dec 12, 2022

    @cmb69
    Member

    Do you think the original crash dumps help? ~330 MB each.

    Maybe for someone accustomed to JIT, but even then it might be almost impossible to debug on Windows.

    And no, no specific reason why I use ZTS. I use it since ever. Reason possibly is that "thread safe" sounds better than "non thread safe" :-)

    NTS is supposed to be a wee bit faster, and if you don't need multi-threading, it's usually recommendable.

  7. removed their assignment
    on Dec 12, 2022
  8. DevSysEngineer commented on Dec 14, 2022

    @DevSysEngineer

    Dear all,

    We have exactly the same issue right now.

    This code crashes PHP without any log:

    } elseif (!empty($replaceResults)) {
        foreach ($replaceResults as $key => $otherResult) {
            if (!empty($otherResult[2])) {
                list(,,$otherViewTarget) = $otherResult;
                 if ($ids) {
                    if ($otherViewTarget === $oldPlaylistItemId) {
                          $replaceResults[$key][2] = $newPlaylistItem->id;
                    }
                } elseif ($otherViewTarget->id === $oldPlaylistItemId) {
                    $replaceResults[$key][2] = $newPlaylistItem;
                }
            }
        }
    }

    When I changed this code to modern version, the code will run without any problems.

    } elseif (!empty($replaceResults)) {
        foreach ($replaceResults as &$otherResult) {
            if (!empty($otherResult[2])) {
                list(,,$otherViewTarget) = $otherResult;
                if ($ids) {
                    if ($otherViewTarget === $oldPlaylistItemId) {
                           $otherResult[2] = $newPlaylistItem->id;
                    }
                } elseif ($otherViewTarget->id === $oldPlaylistItemId) {
                    $otherResult[2] = $newPlaylistItem;
                }
            }
        }
        unset($otherResult);
    }
  9. mdrmdrmdr commented on Dec 15, 2022

    @mdrmdrmdr
    Author

    NTS is supposed to be a wee bit faster, and if you don't need multi-threading, it's usually recommendable.

    Now I found out that I need ZTS. I'm running a local Apache installation. And it seems that NTS does not come with php8apache2_4.dll.

    When I changed this code to modern version, the code will run without any problems.

    Same here. Once I change the loop element to "access by reference", the loop does not crash PHP anymore.

  10. ndossche commented on Mar 25, 2023

    @ndossche
    Member

    This looks very similar to #10626. That issue was about predicted empty arrays and foreach loops causing a segfault. This was fixed in 8.2.4 and above. Given that the code you posted has both an empty check and foreach loop, I think this might be the same issue and may be fixed as well.

    Could you try version 8.2.4 and see if that fixes your problem? Thanks.

  11. mdrmdrmdr commented on Mar 25, 2023

    @mdrmdrmdr
    Author

    Dug up the old code from my NAS backup. The crash still occurs with PHP 8.2.4 64Bit ZTS on Windows.

    This one crashes (in the loop modifing the iterable_expression by val "$execs[$k][1]" ):

    foreach ($execs as $k => $exec) {
    	# combine start movement relays on & off if one exists already at same time
    	if ($exec[0] == 0 && $exec[2] == cmdOn) { $execs[$k][1] .= B.$blind[$first]; $on1 = true; }
    	if ($exec[0] == $blind[TA] && $exec[2] == cmdOff) { $execs[$k][1] .= B.$blind[$first]; $off1 = true; }
    	# combine stop movement relays on & off if one exists already at same time
    	if ($exec[0] == $delay && $exec[2] == cmdOn) { $execs[$k][1] .= ($stopMove ? B.$blind[$second] : ""); $on2 = true; }
    	if ($exec[0] == $delay+$blind[TD] && $exec[2] == cmdOff && $stopMove) { $execs[$k][1] .= B.$blind[$second]; $off2 = true; }
    }
    

    This one works fine (in the loop modifing the value by ref "$exec[1]"):

    foreach ($execs as &$exec) {
    	# combine start movement relays on & off if one exists already at same time
    	if ($exec[0] == 0 && $exec[2] == cmdOn) { $exec[1] .= B.$blind[$first]; $on1 = true; }
    	if ($exec[0] == $blind[TA] && $exec[2] == cmdOff) { $exec[1] .= B.$blind[$first]; $off1 = true; }
    	# combine stop movement relays on & off if one exists already at same time
    	if ($exec[0] == $delay && $exec[2] == cmdOn) { $exec[1] .= ($stopMove ? B.$blind[$second] : ""); $on2 = true; }
    	if ($exec[0] == $delay+$blind[TD] && $exec[2] == cmdOff && $stopMove) { $exec[1] .= B.$blind[$second]; $off2 = true; }
    }
    unset($exec);
    
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