Subject: | [PATCH] Fix build for VS2015 (VC++ 14) |
Using the patch called "perl-5.24.1-vc14.patch" attached to rt.perl.org #125714 I am able to build perl using the latest Visual Studio 2015 (VC++ 14.0), but PAR::Packer fails to build with that perl and compiler.
The attached patch fixes this. I found and fixed three problems:
1. Manifest files are not generated by default (and haven't been for a while now, actually) so they should not be embedded if not present. ExtUtils::MakeMaker and other similar tools already have similar code.
2. The new VC++ has a massively rewritten CRT and now defines some printf type functions inline, so the #define of snprint is no longer required.
3. I found that boot.exe was crashing on exit with the following call stack:
ntdll.dll!RtlpFreeHeap() Unknown
ntdll.dll!RtlFreeHeap() Unknown
ucrtbase.dll!___acrt_add_locale_ref() Unknown
ucrtbase.dll!___dcrt_uninitialize_environments_nolock() Unknown
ucrtbase.dll!___acrt_uninitialize_lowio() Unknown
ucrtbase.dll!___acrt_execute_uninitializers() Unknown
ucrtbase.dll!___acrt_add_locale_ref() Unknown
ucrtbase.dll!___acrt_DllMain@12() Unknown
ucrtbase.dll!___acrt_DllMain@12() Unknown
ntdll.dll!_LdrxCallInitRoutine@16() Unknown
ntdll.dll!LdrpCallInitRoutine() Unknown
ntdll.dll!LdrShutdownProcess() Unknown
ntdll.dll!RtlExitUserProcess() Unknown
kernel32.dll!_ExitProcessImplementation@4() Unknown
ucrtbase.dll!_swprintf() Unknown
ucrtbase.dll!_swprintf() Unknown
ucrtbase.dll!_exit() Unknown
Show quoted text
> boot.exe!main(int argc, char * * argv, char * * env) Line 234 C
That suggested a problem freeing memory, and code in env.c's par_setenv() function looked like an obvious candidate for causing corruption because of the way that it mallocs/reallocs chunks of the environ array, which is really managed by the CRT. I don't know why it worked in the past and breaks now, but documentation of _putenv() at https://msdn.microsoft.com/en-us/library/83zh4e6k.aspx does warn "Do not change an environment entry directly: instead, use _putenv or _wputenv to change it. In particular, direct freeing elements of the _environ[] global array might lead to invalid memory being addressed." Presumably the change is again to do with the CRT rewrite. Anyway, changing par_setenv() to simply call _putenv() on Windows fixes the crash.
Please consider this patch for your next release of PAR::Packer.
Many thanks for keeping this great tool alive!
Subject: | pp-vc14.patch |
diff --binary -ruN PAR-Packer-1.036.orig/myldr/Makefile.PL PAR-Packer-1.036/myldr/Makefile.PL
--- PAR-Packer-1.036.orig/myldr/Makefile.PL 2016-09-17 22:30:46.000000000 +0100
+++ PAR-Packer-1.036/myldr/Makefile.PL 2017-01-30 10:59:44.416670100 +0000
@@ -100,7 +100,7 @@
# Embed the manifest file for VC 2005 (aka VC8) or higher, but not for the
# 64-bit Platform SDK compiler.
if( $Config{ptrsize} == 4 and $Config{ccversion} =~ /^(\d+)/ and $1 >= 14 ) {
- $mt_cmd = 'mt -nologo -manifest $@.manifest -outputresource:$@;1';
+ $mt_cmd = 'if exist $@.manifest mt -nologo -manifest $@.manifest -outputresource:$@;1';
} else {
$mt_cmd = '-$(NOOP)';
}
diff --binary -ruN PAR-Packer-1.036.orig/myldr/env.c PAR-Packer-1.036/myldr/env.c
--- PAR-Packer-1.036.orig/myldr/env.c 2016-09-17 22:30:46.000000000 +0100
+++ PAR-Packer-1.036/myldr/env.c 2017-01-30 11:03:16.586930700 +0000
@@ -94,6 +94,14 @@
const char *name;
register const char *value;
{
+#ifdef WIN32
+ char* p = (char*)malloc((size_t)(strlen(name) + strlen(value) + 2));
+ if (!p)
+ return (-1);
+ sprintf(p, "%s=%s", name, value);
+ _putenv(p);
+ return (0);
+#else
extern char **environ;
static int alloced = 0; /* if allocated space before */
register char *c;
@@ -137,6 +145,7 @@
for (c = environ[offset]; (*c = *name++) && *c != '='; ++c);
for (*c++ = '='; (*c++ = *value++););
return (0);
+#endif
}
/*
diff --binary -ruN PAR-Packer-1.036.orig/myldr/mktmpdir.h PAR-Packer-1.036/myldr/mktmpdir.h
--- PAR-Packer-1.036.orig/myldr/mktmpdir.h 2016-09-17 22:30:46.000000000 +0100
+++ PAR-Packer-1.036/myldr/mktmpdir.h 2017-01-30 10:59:08.508541800 +0000
@@ -1,5 +1,7 @@
#ifdef _MSC_VER
-# define snprintf _snprintf
+# if _MSC_VER < 1900
+# define snprintf _snprintf
+# endif
# if _MSC_VER < 1500
# define vsnprintf _vsnprintf
# endif