rschupp / PAR-Packer

(perl) Generate stand-alone executables, perl scripts and PAR files https://metacpan.org/pod/PAR::Packer
Other
48 stars 13 forks source link

Odd PATH behaviour for packed binaries on MacOS Intel 12 #63

Closed plk closed 1 year ago

plk commented 2 years ago

I have the following odd situation on MacOS 12 Intel. Doesn't seem to happen on MacOS <12 Intel or on ARM at all. Take a simple script:

print 'PATH=' . $ENV{'PATH'} . "\n";

Call this script via absolute path or via shell PATH and it correctly prints the PATH of the environment. Pack it with 'pp' into a binary and unless it's called via an absolute path, it no longer sees the normal environment PATH and prints a truncated version of it. This is causing problems with things like IPC::Cmd::can_run() which can no longer find anything as the PATH the binary sees is broken.

Not sure what is going on here - it works on MacOS 10.15.7 Intel and on ARM MacOs 12. It fails on MacOS 12 Intel for some strange reason.

The raw perl script behaves as normal when called via absolute path or via PATH. Any hints appreciated.

Issue is being discussed here: https://github.com/plk/biber/issues/416

plk commented 2 years ago

Update - can reproduce on MacOS 10.12 Intel too - when called via PATH, the binary only returns the first component of PATH. When called via absolute path, it works as expected:

bbf-osx1012:tmp philkime$ echo $PATH
/opt/local/bin:/opt/local/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
bbf-osx1012:tmp philkime$ testb
PATH=/opt/local/bin
bbf-osx1012:tmp philkime$ /opt/local/bin/testb
PATH=/opt/local/bin:/opt/local/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
bbf-osx1012:tmp philkime$
rschupp commented 2 years ago

Odd indeed. AFAICT PAR::Packer never mangles PATH, at least from the Perl side. And the C side (in myldr) looks safe, too. Function par_findprog in myldr/utils.c has the potential to corrupt PATH if the executable was invoked without a path (i.e. argv[0] contains no slash). In that case it splits the result of par_getenv("PATH") at ":" and checks each component c if c + "/" + argv[0] exists and is executable. It uses strtok(path, ":") for the splitting which corrupts path in exactly the same way you're seeing (it changes the first occurrence of ":" to "\0", effectively truncating path after the first component). But it isn't called on par_getenv("PATH") (which is indeed a pointer inro the actual environment area), but on a copy (strdup).

Can you change the last lines of myldr/boot.c to the following, then rebuild PAR::Packer and repack your example:

#else
    fprintf(stderr, "boot: PATH=%s\n", par_getenv("PATH"));
    execvp(my_perl, argv);
    die("%s: exec of %s (custom Perl interpreter) failed (errno=%i)\n", 
        argv[0], my_perl, errno);
#endif
}
plk commented 2 years ago

Hmm, this makes little sense - seems ok now but this is with the latest version:

bbf-osx1012:tmp philkime$ echo $PATH
/opt/local/bin:/opt/local/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
bbf-osx1012:tmp philkime$ testb
boot: PATH=/opt/local/bin:/opt/local/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
PATH=/opt/local/bin:/opt/local/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
bbf-osx1012:tmp philkime$ /opt/local/bin/testb
boot: PATH=/opt/local/bin:/opt/local/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
PATH=/opt/local/bin:/opt/local/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin

I was using 1.051 and this is with 1.055 so I tried just vanilla 1.055 and it works ... so presumably something changed between these versions ...

rschupp commented 2 years ago

I was using 1.051 and this is with 1.055 so I tried just vanilla 1.055 and it works ... so presumably something changed between these versions ...

Among other stuff, the strdup for the first argument of par_findprog moved from the callers of that function into the function itself. But that doesn't explain it...

plk commented 2 years ago

I wondered if it was something to do with SIP in MacOS but that doesn't really explain it either.