Package: perl
Version: 5.14.2-21
Severity: important
Tags: patch

Dear Maintainer,

I reported this bug on the perl bug tracker:
https://rt.perl.org/rt3/Public/Bug/Display.html?id=117885
I discovered it was fixed in perl 5.16 so I bisected it and found out which
commit fix the problem.

Please find attached the patches of the git commit fixing it.

-- System Information:
Debian Release: 7.0
  APT prefers stable
  APT policy: (500, 'stable'), (1, 'experimental')
Architecture: i386 (i686)

Kernel: Linux 3.2.0-3-486
Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash

Versions of packages perl depends on:
ii  libbz2-1.0    1.0.6-4
ii  libc6         2.13-38
ii  libdb5.1      5.1.29-5
ii  libgdbm3      1.8.3-11
ii  perl-base     5.14.2-21
ii  perl-modules  5.14.2-21
ii  zlib1g        1:1.2.7.dfsg-13

Versions of packages perl recommends:
ii  netbase  5.0

Versions of packages perl suggests:
pn  libterm-readline-gnu-perl | libterm-readline-perl-perl  <none>
ii  make                                                    3.81-8.2
pn  perl-doc                                                <none>
>From 342f0eda56f3ef8fe29d43f50534cc03175774ef Mon Sep 17 00:00:00 2001
From: Nicholas Clark <n...@ccl4.org>
Date: Wed, 7 Sep 2011 13:15:04 +0200
Subject: [PATCH 1/3] Store struct termios used by POSIX::Termios directly in the object SV.

Previously POSIX::Termios was using the PTROBJ typemap to store a pointer to
a dynamically-allocated struct termios as an IV (blessed into the class).
This requires an explicit DESTROY to free the dynamic allocation, but fails
badly if any POSIX::Termios objects exist at ithread clone time, as the
dynamic allocation is not duplicated in the new thread. (DESTROY is called
in both threads, free-from-wrong pool or other jollity occurs.)

Removing dynamic allocation removes the need for a DESTROY method.

This introduces a new OPAQUEPTROBJ typemap, but currently doesn't use the
OUTPUT section, as that copies an existing structure, whereas
POSIX::Termios->new() only needs to zero-allocate the right space. Assuming
that this typemap should be of general applicability, it should be moved to
the main typemap file.
---
 ext/POSIX/POSIX.xs |   28 +++++++++++++---------------
 ext/POSIX/typemap  |   16 +++++++++++++++-
 2 files changed, 28 insertions(+), 16 deletions(-)

diff --git a/ext/POSIX/POSIX.xs b/ext/POSIX/POSIX.xs
index 8dc1f5a..0675dc2 100644
--- a/ext/POSIX/POSIX.xs
+++ b/ext/POSIX/POSIX.xs
@@ -715,30 +715,28 @@ sigismember(sigset, sig)
 
 MODULE = Termios	PACKAGE = POSIX::Termios	PREFIX = cf
 
-POSIX::Termios
+void
 new(packname = "POSIX::Termios", ...)
     const char *	packname
     CODE:
 	{
 #ifdef I_TERMIOS
-	    Newx(RETVAL, 1, struct termios);
+	    SV *t;
+	    ST(0) = sv_newmortal();
+	    t = newSVrv(ST(0), packname);
+	    sv_grow(t, sizeof(struct termios) + 1);
+	    SvCUR_set(t, sizeof(struct termios));
+	    SvPOK_on(t);
+	    /* The previous implementation stored a pointer to an uninitialised
+	       struct termios. Seems safer to initialise it, particularly as
+	       this implementation exposes the struct to prying from perl-space.
+	    */
+	    memset(SvPVX(t), 0, 1 + sizeof(struct termios));
+	    XSRETURN(1);
 #else
 	    not_here("termios");
-        RETVAL = 0;
 #endif
 	}
-    OUTPUT:
-	RETVAL
-
-void
-DESTROY(termios_ref)
-	POSIX::Termios	termios_ref
-    CODE:
-#ifdef I_TERMIOS
-	Safefree(termios_ref);
-#else
-	    not_here("termios");
-#endif
 
 SysRet
 getattr(termios_ref, fd = 0)
diff --git a/ext/POSIX/typemap b/ext/POSIX/typemap
index d54d5d1..b283099 100644
--- a/ext/POSIX/typemap
+++ b/ext/POSIX/typemap
@@ -12,5 +12,19 @@ speed_t			T_IV
 tcflag_t		T_IV
 cc_t			T_IV
 POSIX::SigSet		T_PTROBJ
