PAR-Packer
PAR-Packer copied to clipboard
Odd PATH behaviour for packed binaries on MacOS Intel 12
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
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$
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
}
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 ...
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...
I wondered if it was something to do with SIP in MacOS but that doesn't really explain it either.