Page MenuHomePhorge

arcanist EXCEPTION: (CommandException) Command failed with error #-1!
Closed, WontfixPublic

Description

This is a funny one. The issue occurs on a Linux server running Remi el8 PHP 8.1, but not on another Linux server running Remi el7 PHP 8.1

When I do an 'arc land' it errors with:

EXCEPTION: (CommandException) Command failed with error #-1!
COMMAND
php -d variables_order=E -r 'echo json_encode($_ENV);'

STDOUT
{MyEnvironmentVars}

STDERR
(empty) at [<arcanist>/src/future/exec/ExecFuture.php:436]
arcanist(head=master, ref.master=788098096e11)
  #0 ExecFuture::raiseResultError(array) called at [<arcanist>/src/future/exec/ExecFuture.php:340]
  #1 ExecFuture::resolvex() called at [<arcanist>/src/future/exec/execx.php:17]
  #2 execx(string, string) called at [<arcanist>/src/utils/PhutilExecutionEnvironment.php:40]
  #3 PhutilExecutionEnvironment::repairMissingVariablesOrder() called at [<arcanist>/support/init/init-script.php:120]
  #4 __arcanist_init_script__() called at [<arcanist>/support/init/init-script.php:131]
  #5 require_once(string) called at [<arcanist>/support/init/init-arcanist.php:3]
  #6 require_once(string) called at [<arcanist>/bin/arc:10]

Debugging showed that every call to proc_get_status() in ExecFuture.php returned an exitcode of -1, before and after the process completing.

My workaround kludge is to assume assume nothing really returns -1:

diff --git a/src/future/exec/ExecFuture.php b/src/future/exec/ExecFuture.php
index ddf9e515..31d4c90f 100644
--- a/src/future/exec/ExecFuture.php
+++ b/src/future/exec/ExecFuture.php
@@ -932,6 +932,8 @@ final class ExecFuture extends PhutilExecutableFuture {
     }

     $this->procStatus = proc_get_status($this->proc);
+    if ($this->procStatus['exitcode'] == -1)
+           $this->procStatus['exitcode'] = 0;

     return $this->procStatus;

Trying to replicate the issue outside of arcanist fails. The following ends with an exitcode 0 as expected:

#!/usr/bin/env php
<?php

$descriptorspec = [['pipe', 'r'], ['pipe', 'w'], ['pipe', 'w']]; //STDIN, STDOUT, STDERR
$proc = proc_open("php -d variables_order=E -r 'echo json_encode(\$_ENV);'", $descriptorspec, $pipes);
do {
  $status = proc_get_status($proc);
  echo var_export($status, true), "\n";
  if (! $status['running'])
    break;
} while (true);

Which means it's probably something in the guts of PHP related to the specific server build. Thought I'd put it out here to see if anyone else experienced it.

Event Timeline

What is even stranger is that theoretically, php should not be able to exit with a status code of -1 - If you try, it changes it to 255

$ php -r 'exit(-1);'
$ echo $?
255

So - How did this command php -d variables_order=E -r 'echo json_encode($_ENV);' exit with a status code of -1?

This is probs related : https://stackoverflow.com/questions/71354900/php-proc-get-status-exitcode-is-always-1-after-pcntl-fork

And here are some related release notes - https://github.com/php/php-src/blob/master/UPGRADING (These are for PHP 8.3)

Executing proc_get_status() multiple times will now always return the right
value on posix systems. Previously, only the first call of the function
returned the right value. Executing proc_close() after proc_get_status() will
now also return the right exit code. Previously this would return -1.
Internally, this works by caching the result on posix systems. If you want
the old behaviour, you can check the "cached" key in the array returned by
proc_get_status() to check whether the result was cached.

This is probs related : https://stackoverflow.com/questions/71354900/php-proc-get-status-exitcode-is-always-1-after-pcntl-fork

Yes it is! Adding 'pcntl_signal(SIGCHLD, SIG_IGN);' to the top of my test script results in an exitcode of -1 being returned. However, it does so on both of my systems. However, if I set SIGCHLD to a signal handler function like FutureIterator.php then I can replicate my fault such that the one system returns an exitcode of -1, and the other system returns 0.

#!/usr/bin/env php
<?php

function handleSIGCHLD($signo) {
}

pcntl_signal(SIGCHLD, 'handleSIGCHLD');

$proc = proc_open("/usr/bin/sleep 1", [['pipe', 'r'], ['pipe', 'w'], ['pipe', 'w']], $pipes);
do {
    $status = proc_get_status($proc);
    if (! $status['running'])
        break;
    usleep(300000);
} while (true);
echo "Exitcode: $status[exitcode]", PHP_EOL;
Sten claimed this task.

Three days ago I ran into the same output (though different steps in Phorge that I don't perfectly remember) after upgrading from PHP 8.2.8 to PHP 8.2.9 on Fedora 38. Thus I downgraded again.

The issue is in a change which went in with PHP 8.1.22, and is being reverted in PHP 8.1.23.
@aklapper - as PHP 8.2.9 isn't released yet, I assume you compiled from source? If you 'git pull' and recompile, the latest 8.2.9-dev should work. The fix was committed Aug 2 21:08:52.

For the records, I did not compile from source, I had used the official Fedora package php-8.2.9-1.fc38 created on Aug 1st from https://koji.fedoraproject.org/koji/packageinfo?packageID=72