Fix a memory allocation bug (rts_argv wasn't big enough)
authorSimon Marlow <marlowsd@gmail.com>
Wed, 14 Dec 2011 10:42:47 +0000 (10:42 +0000)
committerSimon Marlow <marlowsd@gmail.com>
Wed, 14 Dec 2011 10:49:43 +0000 (10:49 +0000)
rts/RtsFlags.c

index 2685d2e..421e81e 100644 (file)
@@ -41,6 +41,7 @@ char  **full_prog_argv = NULL;
 char   *prog_name = NULL; /* 'basename' of prog_argv[0] */
 int     rts_argc = 0;  /* ditto */
 char  **rts_argv = NULL;
+int     rts_argv_size = 0;
 #if defined(mingw32_HOST_OS)
 // On Windows, we want to use GetCommandLineW rather than argc/argv,
 // but we need to mutate the command line arguments for withProgName and
@@ -409,6 +410,19 @@ strequal(const char *a, const char * b)
     return(strcmp(a, b) == 0);
 }
 
+// We can't predict up front how much space we'll need for rts_argv,
+// because it involves parsing ghc_rts_opts and GHCRTS, so we
+// expand it on demand.
+static void appendRtsArg (char *arg)
+{
+    if (rts_argc == rts_argv_size) {
+        rts_argv_size *= 2;
+        rts_argv = stgReallocBytes(rts_argv, rts_argv_size * sizeof (char *),
+                                   "RtsFlags.c:appendRtsArg");
+    }
+    rts_argv[rts_argc++] = arg;
+}
+
 static void splitRtsFlags(const char *s)
 {
     const char *c1, *c2;
@@ -425,7 +439,7 @@ static void splitRtsFlags(const char *s)
         t = stgMallocBytes(c2-c1+1, "RtsFlags.c:splitRtsFlags()");
         strncpy(t, c1, c2-c1);
         t[c2-c1] = '\0';
-        rts_argv[rts_argc++] = t;
+        appendRtsArg(t);
 
        c1 = c2;
     } while (*c1 != '\0');
@@ -463,11 +477,12 @@ void setupRtsFlags (int *argc, char *argv[],
     *argc = 1;
     rts_argc = 0;
 
-    rts_argv = stgCallocBytes(total_arg + 1, sizeof (char *), "setupRtsFlags");
+    rts_argv_size = total_arg + 1;
+    rts_argv = stgMallocBytes(rts_argv_size * sizeof (char *), "setupRtsFlags");
 
     rts_argc0 = rts_argc;
 
-    // process arguments from the ghc_rts_opts global variable first.
+    // process arguments from the -with-rtsopts compile-time flag first
     // (arguments from the GHCRTS environment variable and the command
     // line override these).
     {
@@ -517,7 +532,7 @@ void setupRtsFlags (int *argc, char *argv[],
            mode = PGM;
        }
         else if (mode == RTS) {
-            rts_argv[rts_argc++] = copyArg(argv[arg]);
+            appendRtsArg(copyArg(argv[arg]));
         }
         else {
             argv[(*argc)++] = argv[arg];
@@ -528,10 +543,11 @@ void setupRtsFlags (int *argc, char *argv[],
        argv[(*argc)++] = argv[arg];
     }
     argv[*argc] = (char *) 0;
-    rts_argv[rts_argc] = (char *) 0;
 
     procRtsOpts(rts_argc0, rtsOptsEnabled);
 
+    appendRtsArg((char *)0);
+
     normaliseRtsOpts();
 
     setProgArgv(*argc, argv);
@@ -1798,6 +1814,7 @@ freeRtsArgv(void)
     freeArgv(rts_argc,rts_argv);
     rts_argc = 0;
     rts_argv = NULL;
+    rts_argv_size = 0;
 }
 
 /* ----------------------------------------------------------------------------