[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#724849: pu: package perl/5.14.2-21+deb7u1



Package: release.debian.org
Severity: normal
User: release.debian.org@packages.debian.org
Usertags: pu

Attached are two patches against perl 5.14.2-21 for consideration for
the next wheezy point release.

The first patch contains mainly functional changes with associated
Debian bugs. The second set are correctness/believed-to-be-non-exploitable
security issues taken from 5.14.4.

Please note that a separate bug report will follow for
libdigest-sha-perl, which will need to be released at the same time.

Please would you let me know whether I may upload packages including
either or both sets of changes?

Thanks,
Dominic.
diff --git a/cpan/Digest-SHA/SHA.xs b/cpan/Digest-SHA/SHA.xs
index 7088a33..893bed2 100644
--- a/cpan/Digest-SHA/SHA.xs
+++ b/cpan/Digest-SHA/SHA.xs
@@ -23,6 +23,9 @@ PROTOTYPES: ENABLE
 int
 shaclose(s)
 	SHA *	s
+CODE:
+       RETVAL = shaclose(s);
+       sv_setiv(SvRV(ST(0)), 0);
 
 int
 shadump(file, s)
diff --git a/cpan/Digest-SHA/lib/Digest/SHA.pm b/cpan/Digest-SHA/lib/Digest/SHA.pm
index 8cea302..2e70f60 100644
--- a/cpan/Digest-SHA/lib/Digest/SHA.pm
+++ b/cpan/Digest-SHA/lib/Digest/SHA.pm
@@ -65,7 +65,7 @@ sub new {
 
 sub DESTROY {
 	my $self = shift;
-	shaclose($$self) if $$self;
+	if ($$self) { shaclose($$self); $$self = undef }
 }
 
 sub clone {
diff --git a/debian/.git-dpm b/debian/.git-dpm
index c8c980a..36f1942 100644
--- a/debian/.git-dpm
+++ b/debian/.git-dpm
@@ -1,6 +1,6 @@
 # see git-dpm(1) from git-dpm package
-93f6c83c7454de33df00a0e3fde3a890d6c87e91
-93f6c83c7454de33df00a0e3fde3a890d6c87e91
+504aefc29e21b6cc8e7d81ca83548ccda7ca606d
+504aefc29e21b6cc8e7d81ca83548ccda7ca606d
 5f99bf7a09dd2ae3c22081331f4973210a543731
 5f99bf7a09dd2ae3c22081331f4973210a543731
 perl_5.14.2.orig.tar.bz2
diff --git a/debian/changelog b/debian/changelog
index 14df505..fa9a5b9 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,13 @@
+perl (5.14.2-21+deb7u1) UNRELEASED; urgency=low
+
+  * Fix issue with shared references disappearing on sub return
+    (Closes: #718438)
+  * Make perlbug.PL look up local patches at runtime (Closes: #710842)
+  * Apply patch from upstream fixing Digest::SHA double-free
+    crash (Closes: #711206)
+
+ -- Dominic Hargreaves <dom@earth.li>  Mon, 23 Sep 2013 20:40:20 +0100
+
 perl (5.14.2-21) unstable; urgency=low
 
   [ Dominic Hargreaves ]
diff --git a/debian/control b/debian/control
index a0310a1..0840ed0 100644
--- a/debian/control
+++ b/debian/control
@@ -282,7 +282,7 @@ Breaks: perl-doc (<< ${Upstream-Version}-1),
  libmime-base64-perl (<< 3.13),
  libtime-hires-perl (<< 1.9721.01),
  libstorable-perl (<< 2.27),
- libdigest-sha-perl (<< 5.71-2),
+ libdigest-sha-perl (<< 5.71-2+deb7u1),
  libsys-syslog-perl (<< 0.27),
  libcompress-zlib-perl (<< 2.033),
  libcompress-raw-zlib-perl (<< 2.033),
diff --git a/debian/patches/fixes/digest_sha_double_free.diff b/debian/patches/fixes/digest_sha_double_free.diff
new file mode 100644
index 0000000..340a699
--- /dev/null
+++ b/debian/patches/fixes/digest_sha_double_free.diff
@@ -0,0 +1,43 @@
+From 504aefc29e21b6cc8e7d81ca83548ccda7ca606d Mon Sep 17 00:00:00 2001
+From: Chris 'BinGOs' Williams <chris@bingosnet.co.uk>
+Date: Fri, 28 Jun 2013 13:07:34 +0100
+Subject: maint-5.18: Digest-SHA crash fix in 5.85
+
+Backported minimal changes from blead
+
+Bug-Debian: http://bugs.debian.org/711206
+Bug: https://rt.cpan.org/Public/Bug/Display.html?id=86295
+Origin: http://perl5.git.perl.org/perl.git/commit/ee8c6f40e6bd7b4e08eac8386f9a092fdd609ffa
+Patch-Name: fixes/digest_sha_double_free.diff
+---
+ cpan/Digest-SHA/SHA.xs            |    3 +++
+ cpan/Digest-SHA/lib/Digest/SHA.pm |    2 +-
+ 2 files changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/cpan/Digest-SHA/SHA.xs b/cpan/Digest-SHA/SHA.xs
+index 7088a33..893bed2 100644
+--- a/cpan/Digest-SHA/SHA.xs
++++ b/cpan/Digest-SHA/SHA.xs
+@@ -23,6 +23,9 @@ PROTOTYPES: ENABLE
+ int
+ shaclose(s)
+ 	SHA *	s
++CODE:
++       RETVAL = shaclose(s);
++       sv_setiv(SvRV(ST(0)), 0);
+ 
+ int
+ shadump(file, s)
+diff --git a/cpan/Digest-SHA/lib/Digest/SHA.pm b/cpan/Digest-SHA/lib/Digest/SHA.pm
+index 8cea302..2e70f60 100644
+--- a/cpan/Digest-SHA/lib/Digest/SHA.pm
++++ b/cpan/Digest-SHA/lib/Digest/SHA.pm
+@@ -65,7 +65,7 @@ sub new {
+ 
+ sub DESTROY {
+ 	my $self = shift;
+-	shaclose($$self) if $$self;
++	if ($$self) { shaclose($$self); $$self = undef }
+ }
+ 
+ sub clone {
diff --git a/debian/patches/fixes/perlbug-patchlist.diff b/debian/patches/fixes/perlbug-patchlist.diff
new file mode 100644
index 0000000..d123722
--- /dev/null
+++ b/debian/patches/fixes/perlbug-patchlist.diff
@@ -0,0 +1,83 @@
+From dc41c3a1d8f2f3f3f507971fe86eb45079e5ec21 Mon Sep 17 00:00:00 2001
+From: Niko Tyni <ntyni@debian.org>
+Date: Thu, 27 Jun 2013 14:37:01 +0300
+Subject: Make perlbug look up the list of local patches at run time
+
+Re-parsing patchlevel.h in Perl by perlbug.PL is error prone
+and apparently unnecessary. The same information is available
+to perlbug via Config::local_patches().
+
+This fixes [perl #118433].
+
+Bug: https://rt.perl.org/rt3/Public/Bug/Display.html?id=118433
+Bug-Debian: http://bugs.debian.org/710842
+Origin: http://perl5.git.perl.org/perl.git/commit/3541c11ab9be01478a51881e3972abb78481726e
+Patch-Name: fixes/perlbug-patchlist.diff
+---
+ utils/perlbug.PL |   39 ++++++---------------------------------
+ 1 file changed, 6 insertions(+), 33 deletions(-)
+
+diff --git a/utils/perlbug.PL b/utils/perlbug.PL
+index 368ce91..8318531 100644
+--- a/utils/perlbug.PL
++++ b/utils/perlbug.PL
+@@ -22,37 +22,12 @@ $file .= '.com' if $^O eq 'VMS';
+ 
+ open OUT, ">$file" or die "Can't create $file: $!";
+ 
+-# extract patchlevel.h information
++# get patchlevel.h timestamp
+ 
+-open PATCH_LEVEL, "<" . catfile(updir, "patchlevel.h")
+-    or die "Can't open patchlevel.h: $!";
++-e catfile(updir, "patchlevel.h")
++    or die "Can't find patchlevel.h: $!";
+ 
+-my $patchlevel_date = (stat PATCH_LEVEL)[9];
+-
+-while (<PATCH_LEVEL>) {
+-    last if $_ =~ /^\s*static\s+(?:const\s+)?char.*?local_patches\[\]\s*=\s*{\s*$/;
+-}
+-
+-if (! defined($_)) {
+-    warn "Warning: local_patches section not found in patchlevel.h\n";
+-}
+-
+-my @patches;
+-while (<PATCH_LEVEL>) {
+-    last if /^\s*}/;
+-    next if /^\s*#/;  # preprocessor stuff
+-    next if /PERL_GIT_UNPUSHED_COMMITS/;    # XXX expand instead
+-    next if /"uncommitted-changes"/;        # XXX determine if active instead
+-    chomp;
+-    s/^\s+,?\s*"?//;
+-    s/"?\s*,?$//;
+-    s/(['\\])/\\$1/g;
+-    push @patches, $_ unless $_ eq 'NULL';
+-}
+-my $patch_desc = "'" . join("',\n    '", @patches) . "'";
+-my $patch_tags = join "", map /(\S+)/ ? "+$1 " : (), @patches;
+-
+-close(PATCH_LEVEL) or die "Error closing patchlevel.h: $!";
++my $patchlevel_date = (stat _)[9];
+ 
+ # TO DO (prehaps): store/embed $Config::config_sh into perlbug. When perlbug is
+ # used, compare $Config::config_sh with the stored version. If they differ then
+@@ -74,15 +49,13 @@ $Config{startperl}
+ my \$config_tag1 = '$extract_version - $Config{cf_time}';
+ 
+ my \$patchlevel_date = $patchlevel_date;
+-my \$patch_tags = '$patch_tags';
+-my \@patches = (
+-    $patch_desc
+-);
+ !GROK!THIS!
+ 
+ # In the following, perl variables are not expanded during extraction.
+ 
+ print OUT <<'!NO!SUBS!';
++my @patches = Config::local_patches();
++my $patch_tags = join "", map /(\S+)/ ? "+$1 " : (), @patches;
+ 
+ use warnings;
+ no warnings 'once'; # Eventually, the $::opt_ stuff should get cleaned up
diff --git a/debian/patches/fixes/threads_shared_elements_crash.diff b/debian/patches/fixes/threads_shared_elements_crash.diff
new file mode 100644
index 0000000..20f9eac
--- /dev/null
+++ b/debian/patches/fixes/threads_shared_elements_crash.diff
@@ -0,0 +1,178 @@
+From 4e07a8e0c8772662e962688a7f7eef04c1540a0c Mon Sep 17 00:00:00 2001
+From: Nicholas Clark <nick@ccl4.org>
+Date: Fri, 2 Aug 2013 12:08:33 +0200
+Subject: threads::shared should not crash if shared elements outlive their
+ aggregate.
+
+If an element of a shared aggregate is returned from a function, it is
+possible for it to outlive the aggregate itself. As the element has a pointer
+to the underlying shared aggregate and might use it, it is necessary for that
+pointer to remain valid. Hence threads::shared needs to ensure that cleanup
+of the shared aggregate is performed by the last proxy pointing to it, which
+is not necessarily the proxy for the aggregate itself. This can happen with
+lvalue subroutines.
+
+See the discussion in perl #119089 for more details.
+
+Backport to 5.14 via discussion in the upstream RT ticket.
+
+Bug-Debian: http://bugs.debian.org/718438
+Bug: https://rt.perl.org/rt3/Ticket/Display.html?id=119089
+Patch-Name: fixes/threads_shared_elements_crash.diff
+---
+ dist/threads-shared/shared.xs   |   39 +++++++++++++++++++++++++++++++++++++--
+ dist/threads-shared/t/av_refs.t |   27 ++++++++++++++++++++++++++-
+ dist/threads-shared/t/hv_refs.t |   24 +++++++++++++++++++++++-
+ 3 files changed, 86 insertions(+), 4 deletions(-)
+
+diff --git a/dist/threads-shared/shared.xs b/dist/threads-shared/shared.xs
+index 7f1cd06..a21606c 100644
+--- a/dist/threads-shared/shared.xs
++++ b/dist/threads-shared/shared.xs
+@@ -998,6 +998,27 @@ sharedsv_elem_mg_DELETE(pTHX_ SV *sv, MAGIC *mg)
+     return (0);
+ }
+ 
++int
++sharedsv_elem_mg_free(pTHX_ SV *sv, MAGIC *mg)
++{
++    dTHXc;
++    PERL_UNUSED_ARG(sv);
++    ENTER_LOCK;
++    if (mg->mg_obj) {
++        if (!PL_dirty) {
++            assert(SvROK(mg->mg_obj));
++        }
++        if (SvREFCNT(mg->mg_obj) == 1) {
++            /* If the element has the last pointer to the shared aggregate, then
++               it has to free the shared aggregate.  mg->mg_obj itself is freed
++               by Perl_mg_free()  */
++            S_sharedsv_dec(aTHX_ S_sharedsv_from_obj(aTHX_ mg->mg_obj));
++        }
++    }
++    LEAVE_LOCK;
++    return (0);
++}
++
+ /* Called during cloning of PERL_MAGIC_tiedelem(p) magic in new
+  * thread */
+ 
+@@ -1015,7 +1036,7 @@ MGVTBL sharedsv_elem_vtbl = {
+     sharedsv_elem_mg_STORE,     /* set */
+     0,                          /* len */
+     sharedsv_elem_mg_DELETE,    /* clear */
+-    0,                          /* free */
++    sharedsv_elem_mg_free,      /* free */
+     0,                          /* copy */
+     sharedsv_elem_mg_dup,       /* dup */
+ #ifdef MGf_LOCAL
+@@ -1069,7 +1090,21 @@ int
+ sharedsv_array_mg_free(pTHX_ SV *sv, MAGIC *mg)
+ {
+     PERL_UNUSED_ARG(sv);
+-    S_sharedsv_dec(aTHX_ (SV*)mg->mg_ptr);
++    if (!PL_dirty) {
++        assert(mg->mg_obj);
++        assert(SvROK(mg->mg_obj));
++        assert(SvUV(SvRV(mg->mg_obj)) == PTR2UV(mg->mg_ptr));
++    }
++    if (mg->mg_obj) {
++        if (SvREFCNT(mg->mg_obj) == 1) {
++            S_sharedsv_dec(aTHX_ (SV*)mg->mg_ptr);
++        } else {
++            /* An element of this aggregate still has PERL_MAGIC_tied(p)
++               pointing to this shared aggregate.  It will take responsibility
++               for freeing the shared aggregate.  Perl_mg_free() drops the
++               reference count on mg->mg_obj.  */
++        }
++    }
+     return (0);
+ }
+ 
+diff --git a/dist/threads-shared/t/av_refs.t b/dist/threads-shared/t/av_refs.t
+index 8106e32..5243c54 100644
+--- a/dist/threads-shared/t/av_refs.t
++++ b/dist/threads-shared/t/av_refs.t
+@@ -27,7 +27,7 @@ sub ok {
+ 
+ BEGIN {
+     $| = 1;
+-    print("1..14\n");   ### Number of tests that will be run ###
++    print("1..16\n");   ### Number of tests that will be run ###
+ };
+ 
+ use threads;
+@@ -90,6 +90,31 @@ ok(13, is_shared(@av), "Check for sharing");
+ my $x :shared;
+ ok(14, is_shared($x), "Check for sharing");
+ 
++# This is a reduction of the test case from perl #119089. Whilst the bug that
++# this exposes was fixed by a core change in 5.15.7, the variant with lvalues
++# below would still crash, and the fix for it also a fix for this bug on earlier
++# perl versions:
++
++sub elem_on_stack {
++    my @a :shared;
++    $a[0] = 6;
++    $a[0];
++}
++
++ok(15, defined elem_on_stack(), "element on stack should be defined");
++
++sub lvalue_elem_on_stack :lvalue {
++    my @a :shared;
++    $a[0];
++}
++
++if ($] >= 5.008008) {
++    lvalue_elem_on_stack() = 9;
++    ok(16, 1, "assigning to lvalue element on stack does not crash");
++} else {
++    print "ok 16 # skip $] can't return temporaries from lvalue subs\n";
++}
++
+ exit(0);
+ 
+ # EOF
+diff --git a/dist/threads-shared/t/hv_refs.t b/dist/threads-shared/t/hv_refs.t
+index ecefdc6..3b9b36b 100644
+--- a/dist/threads-shared/t/hv_refs.t
++++ b/dist/threads-shared/t/hv_refs.t
+@@ -27,7 +27,7 @@ sub ok {
+ 
+ BEGIN {
+     $| = 1;
+-    print("1..20\n");   ### Number of tests that will be run ###
++    print("1..22\n");   ### Number of tests that will be run ###
+ };
+ 
+ use threads;
+@@ -106,6 +106,28 @@ ok(10, keys %foo == 0, "And make sure we realy have deleted the values");
+ ok(19, is_shared($foo), "Check for sharing");
+ ok(20, is_shared(%foo), "Check for sharing");
+ 
++# See av_refs.t for a description.
++
++sub elem_on_stack {
++    my %h :shared;
++    $h{''} = 6;
++    $h{''};
++}
++
++ok(21, defined elem_on_stack(), "element on stack should be defined");
++
++sub lvalue_elem_on_stack :lvalue {
++    my %h :shared;
++    $h{''};
++}
++
++if ($] >= 5.008008) {
++    lvalue_elem_on_stack() = 9;
++    ok(22, 1, "assigning to lvalue element on stack does not crash");
++} else {
++    print "ok 22 # skip $] can't return temporaries from lvalue subs\n";
++}
++
+ exit(0);
+ 
+ # EOF
diff --git a/debian/patches/series b/debian/patches/series
index 2d0696c..bdf49b8 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -78,3 +78,6 @@ fixes/64bitint-signedness-wraparound.diff
 fixes/stdin-sigchld.diff
 fixes/hsplit-rehash.diff
 fixes/encode-memleak.diff
+fixes/threads_shared_elements_crash.diff
+fixes/perlbug-patchlist.diff
+fixes/digest_sha_double_free.diff
diff --git a/dist/threads-shared/shared.xs b/dist/threads-shared/shared.xs
index 7f1cd06..a21606c 100644
--- a/dist/threads-shared/shared.xs
+++ b/dist/threads-shared/shared.xs
@@ -998,6 +998,27 @@ sharedsv_elem_mg_DELETE(pTHX_ SV *sv, MAGIC *mg)
     return (0);
 }
 
+int
+sharedsv_elem_mg_free(pTHX_ SV *sv, MAGIC *mg)
+{
+    dTHXc;
+    PERL_UNUSED_ARG(sv);
+    ENTER_LOCK;
+    if (mg->mg_obj) {
+        if (!PL_dirty) {
+            assert(SvROK(mg->mg_obj));
+        }
+        if (SvREFCNT(mg->mg_obj) == 1) {
+            /* If the element has the last pointer to the shared aggregate, then
+               it has to free the shared aggregate.  mg->mg_obj itself is freed
+               by Perl_mg_free()  */
+            S_sharedsv_dec(aTHX_ S_sharedsv_from_obj(aTHX_ mg->mg_obj));
+        }
+    }
+    LEAVE_LOCK;
+    return (0);
+}
+
 /* Called during cloning of PERL_MAGIC_tiedelem(p) magic in new
  * thread */
 
@@ -1015,7 +1036,7 @@ MGVTBL sharedsv_elem_vtbl = {
     sharedsv_elem_mg_STORE,     /* set */
     0,                          /* len */
     sharedsv_elem_mg_DELETE,    /* clear */
-    0,                          /* free */
+    sharedsv_elem_mg_free,      /* free */
     0,                          /* copy */
     sharedsv_elem_mg_dup,       /* dup */
 #ifdef MGf_LOCAL
@@ -1069,7 +1090,21 @@ int
 sharedsv_array_mg_free(pTHX_ SV *sv, MAGIC *mg)
 {
     PERL_UNUSED_ARG(sv);
-    S_sharedsv_dec(aTHX_ (SV*)mg->mg_ptr);
+    if (!PL_dirty) {
+        assert(mg->mg_obj);
+        assert(SvROK(mg->mg_obj));
+        assert(SvUV(SvRV(mg->mg_obj)) == PTR2UV(mg->mg_ptr));
+    }
+    if (mg->mg_obj) {
+        if (SvREFCNT(mg->mg_obj) == 1) {
+            S_sharedsv_dec(aTHX_ (SV*)mg->mg_ptr);
+        } else {
+            /* An element of this aggregate still has PERL_MAGIC_tied(p)
+               pointing to this shared aggregate.  It will take responsibility
+               for freeing the shared aggregate.  Perl_mg_free() drops the
+               reference count on mg->mg_obj.  */
+        }
+    }
     return (0);
 }
 
diff --git a/dist/threads-shared/t/av_refs.t b/dist/threads-shared/t/av_refs.t
index 8106e32..5243c54 100644
--- a/dist/threads-shared/t/av_refs.t
+++ b/dist/threads-shared/t/av_refs.t
@@ -27,7 +27,7 @@ sub ok {
 
 BEGIN {
     $| = 1;
-    print("1..14\n");   ### Number of tests that will be run ###
+    print("1..16\n");   ### Number of tests that will be run ###
 };
 
 use threads;
@@ -90,6 +90,31 @@ ok(13, is_shared(@av), "Check for sharing");
 my $x :shared;
 ok(14, is_shared($x), "Check for sharing");
 
+# This is a reduction of the test case from perl #119089. Whilst the bug that
+# this exposes was fixed by a core change in 5.15.7, the variant with lvalues
+# below would still crash, and the fix for it also a fix for this bug on earlier
+# perl versions:
+
+sub elem_on_stack {
+    my @a :shared;
+    $a[0] = 6;
+    $a[0];
+}
+
+ok(15, defined elem_on_stack(), "element on stack should be defined");
+
+sub lvalue_elem_on_stack :lvalue {
+    my @a :shared;
+    $a[0];
+}
+
+if ($] >= 5.008008) {
+    lvalue_elem_on_stack() = 9;
+    ok(16, 1, "assigning to lvalue element on stack does not crash");
+} else {
+    print "ok 16 # skip $] can't return temporaries from lvalue subs\n";
+}
+
 exit(0);
 
 # EOF
diff --git a/dist/threads-shared/t/hv_refs.t b/dist/threads-shared/t/hv_refs.t
index ecefdc6..3b9b36b 100644
--- a/dist/threads-shared/t/hv_refs.t
+++ b/dist/threads-shared/t/hv_refs.t
@@ -27,7 +27,7 @@ sub ok {
 
 BEGIN {
     $| = 1;
-    print("1..20\n");   ### Number of tests that will be run ###
+    print("1..22\n");   ### Number of tests that will be run ###
 };
 
 use threads;
@@ -106,6 +106,28 @@ ok(10, keys %foo == 0, "And make sure we realy have deleted the values");
 ok(19, is_shared($foo), "Check for sharing");
 ok(20, is_shared(%foo), "Check for sharing");
 
+# See av_refs.t for a description.
+
+sub elem_on_stack {
+    my %h :shared;
+    $h{''} = 6;
+    $h{''};
+}
+
+ok(21, defined elem_on_stack(), "element on stack should be defined");
+
+sub lvalue_elem_on_stack :lvalue {
+    my %h :shared;
+    $h{''};
+}
+
+if ($] >= 5.008008) {
+    lvalue_elem_on_stack() = 9;
+    ok(22, 1, "assigning to lvalue element on stack does not crash");
+} else {
+    print "ok 22 # skip $] can't return temporaries from lvalue subs\n";
+}
+
 exit(0);
 
 # EOF
diff --git a/utils/perlbug.PL b/utils/perlbug.PL
index 368ce91..8318531 100644
--- a/utils/perlbug.PL
+++ b/utils/perlbug.PL
@@ -22,37 +22,12 @@ $file .= '.com' if $^O eq 'VMS';
 
 open OUT, ">$file" or die "Can't create $file: $!";
 
-# extract patchlevel.h information
+# get patchlevel.h timestamp
 
-open PATCH_LEVEL, "<" . catfile(updir, "patchlevel.h")
-    or die "Can't open patchlevel.h: $!";
+-e catfile(updir, "patchlevel.h")
+    or die "Can't find patchlevel.h: $!";
 
-my $patchlevel_date = (stat PATCH_LEVEL)[9];
-
-while (<PATCH_LEVEL>) {
-    last if $_ =~ /^\s*static\s+(?:const\s+)?char.*?local_patches\[\]\s*=\s*{\s*$/;
-}
-
-if (! defined($_)) {
-    warn "Warning: local_patches section not found in patchlevel.h\n";
-}
-
-my @patches;
-while (<PATCH_LEVEL>) {
-    last if /^\s*}/;
-    next if /^\s*#/;  # preprocessor stuff
-    next if /PERL_GIT_UNPUSHED_COMMITS/;    # XXX expand instead
-    next if /"uncommitted-changes"/;        # XXX determine if active instead
-    chomp;
-    s/^\s+,?\s*"?//;
-    s/"?\s*,?$//;
-    s/(['\\])/\\$1/g;
-    push @patches, $_ unless $_ eq 'NULL';
-}
-my $patch_desc = "'" . join("',\n    '", @patches) . "'";
-my $patch_tags = join "", map /(\S+)/ ? "+$1 " : (), @patches;
-
-close(PATCH_LEVEL) or die "Error closing patchlevel.h: $!";
+my $patchlevel_date = (stat _)[9];
 
 # TO DO (prehaps): store/embed $Config::config_sh into perlbug. When perlbug is
 # used, compare $Config::config_sh with the stored version. If they differ then
@@ -74,15 +49,13 @@ $Config{startperl}
 my \$config_tag1 = '$extract_version - $Config{cf_time}';
 
 my \$patchlevel_date = $patchlevel_date;
-my \$patch_tags = '$patch_tags';
-my \@patches = (
-    $patch_desc
-);
 !GROK!THIS!
 
 # In the following, perl variables are not expanded during extraction.
 
 print OUT <<'!NO!SUBS!';
+my @patches = Config::local_patches();
+my $patch_tags = join "", map /(\S+)/ ? "+$1 " : (), @patches;
 
 use warnings;
 no warnings 'once'; # Eventually, the $::opt_ stuff should get cleaned up
diff --git a/cpan/List-Util/ListUtil.xs b/cpan/List-Util/ListUtil.xs
index 7da9b95..eacdde4 100644
--- a/cpan/List-Util/ListUtil.xs
+++ b/cpan/List-Util/ListUtil.xs
@@ -595,7 +595,7 @@ BOOT:
     varav = GvAVn(vargv);
 #endif
     if (SvTYPE(rmcgv) != SVt_PVGV)
-	gv_init(rmcgv, lu_stash, "List::Util", 12, TRUE);
+	gv_init(rmcgv, lu_stash, "List::Util", 10, TRUE);
     rmcsv = GvSVn(rmcgv);
 #ifndef SvWEAKREF
     av_push(varav, newSVpv("weaken",6));
diff --git a/debian/.git-dpm b/debian/.git-dpm
index 36f1942..514a406 100644
--- a/debian/.git-dpm
+++ b/debian/.git-dpm
@@ -1,6 +1,6 @@
 # see git-dpm(1) from git-dpm package
-504aefc29e21b6cc8e7d81ca83548ccda7ca606d
-504aefc29e21b6cc8e7d81ca83548ccda7ca606d
+30c39051fabf7d1111a2c55f5665c8bea679d19f
+30c39051fabf7d1111a2c55f5665c8bea679d19f
 5f99bf7a09dd2ae3c22081331f4973210a543731
 5f99bf7a09dd2ae3c22081331f4973210a543731
 perl_5.14.2.orig.tar.bz2
diff --git a/debian/changelog b/debian/changelog
index fa9a5b9..604524f 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -5,6 +5,12 @@ perl (5.14.2-21+deb7u1) UNRELEASED; urgency=low
   * Make perlbug.PL look up local patches at runtime (Closes: #710842)
   * Apply patch from upstream fixing Digest::SHA double-free
     crash (Closes: #711206)
+  * Apply correctness patches from 5.14.4:
+    - fixes/pl_eval_start_use_after_free.diff
+    - fixes/regcomp_fix_segv.diff
+    - list_util_off_by_two.diff
+    - sdbm_off_by_one.diff
+    - socket_unpack_sockaddr_un_heap_buffer_overflow.diff
 
  -- Dominic Hargreaves <dom@earth.li>  Mon, 23 Sep 2013 20:40:20 +0100
 
diff --git a/debian/patches/fixes/list_util_off_by_two.diff b/debian/patches/fixes/list_util_off_by_two.diff
new file mode 100644
index 0000000..c853a63
--- /dev/null
+++ b/debian/patches/fixes/list_util_off_by_two.diff
@@ -0,0 +1,27 @@
+From e84d279b900223724e7b81c97ec6b0bab30381a9 Mon Sep 17 00:00:00 2001
+From: David Mitchell <davem@iabyn.com>
+Date: Sun, 24 Feb 2013 15:45:48 +0000
+Subject: fix off-by-two error in List::Util
+
+A string literal is being used that includes two bytes beyond the
+end of the string.
+
+Origin: http://perl5.git.perl.org/perl.git/commit/623a911da450f8f4f1f400cb2c291c7898aecbd1
+Patch-Name: fixes/list_util_off_by_two.diff
+---
+ cpan/List-Util/ListUtil.xs |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/cpan/List-Util/ListUtil.xs b/cpan/List-Util/ListUtil.xs
+index 7da9b95..eacdde4 100644
+--- a/cpan/List-Util/ListUtil.xs
++++ b/cpan/List-Util/ListUtil.xs
+@@ -595,7 +595,7 @@ BOOT:
+     varav = GvAVn(vargv);
+ #endif
+     if (SvTYPE(rmcgv) != SVt_PVGV)
+-	gv_init(rmcgv, lu_stash, "List::Util", 12, TRUE);
++	gv_init(rmcgv, lu_stash, "List::Util", 10, TRUE);
+     rmcsv = GvSVn(rmcgv);
+ #ifndef SvWEAKREF
+     av_push(varav, newSVpv("weaken",6));
diff --git a/debian/patches/fixes/pl_eval_start_use_after_free.diff b/debian/patches/fixes/pl_eval_start_use_after_free.diff
new file mode 100644
index 0000000..6328c09
--- /dev/null
+++ b/debian/patches/fixes/pl_eval_start_use_after_free.diff
@@ -0,0 +1,89 @@
+From c3492954a5e9c5a358dea824be027746f0c817c5 Mon Sep 17 00:00:00 2001
+From: David Mitchell <davem@iabyn.com>
+Date: Fri, 7 Dec 2012 11:07:30 +0000
+Subject: PL_eval_start use-after-free
+
+PL_eval_start is used for two purposes.
+
+First, it indicates the start op of a freshly-compiled eval. It is set in
+newPROG(), and used by entereval etc to know where to begin executing.
+After execution has begun, its value is meaningless (and may well point
+to a freed op).
+
+Second, it's used as a temporary pointer to indicate, within an assignment
+to $] (which has been optimised into a const), that it's not to croak in
+op_lvalue() with "Can't modify constant item", but instead to set
+CopARYBASE.
+
+This second use temporarily sets it in Perl_newASSIGNOP(), which calls
+op_lvalue(), which uses and then clears it. The issue is that it can also
+be left set by a previous eval, so something like 'local $[' will see it
+set and try to use its value.
+
+The quickest fix is to just set it NULL directly after each eval where its
+used.
+
+This change has been applied directly to maint-5.14 rather than going via
+bleed, since the old $[ mechanism was ripped out for 5.15.3.
+
+Bug: https://rt.perl.org/rt3//Ticket/Display.html?id=115992
+Origin: http://perl5.git.perl.org/perl.git/commit/eae139f3f1da0f91ca0fb543c5f5bc3b2b94cbc9
+Patch-Name: fixes/pl_eval_start_use_after_free.diff
+---
+ pp_ctl.c |   14 +++++++++++---
+ 1 file changed, 11 insertions(+), 3 deletions(-)
+
+diff --git a/pp_ctl.c b/pp_ctl.c
+index cbeeeee..615b82e 100644
+--- a/pp_ctl.c
++++ b/pp_ctl.c
+@@ -3088,6 +3088,7 @@ Perl_sv_compile_2op_is_broken(pTHX_ SV *sv, OP **startop, const char *code,
+     CV* runcv = NULL;	/* initialise to avoid compiler warnings */
+     STRLEN len;
+     bool need_catch;
++    OP* ret;
+ 
+     PERL_ARGS_ASSERT_SV_COMPILE_2OP_IS_BROKEN;
+ 
+@@ -3182,7 +3183,9 @@ Perl_sv_compile_2op_is_broken(pTHX_ SV *sv, OP **startop, const char *code,
+     PERL_UNUSED_VAR(newsp);
+     PERL_UNUSED_VAR(optype);
+ 
+-    return PL_eval_start;
++    ret = PL_eval_start;
++    PL_eval_start = NULL;
++    return ret;
+ }
+ 
+ 
+@@ -3903,8 +3906,10 @@ PP(pp_require)
+     encoding = PL_encoding;
+     PL_encoding = NULL;
+ 
+-    if (doeval(gimme, NULL, NULL, PL_curcop->cop_seq))
++    if (doeval(gimme, NULL, NULL, PL_curcop->cop_seq)) {
+ 	op = DOCATCH(PL_eval_start);
++	PL_eval_start = NULL;
++    }
+     else
+ 	op = PL_op->op_next;
+ 
+@@ -4029,6 +4034,7 @@ PP(pp_entereval)
+     PUTBACK;
+ 
+     if (doeval(gimme, NULL, runcv, seq)) {
++	OP *ret;
+ 	if (was != PL_breakable_sub_gen /* Some subs defined here. */
+ 	    ? (PERLDB_LINE || PERLDB_SAVESRC)
+ 	    :  PERLDB_SAVESRC_NOSUBS) {
+@@ -4037,7 +4043,9 @@ PP(pp_entereval)
+ 	    char *const safestr = savepvn(tmpbuf, len);
+ 	    SAVEDELETE(PL_defstash, safestr, len);
+ 	}
+-	return DOCATCH(PL_eval_start);
++	ret = DOCATCH(PL_eval_start);
++	PL_eval_start = NULL;
++	return ret;
+     } else {
+ 	/* We have already left the scope set up earlier thanks to the LEAVE
+ 	   in doeval().  */
diff --git a/debian/patches/fixes/regcomp_fix_segv.diff b/debian/patches/fixes/regcomp_fix_segv.diff
new file mode 100644
index 0000000..b941932
--- /dev/null
+++ b/debian/patches/fixes/regcomp_fix_segv.diff
@@ -0,0 +1,47 @@
+From 356ca08fba8dbd2ef6fbf5e09ac7d438887fbc61 Mon Sep 17 00:00:00 2001
+From: David Mitchell <davem@iabyn.com>
+Date: Tue, 5 Jul 2011 11:35:08 +0100
+Subject: fix segv in regcomp.c:S_join_exact()
+
+[ cherry-picked from bb789b09de07edfb74477eb1603949c96d60927d
+to stop clang's address-sanitizer from complaining. See [perl #115994] ]
+
+This function joins multiple EXACT* nodes into a single node.
+At the end, under DEBUGGING, it marks the optimised-out nodes as being
+type OPTIMIZED. However, some of the 'nodes' aren't actually nodes;
+they're random bits of string at the tail of those nodes. So you
+can't peek that the 'node's OP field to decide what type it was.
+
+Instead, just unconditionally overwrite all the slots with fake
+OPTIMIZED nodes.
+
+Bug: https://rt.perl.org/rt3//Ticket/Display.html?id=115994
+Origin: http://perl5.git.perl.org/perl.git/commit/ebb390a3767eb21f1f35d77eb92061bd48850a9e
+Patch-Name: fixes/regcomp_fix_segv.diff
+---
+ regcomp.c |   10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/regcomp.c b/regcomp.c
+index b186c8d..b30e3bc 100644
+--- a/regcomp.c
++++ b/regcomp.c
+@@ -2647,13 +2647,13 @@ S_join_exact(pTHX_ RExC_state_t *pRExC_state, regnode *scan, I32 *min, U32 flags
+     }
+     
+ #ifdef DEBUGGING
+-    /* Allow dumping */
++    /* Allow dumping but overwriting the collection of skipped
++     * ops and/or strings with fake optimized ops */
+     n = scan + NODE_SZ_STR(scan);
+     while (n <= stop) {
+-        if (PL_regkind[OP(n)] != NOTHING || OP(n) == NOTHING) {
+-            OP(n) = OPTIMIZED;
+-            NEXT_OFF(n) = 0;
+-        }
++	OP(n) = OPTIMIZED;
++	FLAGS(n) = 0;
++	NEXT_OFF(n) = 0;
+         n++;
+     }
+ #endif
diff --git a/debian/patches/fixes/sdbm_off_by_one.diff b/debian/patches/fixes/sdbm_off_by_one.diff
new file mode 100644
index 0000000..7a7ce34
--- /dev/null
+++ b/debian/patches/fixes/sdbm_off_by_one.diff
@@ -0,0 +1,61 @@
+From 2a6361c589c39bc3124e49360b54224d89f41fff Mon Sep 17 00:00:00 2001
+From: Reini Urban <rurban@x-ray.at>
+Date: Fri, 9 Mar 2012 09:11:50 -0600
+Subject: sdbm.c: fix off-by-one access to global ".dir"
+
+Detected by clang -faddress-sanitizer.
+
+The bug came in 081f72ad6fa2b76e0b3cd9046371b2dbd9130114, where
+we started calculating lengths with sizeof on string constants
+instead of using strlen.  Since string constants include the null
+byte, sizeof(".dir"), for example, is 5, but we've been copying 6
+bytes.
+
+This patch resolves [perl #111586] and includes revisions by the
+committer.
+
+Bug: https://rt.perl.org/rt3//Ticket/Display.html?id=111586
+Origin: http://perl5.git.perl.org/perl.git/commit/7f5f08b152bb9d0c88efd1dd0f70d45e427efe1c
+Patch-Name: fixes/sdbm_off_by_one.diff
+---
+ ext/SDBM_File/sdbm/sdbm.c |   14 +++++++-------
+ 1 file changed, 7 insertions(+), 7 deletions(-)
+
+diff --git a/ext/SDBM_File/sdbm/sdbm.c b/ext/SDBM_File/sdbm/sdbm.c
+index c554e52..46be83e 100644
+--- a/ext/SDBM_File/sdbm/sdbm.c
++++ b/ext/SDBM_File/sdbm/sdbm.c
+@@ -78,8 +78,8 @@ sdbm_open(register char *file, register int flags, register int mode)
+ 	register char *dirname;
+ 	register char *pagname;
+ 	size_t filelen;
+-	const size_t dirfext_len = sizeof(DIRFEXT "");
+-	const size_t pagfext_len = sizeof(PAGFEXT "");
++	const size_t dirfext_size = sizeof(DIRFEXT "");
++	const size_t pagfext_size = sizeof(PAGFEXT "");
+ 
+ 	if (file == NULL || !*file)
+ 		return errno = EINVAL, (DBM *) NULL;
+@@ -88,17 +88,17 @@ sdbm_open(register char *file, register int flags, register int mode)
+  */
+ 	filelen = strlen(file);
+ 
+-	if ((dirname = (char *) malloc(filelen + dirfext_len + 1
+-				       + filelen + pagfext_len + 1)) == NULL)
++	if ((dirname = (char *) malloc(filelen + dirfext_size
++				       + filelen + pagfext_size)) == NULL)
+ 		return errno = ENOMEM, (DBM *) NULL;
+ /*
+  * build the file names
+  */
+ 	memcpy(dirname, file, filelen);
+-	memcpy(dirname + filelen, DIRFEXT, dirfext_len + 1);
+-	pagname = dirname + filelen + dirfext_len + 1;
++	memcpy(dirname + filelen, DIRFEXT, dirfext_size);
++	pagname = dirname + filelen + dirfext_size;
+ 	memcpy(pagname, file, filelen);
+-	memcpy(pagname + filelen, PAGFEXT, pagfext_len + 1);
++	memcpy(pagname + filelen, PAGFEXT, pagfext_size);
+ 
+ 	db = sdbm_prep(dirname, pagname, flags, mode);
+ 	free((char *) dirname);
diff --git a/debian/patches/fixes/socket_unpack_sockaddr_un_heap_buffer_overflow.diff b/debian/patches/fixes/socket_unpack_sockaddr_un_heap_buffer_overflow.diff
new file mode 100644
index 0000000..ddd0259
--- /dev/null
+++ b/debian/patches/fixes/socket_unpack_sockaddr_un_heap_buffer_overflow.diff
@@ -0,0 +1,51 @@
+From 30c39051fabf7d1111a2c55f5665c8bea679d19f Mon Sep 17 00:00:00 2001
+From: David Mitchell <davem@iabyn.com>
+Date: Sun, 24 Feb 2013 16:46:19 +0000
+Subject: Socket::unpack_sockaddr_un heap-buffer-overflow
+
+[perl #111594]
+
+A (fairly harmless) read buffer overflow can occur when copying sockaddr
+buffers. Cherry-pick the fix from Socket 2.009 to keep ASAN happy.
+
+Bug: https://rt.perl.org/rt3//Ticket/Display.html?id=111594
+Origin: http://perl5.git.perl.org/perl.git/commit/e5086424505dcbfc5e26aeb984b769ecf5ffed01
+Patch-Name: fixes/socket_unpack_sockaddr_un_heap_buffer_overflow.diff
+---
+ ext/Socket/Socket.xs |   18 +++++++++++-------
+ 1 file changed, 11 insertions(+), 7 deletions(-)
+
+diff --git a/ext/Socket/Socket.xs b/ext/Socket/Socket.xs
+index 9214fc1..e5abb71 100644
+--- a/ext/Socket/Socket.xs
++++ b/ext/Socket/Socket.xs
+@@ -557,18 +557,22 @@ unpack_sockaddr_un(sun_sv)
+ 	STRLEN sockaddrlen;
+ 	char * sun_ad = SvPVbyte(sun_sv,sockaddrlen);
+ 	int addr_len;
+-#   ifndef __linux__
++#   ifdef __linux__
+ 	/* On Linux sockaddrlen on sockets returned by accept, recvfrom,
+ 	   getpeername and getsockname is not equal to sizeof(addr). */
+-	if (sockaddrlen != sizeof(addr)) {
+-	    croak("Bad arg length for %s, length is %d, should be %d",
+-			"Socket::unpack_sockaddr_un",
+-			sockaddrlen, sizeof(addr));
++	if (sockaddrlen < sizeof(addr)) {
++	  Copy(sun_ad, &addr, sockaddrlen, char);
++	  Zero(((char*)&addr) + sockaddrlen, sizeof(addr) - sockaddrlen, char);
++	} else {
++	  Copy(sun_ad, &addr, sizeof(addr), char);
+ 	}
++#   else
++	if (sockaddrlen != sizeof(addr))
++		croak("Bad arg length for %s, length is %"UVuf", should be %"UVuf,
++		      "Socket::unpack_sockaddr_un", (UV)sockaddrlen, (UV)sizeof(addr));
++	Copy(sun_ad, &addr, sizeof(addr), char);
+ #   endif
+ 
+-	Copy( sun_ad, &addr, sizeof addr, char );
+-
+ 	if ( addr.sun_family != AF_UNIX ) {
+ 	    croak("Bad address family for %s, got %d, should be %d",
+ 			"Socket::unpack_sockaddr_un",
diff --git a/debian/patches/series b/debian/patches/series
index bdf49b8..2c15b2e 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -81,3 +81,8 @@ fixes/encode-memleak.diff
 fixes/threads_shared_elements_crash.diff
 fixes/perlbug-patchlist.diff
 fixes/digest_sha_double_free.diff
+fixes/pl_eval_start_use_after_free.diff
+fixes/regcomp_fix_segv.diff
+fixes/list_util_off_by_two.diff
+fixes/sdbm_off_by_one.diff
+fixes/socket_unpack_sockaddr_un_heap_buffer_overflow.diff
diff --git a/ext/SDBM_File/sdbm/sdbm.c b/ext/SDBM_File/sdbm/sdbm.c
index c554e52..46be83e 100644
--- a/ext/SDBM_File/sdbm/sdbm.c
+++ b/ext/SDBM_File/sdbm/sdbm.c
@@ -78,8 +78,8 @@ sdbm_open(register char *file, register int flags, register int mode)
 	register char *dirname;
 	register char *pagname;
 	size_t filelen;
-	const size_t dirfext_len = sizeof(DIRFEXT "");
-	const size_t pagfext_len = sizeof(PAGFEXT "");
+	const size_t dirfext_size = sizeof(DIRFEXT "");
+	const size_t pagfext_size = sizeof(PAGFEXT "");
 
 	if (file == NULL || !*file)
 		return errno = EINVAL, (DBM *) NULL;
@@ -88,17 +88,17 @@ sdbm_open(register char *file, register int flags, register int mode)
  */
 	filelen = strlen(file);
 
-	if ((dirname = (char *) malloc(filelen + dirfext_len + 1
-				       + filelen + pagfext_len + 1)) == NULL)
+	if ((dirname = (char *) malloc(filelen + dirfext_size
+				       + filelen + pagfext_size)) == NULL)
 		return errno = ENOMEM, (DBM *) NULL;
 /*
  * build the file names
  */
 	memcpy(dirname, file, filelen);
-	memcpy(dirname + filelen, DIRFEXT, dirfext_len + 1);
-	pagname = dirname + filelen + dirfext_len + 1;
+	memcpy(dirname + filelen, DIRFEXT, dirfext_size);
+	pagname = dirname + filelen + dirfext_size;
 	memcpy(pagname, file, filelen);
-	memcpy(pagname + filelen, PAGFEXT, pagfext_len + 1);
+	memcpy(pagname + filelen, PAGFEXT, pagfext_size);
 
 	db = sdbm_prep(dirname, pagname, flags, mode);
 	free((char *) dirname);
diff --git a/ext/Socket/Socket.xs b/ext/Socket/Socket.xs
index 9214fc1..e5abb71 100644
--- a/ext/Socket/Socket.xs
+++ b/ext/Socket/Socket.xs
@@ -557,18 +557,22 @@ unpack_sockaddr_un(sun_sv)
 	STRLEN sockaddrlen;
 	char * sun_ad = SvPVbyte(sun_sv,sockaddrlen);
 	int addr_len;
-#   ifndef __linux__
+#   ifdef __linux__
 	/* On Linux sockaddrlen on sockets returned by accept, recvfrom,
 	   getpeername and getsockname is not equal to sizeof(addr). */
-	if (sockaddrlen != sizeof(addr)) {
-	    croak("Bad arg length for %s, length is %d, should be %d",
-			"Socket::unpack_sockaddr_un",
-			sockaddrlen, sizeof(addr));
+	if (sockaddrlen < sizeof(addr)) {
+	  Copy(sun_ad, &addr, sockaddrlen, char);
+	  Zero(((char*)&addr) + sockaddrlen, sizeof(addr) - sockaddrlen, char);
+	} else {
+	  Copy(sun_ad, &addr, sizeof(addr), char);
 	}
+#   else
+	if (sockaddrlen != sizeof(addr))
+		croak("Bad arg length for %s, length is %"UVuf", should be %"UVuf,
+		      "Socket::unpack_sockaddr_un", (UV)sockaddrlen, (UV)sizeof(addr));
+	Copy(sun_ad, &addr, sizeof(addr), char);
 #   endif
 
-	Copy( sun_ad, &addr, sizeof addr, char );
-
 	if ( addr.sun_family != AF_UNIX ) {
 	    croak("Bad address family for %s, got %d, should be %d",
 			"Socket::unpack_sockaddr_un",
diff --git a/pp_ctl.c b/pp_ctl.c
index cbeeeee..615b82e 100644
--- a/pp_ctl.c
+++ b/pp_ctl.c
@@ -3088,6 +3088,7 @@ Perl_sv_compile_2op_is_broken(pTHX_ SV *sv, OP **startop, const char *code,
     CV* runcv = NULL;	/* initialise to avoid compiler warnings */
     STRLEN len;
     bool need_catch;
+    OP* ret;
 
     PERL_ARGS_ASSERT_SV_COMPILE_2OP_IS_BROKEN;
 
@@ -3182,7 +3183,9 @@ Perl_sv_compile_2op_is_broken(pTHX_ SV *sv, OP **startop, const char *code,
     PERL_UNUSED_VAR(newsp);
     PERL_UNUSED_VAR(optype);
 
-    return PL_eval_start;
+    ret = PL_eval_start;
+    PL_eval_start = NULL;
+    return ret;
 }
 
 
@@ -3903,8 +3906,10 @@ PP(pp_require)
     encoding = PL_encoding;
     PL_encoding = NULL;
 
-    if (doeval(gimme, NULL, NULL, PL_curcop->cop_seq))
+    if (doeval(gimme, NULL, NULL, PL_curcop->cop_seq)) {
 	op = DOCATCH(PL_eval_start);
+	PL_eval_start = NULL;
+    }
     else
 	op = PL_op->op_next;
 
@@ -4029,6 +4034,7 @@ PP(pp_entereval)
     PUTBACK;
 
     if (doeval(gimme, NULL, runcv, seq)) {
+	OP *ret;
 	if (was != PL_breakable_sub_gen /* Some subs defined here. */
 	    ? (PERLDB_LINE || PERLDB_SAVESRC)
 	    :  PERLDB_SAVESRC_NOSUBS) {
@@ -4037,7 +4043,9 @@ PP(pp_entereval)
 	    char *const safestr = savepvn(tmpbuf, len);
 	    SAVEDELETE(PL_defstash, safestr, len);
 	}
-	return DOCATCH(PL_eval_start);
+	ret = DOCATCH(PL_eval_start);
+	PL_eval_start = NULL;
+	return ret;
     } else {
 	/* We have already left the scope set up earlier thanks to the LEAVE
 	   in doeval().  */
diff --git a/regcomp.c b/regcomp.c
index b186c8d..b30e3bc 100644
--- a/regcomp.c
+++ b/regcomp.c
@@ -2647,13 +2647,13 @@ S_join_exact(pTHX_ RExC_state_t *pRExC_state, regnode *scan, I32 *min, U32 flags
     }
     
 #ifdef DEBUGGING
-    /* Allow dumping */
+    /* Allow dumping but overwriting the collection of skipped
+     * ops and/or strings with fake optimized ops */
     n = scan + NODE_SZ_STR(scan);
     while (n <= stop) {
-        if (PL_regkind[OP(n)] != NOTHING || OP(n) == NOTHING) {
-            OP(n) = OPTIMIZED;
-            NEXT_OFF(n) = 0;
-        }
+	OP(n) = OPTIMIZED;
+	FLAGS(n) = 0;
+	NEXT_OFF(n) = 0;
         n++;
     }
 #endif

Reply to: