Fix for Coverity perl5 CID 29034: Out-of-bounds read (OVERRUN) overrun-local: Overrun...
authorJarkko Hietaniemi <jhi@iki.fi>
Tue, 22 Apr 2014 01:43:12 +0000 (21:43 -0400)
committerTony Cook <tony@develop-help.com>
Tue, 29 Apr 2014 23:58:53 +0000 (09:58 +1000)
Needed compile-time limits for the PL_reg_intflags_name so that the
bit loop doesn't waltz off past the array.  Could not use C_ARRAY_LENGTH
because the size of name array is not visible during compile time
(only const char*[] is), so modified regcomp.pl to generate the size,
made it visible only under DEBUGGING.  Did extflags analogously
even though its size currently exactly 32 already.  The sizeof(flags)*8
is extra paranoia for ILP64.

regcomp.c
regen/regcomp.pl
regnodes.h

index 0238af9..920f7cb 100644 (file)
--- a/regcomp.c
+++ b/regcomp.c
@@ -15365,7 +15365,9 @@ S_regdump_intflags(pTHX_ const char *lead, const U32 flags)
     int bit;
     int set=0;
 
-    for (bit=0; bit<32; bit++) {
+    ASSUME(REG_INTFLAGS_NAME_SIZE <= sizeof(flags)*8);
+
+    for (bit=0; bit<REG_INTFLAGS_NAME_SIZE; bit++) {
         if (flags & (1<<bit)) {
             if (!set++ && lead)
                 PerlIO_printf(Perl_debug_log, "%s",lead);
@@ -15387,7 +15389,9 @@ S_regdump_extflags(pTHX_ const char *lead, const U32 flags)
     int set=0;
     regex_charset cs;
 
-    for (bit=0; bit<32; bit++) {
+    ASSUME(REG_EXTFLAGS_NAME_SIZE <= sizeof(flags)*8);
+
+    for (bit=0; bit<REG_EXTFLAGS_NAME_SIZE; bit++) {
         if (flags & (1<<bit)) {
            if ((1<<bit) & RXf_PMf_CHARSET) {   /* Output separately, below */
                continue;
index 4a8b9d5..2b6d964 100644 (file)
@@ -261,6 +261,7 @@ my %rxfv;
 my %definitions;    # Remember what the symbol definitions are
 my $val = 0;
 my %reverse;
+my $REG_EXTFLAGS_NAME_SIZE = 0;
 foreach my $file ("op_reg_common.h", "regexp.h") {
     open FH,"<$file" or die "Can't read $file: $!";
     while (<FH>) {
@@ -332,6 +333,7 @@ for (0..31) {
     s/\bRXf_(PMf_)?// for $n, $extra;
     printf $out qq(\t%-20s/* 0x%08x%s */\n),
         qq("$n",),$power_of_2, $extra;
+    $REG_EXTFLAGS_NAME_SIZE++;
 }  
  
 print $out <<EOP;
@@ -339,6 +341,12 @@ print $out <<EOP;
 #endif /* DOINIT */
 
 EOP
+print $out <<EOQ
+#ifdef DEBUGGING
+#  define REG_EXTFLAGS_NAME_SIZE $REG_EXTFLAGS_NAME_SIZE
+#endif
+
+EOQ
 }
 {
 print $out <<EOP;
@@ -354,6 +362,7 @@ my %rxfv;
 my %definitions;    # Remember what the symbol definitions are
 my $val = 0;
 my %reverse;
+my $REG_INTFLAGS_NAME_SIZE = 0;
 foreach my $file ("regcomp.h") {
     open my $fh, "<", $file or die "Can't read $file: $!";
     while (<$fh>) {
@@ -369,6 +378,7 @@ foreach my $file ("regcomp.h") {
             $comment= $comment ? " - $comment" : "";
 
             printf $out qq(\t%-30s/* 0x%08x - %s%s */\n), qq("$abbr",), $val, $define, $comment;
+            $REG_INTFLAGS_NAME_SIZE++;
         }
     }
 }
@@ -378,8 +388,13 @@ print $out <<EOP;
 #endif /* DOINIT */
 
 EOP
-}
+print $out <<EOQ;
+#ifdef DEBUGGING
+#  define REG_INTFLAGS_NAME_SIZE $REG_INTFLAGS_NAME_SIZE
+#endif
 
+EOQ
+}
 
 print $out process_flags('V', 'varies', <<'EOC');
 /* The following have no fixed length. U8 so we can do strchr() on it. */
index 4f4ff9e..43ec681 100644 (file)
@@ -676,6 +676,10 @@ EXTCONST char * const PL_reg_extflags_name[] = {
 };
 #endif /* DOINIT */
 
+#ifdef DEBUGGING
+#  define REG_EXTFLAGS_NAME_SIZE 32
+#endif
+
 /* PL_reg_intflags_name[] - Opcode/state names in string form, for debugging */
 
 #ifndef DOINIT
@@ -699,6 +703,10 @@ EXTCONST char * const PL_reg_intflags_name[] = {
 };
 #endif /* DOINIT */
 
+#ifdef DEBUGGING
+#  define REG_INTFLAGS_NAME_SIZE 14
+#endif
+
 /* The following have no fixed length. U8 so we can do strchr() on it. */
 #define REGNODE_VARIES(node) (PL_varies_bitmask[(node) >> 3] & (1 << ((node) & 7)))