PAR-Packer
PAR-Packer copied to clipboard
Subroutine requires_firewall redefined
On Windows, after x calls of the app.exe created with pp, the app does not start and the error message I can get is the following:
Subroutine requires_firewall redefined at C:\Users\User\AppData\Local\Temp\par-416e61\cache-d08980143978b78da45c870adb39c4834fc93e55\f7e1bfba.pm line 104.
I cannot understand how this can happen randomly after x calls. Deleting par-416e61 and rerunning the exe solves the issue. What can be the cause?
I cannot understand how this can happen randomly after x calls
Me neither 😕 Just for the record: can you state the OS you're using and the version of perl
, PAR::Packer
, PAR
and Module::ScanDeps
?
"Subroutine ... redefined" is typically just a warning and won't abort your program (unless someone does use warnings FATAL => ...
), so that message may be just a red herring. Have you looked at the file mentioned in the message, can you identify where it came from?
These are the info:
This is perl 5, version 32, subversion 1 (v5.32.1) built for MSWin32-x64-multi-thread
PAR::Packer: 1.052 PAR: 1.017 Module::ScanDeps: 1.31
Inspecting the entire par folder, I find only one item with "requires_firewall": Net::Config.pm
Note that the issue above (the logfile produced by the app looks like and endless print of the same statement (some loop?), can be found on only one machine...
This is perl 5, version 32, subversion 1 (v5.32.1) built for MSWin32-x64-multi-thread
Strawberry Perl, I guess?
PAR::Packer: 1.052 PAR: 1.017
A little old, but I don't see how stuff fixed in newer versions might affect your problem.
Inspecting the entire par folder, I find only one item with "requires_firewall": Net::Config.pm
That's what I suspected as well. What's strange is the file from where the message apparently originates: files named 8-hex-numbers.pm in the top level of the par cache folder should be either a copy of the script packed by pp
or copies of a well-known set of modules, but Net::Config
isn't among them.
Anyway, my first suspicion when I see "a packed program stops working after several successful invocations" is some program periodically cleaning up the user's temp folder and randomly deleting files in the par cache folder. The files in the cache folder are written only when the folder doesn't exist. Once an invocation of the packed program sees the cache folder, it assumes it's complete. That's why blowing away the cache folder solves the problem (at least temporarily).
PAR::Packer
uses a simple heuristic to work against such cleaners: all files extracted are timestamped with the time of extraction and one file (_canary_.txt or such) is created with a timestamp backdated by a few days. And the check for "can we skip extracting files" is actually: does the cache folder exist and contains _canary_.txt? If this heuristic fails and a cleaner randomly deletes files from the cache, I would typically expect the packed program to fail with "can't find module Foo" errors, but other ways are conceivable.
If you can get hold of the cache folder where the problem manifests itself you could compare its contents to the contents of a freshly extracted cache folder.
Yes, I suspect too that some files may get deleted from the par cache folder. In the past I had a recurring case of a specific .txt file get routinely deleted from (some) macOS computers. I ended up avoiding the use of the module relying on that file.
I am wondering if adding a "file count" - at run time - of the files present in the cache folder may be a viable solution to avoid this behavior (which does not happen frequently, but it happens). The file number may be added in the canary.txt. Any variation would trigger a new unpacking of the file.
Maybe PAR::Packer
should just use another location (see #23) for the cache folder that isn't prone to cleaner shenanigans?
It doesn't solve your problem, but I can reproduce it (on Linux with latest perl, PAR and PAR::Packer):
- pack the one-liner
pp -o bad.exe -E "say qq[PAR_TEMP = $ENV{PAR_TEMP}]; require Net::Config; say $INC{'Net/Config.pm'};"
- run
bad.exe
once - remove the file named in the second line of its output
- run
bad.exe
again
On the second run, the previously extracted Net/Config.pm
has vanished, hence PAR::Packer
falls back to the legacy "extract on demand" method and extracts this file from the exe (which is also a zip file) into one of these 8-hex-numbers.pm in the top level of the par cache folder. It executes that file and goes into an infinite loop here (~line 77)
my $file = __FILE__;
my $ref;
$file =~ s/Config.pm/libnet.cfg/;
if (-f $file) {
$ref = eval { local $SIG{__DIE__}; do $file };
because __FILE__
(and hence $file
) is something like /tmp/par-726f646572696368/cache-888dae6771dccfee8408e8b456df4bcde57f820e/71d26277.pm
, i.e. not .../Config.pm
, hence $file
is unchanged after s///
and is loaded a second time via do $file
.
I call that a bug (for not checking the success of the substitution and in general messing with __FILE__
).