Skip to content

Asyncify: Add few more function names#3037

Closed
Utsav-Ladani wants to merge 13 commits intoWordPress:trunkfrom
Utsav-Ladani:fix/file-get-contents-asyncify-error
Closed

Asyncify: Add few more function names#3037
Utsav-Ladani wants to merge 13 commits intoWordPress:trunkfrom
Utsav-Ladani:fix/file-get-contents-asyncify-error

Conversation

@Utsav-Ladani
Copy link
Copy Markdown
Contributor

Motivation for the change, related issues

Testing whether this fix the issue #2957

Implementation details

Adding few functions. Check code change for function names.

Testing Instructions (or ideally a Blueprint)

N/A

@adamziel
Copy link
Copy Markdown
Collaborator

@Utsav-Ladani thank you for contributing! @bgrgicak would you be able to review?

@Utsav-Ladani
Copy link
Copy Markdown
Contributor Author

@adamziel I tried building this for asyncify Node and it's still showing me same error. I guess more functions are missed from this list. Is there any standard way to find such function using any tool?

@adamziel
Copy link
Copy Markdown
Collaborator

@Utsav-Ladani Unfortunately, we don't have any standardized tool. working with these Asyncify problems is notoriously difficult. That being said, this doc page may be helpful in here: https://wordpress.github.io/wordpress-playground/developers/architecture/wasm-asyncify/#fixing-asyncify-crashes

Be sure to also check the linked resources is that there's more potentially helpful content in there.

@Utsav-Ladani Utsav-Ladani force-pushed the fix/file-get-contents-asyncify-error branch from 99c2a97 to 7194c27 Compare December 16, 2025 08:10
@Utsav-Ladani
Copy link
Copy Markdown
Contributor Author

Utsav-Ladani commented Dec 16, 2025

Thanks @adamziel and @bgrgicak for helpful insights. It was related to wrapping the file_get_contents function in the __clone() PHP magic method. After many trials and errors, I finally found all the missing functions and added them to the Dockerfile. I triggered a WASM crash in the playground by opening the following Blueprint in Safari, and the error is gone for PHP 7.4.

{
  "landingPage": "/wp-admin/plugins.php",
  "preferredVersions": {
    "php": "7.4",
    "wp": "5.9"
  },
  "steps": [
    {
      "step": "login",
      "username": "admin"
    },
    {
      "step": "writeFile",
      "path": "/wordpress/wp-content/plugins/crash-php-wasm.php",
      "data": {
        "resource": "url",
        "url": "https://gist.githubusercontent.com/bgrgicak/faad52a34f909306c82800a76a936da5/raw/6e836dccb28876eec07f6dbbe588e56b8c76b0aa/php-wasm-crash.php"
      }
    },
    {
      "step": "activatePlugin",
      "pluginPath": "/wordpress/wp-content/plugins/crash-php-wasm.php"
    }
  ],
  "features": {},
  "login": true
}

Additionally, this PR fixes a bunch of other PHP magic methods like __toString(), __debugInfo(), __serialize(), etc.

Now the only issue is that when a method has an async call like file_get_contents, it creates multiple instances of the object in memory because of context switching or something similar. However, it’s a valid case.

To test that behavior, run the following code with php-wasm-cli and it will print debug log multiple times.

<?php
/**
 * Comprehensive PHP Magic Methods Demo
 * This class demonstrates all PHP magic methods
 */
class MagicDemo
{
    private $name;

    public function __construct($name)
    {
        $this->name = $name;
    }

    public function __destruct()
    {
        echo "__destruct() called for: {$this->name}\n";
    }

    public function __clone()
    {
        $this->name = $this->name . " (cloned)";
        file_get_contents("https://gist.githubusercontent.com/bgrgicak/faad52a34f909306c82800a76a936da5/raw/php-wasm-crash.php");
        echo "__clone() called\n";
    }
}

$obj = new MagicDemo("MyObject");

$clonedObj = clone $obj;

Also, let me know the flow to recompile the PHP files.

@Utsav-Ladani Utsav-Ladani marked this pull request as ready for review December 16, 2025 08:42
@bgrgicak
Copy link
Copy Markdown
Collaborator

Great work @Utsav-Ladani 🚀

To test that behavior, run the following code with php-wasm-cli and it will print debug log multiple times.

Could you please add this test and other test examples you mentioned to php-part-2.spec.ts?

For testing, I suggest that you recompile one PHP version and run the tests using PHP=8.5 nx run php-wasm-node:test-group-6-asyncify -- --testNamePattern="Returns exit code > 0" (Replace the PHP version and test name pattern with your data).