-POSIX::Termios		T_PTROBJ
+POSIX::Termios		T_OPAQUEPTROBJ
 POSIX::SigAction	T_HVREF
+
+INPUT
+T_OPAQUEPTROBJ
+	if (SvROK($arg) && sv_derived_from($arg, \"${ntype}\")) {
+	    $var = ($type)SvPV_nolen(SvRV($arg));
+	}
+	else
+	    Perl_croak(aTHX_ \"%s: %s is not of type %s\",
+			${$ALIAS?\q[GvNAME(CvGV(cv))]:\qq[\"$pname\"]},
+			\"$var\", \"$ntype\")
+
+OUTPUT
+T_OPAQUEPTROBJ
+	sv_setref_pvn($arg, \"${ntype}\", (const char*)$var, sizeof(*$var));
-- 
1.7.2.5

>From 0ea9614344efd5f0a28b93bcf892e1502cce1614 Mon Sep 17 00:00:00 2001
From: Nicholas Clark <n...@ccl4.org>
Date: Wed, 7 Sep 2011 16:57:03 +0200
Subject: [PATCH 2/3] In POSIX.xs, extract allocate_struct() from POSIX::Termios::new().

The same code will be needed for POSIX::SigSet::new(), so share it as a small
static function.
---
 ext/POSIX/POSIX.xs |   20 +++++++++++++-------
 1 files changed, 13 insertions(+), 7 deletions(-)

diff --git a/ext/POSIX/POSIX.xs b/ext/POSIX/POSIX.xs
index 0675dc2..549c9c5 100644
--- a/ext/POSIX/POSIX.xs
+++ b/ext/POSIX/POSIX.xs
@@ -558,6 +558,16 @@ restore_sigmask(pTHX_ SV *osset_sv)
      (void)sigprocmask(SIG_SETMASK, ossetp, (sigset_t *)0);
 }
 
+static void *
+allocate_struct(pTHX_ SV *rv, const STRLEN size, const char *packname) {
+    SV *const t = newSVrv(rv, packname);
+    void *const p = sv_grow(t, size + 1);
+
+    SvCUR_set(t, size);
+    SvPOK_on(t);
+    return p;
+}
+
 #ifdef WIN32
 
 /*
@@ -721,17 +731,13 @@ new(packname = "POSIX::Termios", ...)
     CODE:
 	{
 #ifdef I_TERMIOS
-	    SV *t;
-	    ST(0) = sv_newmortal();
-	    t = newSVrv(ST(0), packname);
-	    sv_grow(t, sizeof(struct termios) + 1);
-	    SvCUR_set(t, sizeof(struct termios));
-	    SvPOK_on(t);
+	    void *const p = allocate_struct(aTHX_ (ST(0) = sv_newmortal()),
+					    sizeof(struct termios), packname);
 	    /* The previous implementation stored a pointer to an uninitialised
 	       struct termios. Seems safer to initialise it, particularly as
 	       this implementation exposes the struct to prying from perl-space.
 	    */
-	    memset(SvPVX(t), 0, 1 + sizeof(struct termios));
+	    memset(p, 0, 1 + sizeof(struct termios));
 	    XSRETURN(1);
 #else
 	    not_here("termios");
-- 
1.7.2.5

>From f62389dc35ad960c92ad755de5c1a453d4100c43 Mon Sep 17 00:00:00 2001
From: Nicholas Clark <n...@ccl4.org>
Date: Wed, 7 Sep 2011 18:52:36 +0200
Subject: [PATCH 3/3] Store sigset_t used by POSIX::SigSet directly in the object SV.

Previously POSIX::SigSet was using the PTROBJ typemap to store a pointer to
a dynamically-allocated sigset_t as an IV (blessed into the class)
This requires an explicit DESTROY to free the dynamic allocation, but fails
badly if any POSIX::SigSet objects exist at ithread clone time, as the
dynamic allocation is not duplicated in the new thread. (DESTROY is called
in both threads, free-from-wrong pool or other jollity occurs.)

Removing dynamic allocation removes the need for a DESTROY method.

This change is analogous to the previous change in POSIX::Termios, and is
made for the same reason.
---
 ext/POSIX/POSIX.xs |   37 +++++++++++++++----------------------
 ext/POSIX/typemap  |    2 +-
 2 files changed, 16 insertions(+), 23 deletions(-)

diff --git a/ext/POSIX/POSIX.xs b/ext/POSIX/POSIX.xs
index 549c9c5..48b800f 100644
--- a/ext/POSIX/POSIX.xs
+++ b/ext/POSIX/POSIX.xs
@@ -680,25 +680,21 @@ my_tzset(pTHX)
 
 MODULE = SigSet		PACKAGE = POSIX::SigSet		PREFIX = sig
 
-POSIX::SigSet
+void
 new(packname = "POSIX::SigSet", ...)
     const char *	packname
     CODE:
 	{
 	    int i;
-	    Newx(RETVAL, 1, sigset_t);
-	    sigemptyset(RETVAL);
+	    sigset_t *const s
+		= (sigset_t *) allocate_struct(aTHX_ (ST(0) = sv_newmortal()),
+					       sizeof(sigset_t),
+					       packname);
+	    sigemptyset(s);
 	    for (i = 1; i < items; i++)
-		sigaddset(RETVAL, SvIV(ST(i)));
+		sigaddset(s, SvIV(ST(i)));
+	    XSRETURN(1);
 	}
-    OUTPUT:
-	RETVAL
-
-void
-DESTROY(sigset)
-	POSIX::SigSet	sigset
-    CODE:
-	Safefree(sigset);
 
 SysRet
 sigaddset(sigset, sig)
@@ -1463,12 +1459,12 @@ sigaction(sig, optaction, oldaction = 0)
 		/* Get back the mask. */
 		svp = hv_fetchs(oldaction, "MASK", TRUE);
 		if (sv_isa(*svp, "POSIX::SigSet")) {
-		    IV tmp = SvIV((SV*)SvRV(*svp));
-		    sigset = INT2PTR(sigset_t*, tmp);
+		    sigset = (sigset_t *) SvPV_nolen(SvRV(*svp));
 		}
 		else {
-		    Newx(sigset, 1, sigset_t);
-		    sv_setptrobj(*svp, sigset, "POSIX::SigSet");
+		    sigset = (sigset_t *) allocate_struct(aTHX_ *svp,
+							  sizeof(sigset_t),
+							  "POSIX::SigSet");
 		}
 		*sigset = oact.sa_mask;
 
@@ -1522,8 +1518,7 @@ sigaction(sig, optaction, oldaction = 0)
 		/* Set up any desired mask. */
 		svp = hv_fetchs(action, "MASK", FALSE);
 		if (svp && sv_isa(*svp, "POSIX::SigSet")) {
-		    IV tmp = SvIV((SV*)SvRV(*svp));
-		    sigset = INT2PTR(sigset_t*, tmp);
+		    sigset = (sigset_t *) SvPV_nolen(SvRV(*svp));
 		    act.sa_mask = *sigset;
 		}
 		else
@@ -1564,8 +1559,7 @@ INIT:
 	if (! SvOK(ST(1))) {
 	    sigset = NULL;
 	} else if (sv_isa(ST(1), "POSIX::SigSet")) {
-	    IV tmp = SvIV((SV*)SvRV(ST(1)));
-	    sigset = INT2PTR(POSIX__SigSet,tmp);
+	    sigset = (sigset_t *) SvPV_nolen(SvRV(ST(1)));
 	} else {
 	    croak("sigset is not of type POSIX::SigSet");
 	}
@@ -1573,8 +1567,7 @@ INIT:
 	if (items < 3 || ! SvOK(ST(2))) {
 	    oldsigset = NULL;
 	} else if (sv_isa(ST(2), "POSIX::SigSet")) {
-	    IV tmp = SvIV((SV*)SvRV(ST(2)));
-	    oldsigset = INT2PTR(POSIX__SigSet,tmp);
+	    oldsigset = (sigset_t *) SvPV_nolen(SvRV(ST(2)));
 	} else {
 	    croak("oldsigset is not of type POSIX::SigSet");
 	}
diff --git a/ext/POSIX/typemap b/ext/POSIX/typemap
index b283099..e6a82dc 100644
--- a/ext/POSIX/typemap
+++ b/ext/POSIX/typemap
@@ -11,7 +11,7 @@ fd			T_IV
 speed_t			T_IV
 tcflag_t		T_IV
 cc_t			T_IV
-POSIX::SigSet		T_PTROBJ
+POSIX::SigSet		T_OPAQUEPTROBJ
 POSIX::Termios		T_OPAQUEPTROBJ
 POSIX::SigAction	T_HVREF
 
-- 
1.7.2.5

Reply via email to