Wed Jun 06 09:16:51 2018: Request 125503 was acted upon.
Transaction: Ticket created by SHAY
Queue: PAR-Packer
Subject: [PATCH] Fix build with 64-bit perl-5.28.0
Broken in: 1.043
Severity: (no value)
Owner: Nobody
Requestors: [email protected]
Status: new
Ticket <URL: https://rt.cpan.org/Ticket/Display.html?id=125503 >
In perl-5.28.0 the PL_statbuf interpreter variable has been removed. This
causes code in several places in PAR-Packer to define it as a "struct stat":
#ifndef PL_statbuf
struct stat PL_statbuf;
#endif
That's fine in boot.c where the code ends up in a plain C program, but not in
mktmpdir.c and utils.c when the code may end up in the custom Perl interpreter
because in that case PL_statbuf is passed to par_lstat(), which is defined as
either lstat() or stat(), which may themselves be defined as calls into PerlIO.
In my case, in an x64 build on Windows, stat() ends up calling perl's
win32_stat(), which calls _stati64(), which expects a struct _stati64 to handle
64-bit times. I found that the 64-bit times got written anyway - into the
struct stat, which only has space for 32-bit times, causing a buffer overrun
and resulting in the following crash when exiting isWritableDir(): "Unhandled
exception at 0x00007FF7183F4554 in par.exe: Stack cookie instrumentation code
detected a stack-based buffer overrun."
(It works in 32-bit builds because win32_stat() calls stat() in that case, for
which struct stat is correct.)
I think the answer is the attached patch, which introduces a par_stat_t to be
used with par_lstat(), and is defined to be perl's Stat_t (which will already
be set up as a suitable struct type to match whatever flavour of stat() gets
used) if that's defined (i.e. in the customer Perl interpreter case), or struct
stat otherwise (i.e. in the plain C program case).
diff -ruN --binary PAR-Packer-1.043.orig/myldr/mktmpdir.c PAR-Packer-1.043/myldr/mktmpdir.c
--- PAR-Packer-1.043.orig/myldr/mktmpdir.c 2017-02-11 17:19:06.000000000 +0000
+++ PAR-Packer-1.043/myldr/mktmpdir.c 2018-06-06 13:03:36.410791600 +0100
@@ -21,7 +21,7 @@
static int isWritableDir(const char* val)
{
#ifndef PL_statbuf
- struct stat PL_statbuf;
+ par_stat_t PL_statbuf;
#endif
return par_lstat(val, &PL_statbuf) == 0 &&
@@ -38,7 +38,7 @@
static int isSafeDir(const char* val)
{
#ifndef PL_statbuf
- struct stat PL_statbuf;
+ par_stat_t PL_statbuf;
#endif
return par_lstat(val, &PL_statbuf) == 0 &&
diff -ruN --binary PAR-Packer-1.043.orig/myldr/mktmpdir.h PAR-Packer-1.043/myldr/mktmpdir.h
--- PAR-Packer-1.043.orig/myldr/mktmpdir.h 2017-02-04 23:29:19.000000000 +0000
+++ PAR-Packer-1.043/myldr/mktmpdir.h 2018-06-06 13:03:07.349713300 +0100
@@ -67,6 +67,12 @@
#define par_lstat stat
#endif
+#ifdef Stat_t
+#define par_stat_t Stat_t
+#else
+#define par_stat_t struct stat
+#endif
+
#if defined(WIN32) || defined(OS2)
static const char *dir_sep = "\\";
static const char *path_sep = ";";
diff -ruN --binary PAR-Packer-1.043.orig/myldr/utils.c PAR-Packer-1.043/myldr/utils.c
--- PAR-Packer-1.043.orig/myldr/utils.c 2017-03-12 17:26:54.000000000 +0000
+++ PAR-Packer-1.043/myldr/utils.c 2018-06-06 13:03:48.029684100 +0100
@@ -95,7 +95,7 @@
* to a struct stat. Try to distinguish these cases by checking
* whether PL_statbuf is defined. */
#ifndef PL_statbuf
-struct stat PL_statbuf;
+par_stat_t PL_statbuf;
#endif
#ifdef WIN32