Also, let me know the flow to recompile the PHP files.

I usually run npm run recompile:php:node:asyncify:all and npm run recompile:php:web:asyncify:all in parallel.

@adamziel
Copy link
Copy Markdown
Collaborator

Such a good work here @Utsav-Ladani, thank you for taking on this challenging fix!

@Utsav-Ladani Utsav-Ladani force-pushed the fix/file-get-contents-asyncify-error branch from 32605ee to 10a705b Compare December 18, 2025 06:07
@Utsav-Ladani
Copy link
Copy Markdown
Contributor Author

@bgrgicak @adamziel

I've added unit tests to packages/php-wasm/node/src/test/php-file-get-contents.spec.ts since it already had the necessary setup. Previously, the setup was broken because the port was a Promise object instead of a number. I fixed this by ensuring the promise resolves before use.

I updated the Dockerfile based on the errors I encountered. Currently, with PHP 7.4, only the __debugInfo() method is throwing errors. I've included all the required functions in the Dockerfile, but the error persists.

Let me know how to analyze and fix such errors.

@adamziel
Copy link
Copy Markdown
Collaborator

@Utsav-Ladani Asyncify is very tricky in that way. If you've listed all the functions and it still throws an error, I'd poke around with setting a breakpoint, stepping over a few calls and seeing if any other function appears. Also, adding an occasional console.trace() might reveal some interesting function names. There's also a chance we need to adjust ASYNCIFY_ flags in xdebug dockerfile or some other dockerfile.

That being said, this PR already makes things a lot better and I would be super happy to get this merged even if __debugInfo still throws an error – we'd just need to rebuild all the wasm binaries first. Be sure to rebase on top of the latest trunk as I've changed the file structure of the php-related packages and you'll need it before recompiling everything.

@Utsav-Ladani Utsav-Ladani force-pushed the fix/file-get-contents-asyncify-error branch from 6e4d212 to 275332d Compare December 24, 2025 05:16
@Utsav-Ladani
Copy link
Copy Markdown
Contributor Author

@adamziel I cannot rebuild the WASM binaries because my device is running out of space, so you or @bgrgicak have to rebuild it on your device.

@bgrgicak
Copy link
Copy Markdown
Collaborator

bgrgicak commented Jan 6, 2026

I'm recomiling it now.

I cannot rebuild the WASM binaries because my device is running out of space

When this happens to me, I'm usually able to work around it by pruning data and running web and Node recompiles separately (npm run recompile:php:web:jspi:all, npm run recompile:php:node:jspi:all, npm run recompile:php:web:asyncify:all, npm run recompile:php:node:asyncify:all).

docker container prune --force
docker image prune --force
docker volume prune --force
docker network prune --force
docker system prune -a --volumes --force

@bgrgicak
Copy link
Copy Markdown
Collaborator

bgrgicak commented Jan 6, 2026

Recomiling currently doesn't work due to a bug in how we pull PHP versions.
@mho22 addressed the bug in #3085, and once it's merged, we should be able to recompile this PR.

@bgrgicak
Copy link
Copy Markdown
Collaborator

bgrgicak commented Jan 6, 2026

@Utsav-Ladani I recompiled PHP-wasm and there are some test errors with file_get_contents. Would you have some time to take a look at it?

@Utsav-Ladani
Copy link
Copy Markdown
Contributor Author

Thanks @bgrgicak for your help. Finally, I am able to recompile everything with your docker prune trick.

I updated Dockerfile to fix __wakeup and __unserialize magic methods, but __debugInfo is still remaining. I tried various methods, but didn't able to find missing function.

However, it's only failing when xdebug is enabled. Happy to explore different techniques to debug it.

@bgrgicak
Copy link
Copy Markdown
Collaborator

bgrgicak commented Jan 9, 2026

However, it's only failing when xdebug is enabled. Happy to explore different techniques to debug it.

@mho22 do you have any tips on how to debug these test failures?

@mho22
Copy link
Copy Markdown
Collaborator

mho22 commented Jan 9, 2026

I tried to analyze what versions and environments caused these crashes

test-unit-asyncify (4/7)

__debugInfo

PHP8.5 : http protocol with and without Xdebug + https protocol with and without Xdebug
PHP8.4 : http protocol with and without Xdebug + https protocol with and without Xdebug
PHP8.3 : http protocol with Xdebug + https protocol with Xdebug
PHP8.2 : http protocol with Xdebug + https protocol with Xdebug
PHP8.1 : http protocol with Xdebug + https protocol with Xdebug
PHP8.0 : http protocol with Xdebug + https protocol with Xdebug
PHP7.4 : http protocol with Xdebug + https protocol with Xdebug


__toString

PHP7.2 : http protocol with Xdebug + https protocol with Xdebug

test-unit-asyncify (5/7)

process crash > Does not crash due to an unhandled Asyncify error 1408ms

the first one reproduces unreachable errors. This means other functions have to be discovered and added to the Asyncify list, like you did before. A way to help would be to compile one version of PHP.wasm Node, let's say 8.4 [ __debugInfo ] and 7.2 [ __toString ] with the --WITH_DEBUG=yes option.

npm run recompile:php:node:asyncify:8.4 -- --WITH_DEBUG=yes

npm run recompile:php:node:asyncify:7.2 -- --WITH_DEBUG=yes

This may help. Another one would be to run --stack-trace-limit=100 when running the test. This will give you a complete stack trace to find what function has been called but not listed in the asyncify list.

The second error process crash is a lot more complicated to debug. Since you added some functions in the asyncify list, the crash that we achieved to provoke before this pull request is not crashing anymore. But as it is related to file_get_contents function, if you fix the unreachable errors from the first tests, you probably will unblock the second tests file.

You should first fix the unreachable errors from PHP8.5 and PHP8.4 without Xdebug. Next, try to run the test with Xdebug enabled.

@Utsav-Ladani Utsav-Ladani requested a review from a team as a code owner February 3, 2026 15:49
@Utsav-Ladani Utsav-Ladani requested a review from zaerl February 3, 2026 15:49
@Utsav-Ladani
Copy link
Copy Markdown
Contributor Author

Thanks @mho22 for guiding me. I am able to fix errors related to PHP 8.5 and 5.4 w/o xdebug.

For PHP 7.2, support is dropped, so no need to fix it.

For crash related unit test, we are triggering network call inside clone method which crashes the process and then we test unhandled rejection, but since this PR fixes that edge case and allows to trigger network calls from clone method, it's failing. We need different test case to test the process crash.

@mho22
Copy link
Copy Markdown
Collaborator

mho22 commented Feb 4, 2026

@Utsav-Ladani Great work! Two last issues !

  1. I can see Xdebug causes problems in __debugInfo. It looks like a function or couple of functions are still missing here :
  RuntimeError: unreachable
   ❯ php_output_write ../../../wasm:/wasm/php.wasm-0578a0f2:1:4352943
   ❯ null.<anonymous> ../../../wasm:/wasm/00106486:1:191024
   ❯ execute_internal ../../../wasm:/wasm/php.wasm-0578a0f2:1:5094299
   ❯ null.<anonymous> ../../../wasm:/wasm/00106486:1:49392
   ❯ ZEND_DO_FCALL_SPEC_RETVAL_UNUSED_HANDLER ../../../wasm:/wasm/php.wasm-0578a0f2:1:5271896
   ❯ execute_ex ../../../wasm:/wasm/php.wasm-0578a0f2:1:5099001
   ❯ null.<anonymous> ../../../wasm:/wasm/00106486:1:48066
   ❯ zend_execute ../../../wasm:/wasm/php.wasm-0578a0f2:1:5100201
   ❯ zend_execute_scripts ../../../wasm:/wasm/php.wasm-0578a0f2:1:4772249
   ❯ dynCall_iiiii ../../../wasm:/wasm/php.wasm-0578a0f2:1:14455682

The null. ones are probably Xdebug ones. They are not problematic, I guess. The stack trace is not very explicit. You could isolate the test and run a command with --stack-trace-limit=100 like :

node --stack-trace-limit=100 ./node_modules/.bin/nx run php-wasm-node:test-group-3-asyncify

It will maybe return a more complete list of functions with the missing one(s) in it.

  1. process crash > Does not crash due to an unhandled Asyncify error doesn't want to crash anymore. It looks weird that a crash still occurs in PHP8.5 while it doesn't anymore in other PHP version. Do you have any idea why?

@Utsav-Ladani
Copy link
Copy Markdown
Contributor Author

@mho22 I debugged as you suggested and I get following functions in trace, I believe those are related to xdebug. Do I have to recompile xdebug? However, those tests are still failing.

"zif_xdebug_var_dump",\
"xdebug_dbgp_init",\
"xdebug_debug_init_if_requested_at_startup",\
"xdebug_objdebug_pp",\
"xdebug_get_zval_value_text_ansi",\

