don't segfault given string repeat count larger than 2^31
authorJim Meyering <jim@meyering.net>
Sun, 23 Oct 2011 23:04:11 +0000 (16:04 -0700)
committerFather Chrysostomos <sprout@cpan.org>
Sun, 23 Oct 2011 23:47:53 +0000 (16:47 -0700)
E.g., this overflows INT_MAX and overruns heap memory:

    $ perl -le 'print "v"x(2**31+1)'
    [Exit 139 (SEGV)]

(Perl_repeatcpy): Use the same type for "count" as our sole
callers in pp.c: IV (long), not I32 (int).  Otherwise, passing
the wider value to a narrower "I32 count"

embed.fnc
proto.h
util.c

index 43ad88b..3a47a30 100644 (file)
--- a/embed.fnc
+++ b/embed.fnc
@@ -1066,7 +1066,7 @@ EXp       |SV*|reg_qr_package|NN REGEXP * const rx
 
 : FIXME - why the E?
 Ep     |void   |regprop        |NULLOK const regexp *prog|NN SV* sv|NN const regnode* o
-Anp    |void   |repeatcpy      |NN char* to|NN const char* from|I32 len|I32 count
+Anp    |void   |repeatcpy      |NN char* to|NN const char* from|I32 len|IV count
 AnpP   |char*  |rninstr        |NN const char* big|NN const char* bigend \
                                |NN const char* little|NN const char* lend
 Ap     |Sighandler_t|rsignal   |int i|Sighandler_t t
diff --git a/proto.h b/proto.h
index 0eb5e7c..a70802b 100644 (file)
--- a/proto.h
+++ b/proto.h
@@ -3244,7 +3244,7 @@ PERL_CALLCONV void        Perl_regprop(pTHX_ const regexp *prog, SV* sv, const regnode*
 #define PERL_ARGS_ASSERT_REGPROP       \
        assert(sv); assert(o)
 
-PERL_CALLCONV void     Perl_repeatcpy(char* to, const char* from, I32 len, I32 count)
+PERL_CALLCONV void     Perl_repeatcpy(char* to, const char* from, I32 len, IV count)
                        __attribute__nonnull__(1)
                        __attribute__nonnull__(2);
 #define PERL_ARGS_ASSERT_REPEATCPY     \
diff --git a/util.c b/util.c
index 1df5453..164d971 100644 (file)
--- a/util.c
+++ b/util.c
@@ -3404,7 +3404,7 @@ Perl_my_pclose(pTHX_ PerlIO *ptr)
 
 #define PERL_REPEATCPY_LINEAR 4
 void
-Perl_repeatcpy(register char *to, register const char *from, I32 len, register I32 count)
+Perl_repeatcpy(register char *to, register const char *from, I32 len, register IV count)
 {
     PERL_ARGS_ASSERT_REPEATCPY;
 
@@ -3412,19 +3412,19 @@ Perl_repeatcpy(register char *to, register const char *from, I32 len, register I
        memset(to, *from, count);
     else if (count) {
        register char *p = to;
-       I32 items, linear, half;
+       IV items, linear, half;
 
        linear = count < PERL_REPEATCPY_LINEAR ? count : PERL_REPEATCPY_LINEAR;
        for (items = 0; items < linear; ++items) {
            register const char *q = from;
-           I32 todo;
+           IV todo;
            for (todo = len; todo > 0; todo--)
                *p++ = *q++;
         }
 
        half = count / 2;
        while (items <= half) {
-           I32 size = items * len;
+           IV size = items * len;
            memcpy(p, to, size);
            p     += size;
            items *= 2;