This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
regcomp.c: Guard against corrupting inversion list SV
authorKarl Williamson <khw@cpan.org>
Tue, 23 Feb 2016 21:00:23 +0000 (14:00 -0700)
committerKarl Williamson <khw@cpan.org>
Wed, 24 Feb 2016 06:59:30 +0000 (23:59 -0700)
I don't know of any cases where this happens, but in working on the next
commit I triggered a problem with shrinking an inversion list so much
that the required 0 UV at the beginning was freed.

embed.fnc
proto.h
regcomp.c

index 6063135..00d527a 100644 (file)
--- a/embed.fnc
+++ b/embed.fnc
@@ -1529,7 +1529,7 @@ EiMRn     |bool   |invlist_is_iterating|NN SV* const invlist
 EiMRn  |IV*    |get_invlist_previous_index_addr|NN SV* invlist
 EiMn   |void   |invlist_set_previous_index|NN SV* const invlist|const IV index
 EiMRn  |IV     |invlist_previous_index|NN SV* const invlist
 EiMRn  |IV*    |get_invlist_previous_index_addr|NN SV* invlist
 EiMn   |void   |invlist_set_previous_index|NN SV* const invlist|const IV index
 EiMRn  |IV     |invlist_previous_index|NN SV* const invlist
-EiMn   |void   |invlist_trim   |NN SV* const invlist
+EiMn   |void   |invlist_trim   |NN SV* invlist
 #endif
 EiMR   |SV*    |invlist_clone  |NN SV* const invlist
 EiMRn  |STRLEN*|get_invlist_iter_addr  |NN SV* invlist
 #endif
 EiMR   |SV*    |invlist_clone  |NN SV* const invlist
 EiMRn  |STRLEN*|get_invlist_iter_addr  |NN SV* invlist
diff --git a/proto.h b/proto.h
index f081d9e..ae98567 100644 (file)
--- a/proto.h
+++ b/proto.h
@@ -3667,7 +3667,7 @@ PERL_STATIC_INLINE IV     S_invlist_previous_index(SV* const invlist)
 PERL_STATIC_INLINE void        S_invlist_set_previous_index(SV* const invlist, const IV index);
 #define PERL_ARGS_ASSERT_INVLIST_SET_PREVIOUS_INDEX    \
        assert(invlist)
 PERL_STATIC_INLINE void        S_invlist_set_previous_index(SV* const invlist, const IV index);
 #define PERL_ARGS_ASSERT_INVLIST_SET_PREVIOUS_INDEX    \
        assert(invlist)
-PERL_STATIC_INLINE void        S_invlist_trim(SV* const invlist);
+PERL_STATIC_INLINE void        S_invlist_trim(SV* invlist);
 #define PERL_ARGS_ASSERT_INVLIST_TRIM  \
        assert(invlist)
 #  endif
 #define PERL_ARGS_ASSERT_INVLIST_TRIM  \
        assert(invlist)
 #  endif
index 5725a3a..a9a5077 100644 (file)
--- a/regcomp.c
+++ b/regcomp.c
@@ -8382,15 +8382,18 @@ S_invlist_set_previous_index(SV* const invlist, const IV index)
 }
 
 PERL_STATIC_INLINE void
 }
 
 PERL_STATIC_INLINE void
-S_invlist_trim(SV* const invlist)
+S_invlist_trim(SV* invlist)
 {
     PERL_ARGS_ASSERT_INVLIST_TRIM;
 
     assert(SvTYPE(invlist) == SVt_INVLIST);
 
     /* Change the length of the inversion list to how many entries it currently
 {
     PERL_ARGS_ASSERT_INVLIST_TRIM;
 
     assert(SvTYPE(invlist) == SVt_INVLIST);
 
     /* Change the length of the inversion list to how many entries it currently
-     * has */
-    SvPV_shrink_to_cur((SV *) invlist);
+     * has.  But don't shorten it so that it would free up the required
+     * initial 0 UV (and a trailing NUL byte) */
+    if (SvCUR(invlist) > TO_INTERNAL_SIZE(1) + 1) {
+        SvPV_shrink_to_cur(invlist);
+    }
 }
 
 #endif /* ifndef PERL_IN_XSUB_RE */
 }
 
 #endif /* ifndef PERL_IN_XSUB_RE */