process crash > Does not crash due to an unhandled Asyncify error doesn't want to crash anymore. It looks weird that a crash still occurs in PHP8.5 while it doesn't anymore in other PHP version. Do you have any idea why?

As per code, process crash > Does not crash due to an unhandled Asyncify error test is skipped for PHP version >= 8.5, so it's passing. But for other PHP versions, It expects clone method to crash, but we fixed it, so process is not crashing. Hence, other tests are failed. Let me know how to trigger crash.

Screenshot 2026-02-10 at 8 53 02 PM

@mho22
Copy link
Copy Markdown
Collaborator

mho22 commented Feb 11, 2026

@Utsav-Ladani You don't have to recompile Xdebug. You found a tricky one. I remember trying to fix similar issues by calling emscripten_log or sprintf inside files from the stack trace to understand which function was missing in that stack trace... Not a fun moment. I need to dig deeper into this one.

And for the second point, I hadn't seen the skip option. So yes, we'll need to figure out what could provoke another Asyncify crash. WDYT @adamziel @bgrgicak @brandonpayton ?

@adamziel
Copy link
Copy Markdown
Collaborator

adamziel commented Feb 11, 2026

We could choose a different code path for PHP 8.5+ or just leave this test disabled in these newer PHP versions. JSPI in Safari will hopefully land before PHP 8.6 or 8.7 at the latest.

@mho22
Copy link
Copy Markdown
Collaborator

mho22 commented Feb 11, 2026

I'm sorry @adamziel, the issue is more related to the PHP versions < 8.5 tests not catching gracefully the Asyncify error anymore because this pull request seems to fix the crash. Could this be possible?

@adamziel
Copy link
Copy Markdown
Collaborator

Aha, gotcha! Listing ZEND_CLONE_SPEC_CV_HANDLER would do it. If there's a valid reason to add that function to the asyncify list, then let's do it and remove that test. It proved to be helpful once, but I don't expect much more Asyncify work to happen so we should be fine without it for a few more months.

Copilot AI review requested due to automatic review settings February 12, 2026 09:52
@Utsav-Ladani
Copy link
Copy Markdown
Contributor Author

@mho22 @adamziel @bgrgicak I removed that process crash related unit test. But not able to fix __debugInfo() method related unit test with xdebug. I tried using breakpoints and increased stack trace limit, but still no success. Please let me know how to debug further from this point.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@mho22
Copy link
Copy Markdown
Collaborator

mho22 commented Feb 18, 2026

@Utsav-Ladani I couldn't help but try this pull request locally, but it was full of oddly linted files. I decided to recreate the pull request based on only two files :

  • php/Dockerfile
  • test/php-file-get-contents.spec.ts

And I finally found out what was causing __debugInfo to crash, and it is clearly related to Xdebug : we had to disable the develop option in the extension's ini entries. That led to lots of other errors. So I pushed another pull request and I'd like to add you as co-author if you don't mind?

@Utsav-Ladani
Copy link
Copy Markdown
Contributor Author

@mho22 Thanks for taking care of remaining issues. Curious to know what was the actual issue.

@mho22
Copy link
Copy Markdown
Collaborator

mho22 commented Feb 23, 2026

Thanks to your work, we were able to run the clone function, which then triggered errors in the Asyncify crash test. Meanwhile, __debugInfowas crashing because of Xdebug.

In develop mode, Xdebug overrides var_dump with its own implementation, and the __debugInfo test relied on var_dump. Rather than finding a replacement for var_dump, I disabled Xdebug's develop mode and reuse that specific crash scenario in the Asyncify crash test file.

That said, since @brandonpayton implemented the multi-worker pull request, we've been experiencing other crashes, so the pull request is not complete yet.

mho22 added a commit that referenced this pull request Feb 24, 2026
## Motivation for the change, related issues

Reproduces issues from pull request :
#3037

Related to issue :
#2957

Thanks to the great work by @Utsav-Ladani, I was able to figure out the
remaining errors.

## Implementation details

- Add list of asyncify functions discovered by @Utsav-Ladani 
- Improving test file.

## Testing Instructions (or ideally a Blueprint)

CI

---------

Co-authored-by: Brandon Payton <brandon@happycode.net>
@mho22
Copy link
Copy Markdown
Collaborator

mho22 commented Feb 24, 2026

It is now merged. Thanks again @Utsav-Ladani for your pull request. I will close this one now.

@mho22 mho22 closed this Feb 24, 2026
@Utsav-Ladani
Copy link
Copy Markdown
Contributor Author

Thanks @mho22 @adamziel @bgrgicak for guiding me 🙇‍♂️.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants