prog_argv and rts_argv now contain *copies* of the args passed to
authorSimon Marlow <marlowsd@gmail.com>
Wed, 25 May 2011 09:00:29 +0000 (10:00 +0100)
committerSimon Marlow <marlowsd@gmail.com>
Wed, 25 May 2011 12:09:47 +0000 (13:09 +0100)
setupRtsFlags(), rather than sharing the memory.  Previously if the
caller of hs_init() passed in dynamically-allocated memory and then
freed it, random crashes could happen later (#5177).

includes/Rts.h
includes/rts/Flags.h
rts/RtsFlags.c
rts/RtsFlags.h
rts/RtsStartup.c

index 3a6c6f2..91ec76d 100644 (file)
@@ -248,9 +248,6 @@ int stg_sig_install (int, int, void *);
    Miscellaneous garbage
    -------------------------------------------------------------------------- */
 
-/* declarations for runtime flags/values */
-#define MAX_RTS_ARGS 32
-
 #ifdef DEBUG
 #define TICK_VAR(arity) \
   extern StgInt SLOW_CALLS_##arity; \
index b4e7b64..42ca671 100644 (file)
@@ -244,7 +244,7 @@ extern RTS_FLAGS RtsFlags;
 extern int     prog_argc;
 extern char  **prog_argv;
 */
-extern int     rts_argc;  /* ditto */
-extern char   *rts_argv[];
+extern int      rts_argc;  /* ditto */
+extern char   **rts_argv;
 
 #endif /* RTS_FLAGS_H */
index 1408070..9c0ec9e 100644 (file)
@@ -33,7 +33,7 @@ int     full_prog_argc = 0;    /* an "int" so as to match normal "argc" */
 char  **full_prog_argv = NULL;
 char   *prog_name = NULL; /* 'basename' of prog_argv[0] */
 int     rts_argc = 0;  /* ditto */
-char   *rts_argv[MAX_RTS_ARGS];
+char  **rts_argv = NULL;
 #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
@@ -73,6 +73,10 @@ static void read_trace_flags(char *arg);
 
 static void errorUsage      (void) GNU_ATTRIBUTE(__noreturn__);
 
+static char *  copyArg  (char *arg);
+static char ** copyArgv (int argc, char *argv[]);
+static void    freeArgv (int argc, char *argv[]);
+
 /* -----------------------------------------------------------------------------
  * Command-line option parsing routines.
  * ---------------------------------------------------------------------------*/
@@ -387,15 +391,11 @@ static void splitRtsFlags(char *s)
        
        if (c1 == c2) { break; }
        
-        if (rts_argc < MAX_RTS_ARGS-1) {
-           s = stgMallocBytes(c2-c1+1, "RtsFlags.c:splitRtsFlags()");
-           strncpy(s, c1, c2-c1);
-           s[c2-c1] = '\0';
-            rts_argv[rts_argc++] = s;
-       } else {
-           barf("too many RTS arguments (max %d)", MAX_RTS_ARGS-1);
-       }
-       
+        s = stgMallocBytes(c2-c1+1, "RtsFlags.c:splitRtsFlags()");
+        strncpy(s, c1, c2-c1);
+        s[c2-c1] = '\0';
+        rts_argv[rts_argc++] = s;
+
        c1 = c2;
     } while (*c1 != '\0');
 }
@@ -407,13 +407,13 @@ static void splitRtsFlags(char *s)
      - argv[] is *modified*, any RTS options have been stripped out
      - *argc  contains the new count of arguments in argv[]
 
-     - rts_argv[]  (global) contains the collected RTS args
+     - rts_argv[]  (global) contains a copy of the collected RTS args
      - rts_argc    (global) contains the count of args in rts_argv
 
-     - prog_argv[] (global) contains the non-RTS args (== argv)
+     - prog_argv[] (global) contains a copy of the non-RTS args (== argv)
      - prog_argc   (global) contains the count of args in prog_argv
 
-     - prog_name   (global) contains the basename of argv[0]
+     - prog_name   (global) contains the basename of prog_argv[0]
 
   -------------------------------------------------------------------------- */
 
@@ -430,6 +430,8 @@ void setupRtsFlags (int *argc, char *argv[])
     *argc = 1;
     rts_argc = 0;
 
+    rts_argv = stgCallocBytes(total_arg + 1, sizeof (char *), "setupRtsFlags");
+
     rts_argc0 = rts_argc;
 
     // process arguments from the ghc_rts_opts global variable first.
@@ -481,14 +483,11 @@ void setupRtsFlags (int *argc, char *argv[])
        else if (strequal("-RTS", argv[arg])) {
            mode = PGM;
        }
-        else if (mode == RTS && rts_argc < MAX_RTS_ARGS-1) {
-            rts_argv[rts_argc++] = argv[arg];
+        else if (mode == RTS) {
+            rts_argv[rts_argc++] = copyArg(argv[arg]);
         }
-        else if (mode == PGM) {
-           argv[(*argc)++] = argv[arg];
-       }
-       else {
-         barf("too many RTS arguments (max %d)", MAX_RTS_ARGS-1);
+        else {
+            argv[(*argc)++] = argv[arg];
        }
     }
     // process remaining program arguments
@@ -1459,6 +1458,41 @@ bad_option(const char *s)
   stg_exit(EXIT_FAILURE);
 }
 
+/* ----------------------------------------------------------------------------
+   Copying and freeing argc/argv
+   ------------------------------------------------------------------------- */
+
+static char * copyArg(char *arg)
+{
+    char *new_arg = stgMallocBytes(strlen(arg) + 1, "copyArg");
+    strcpy(new_arg, arg);
+    return new_arg;
+}
+
+static char ** copyArgv(int argc, char *argv[])
+{
+    int i;
+    char **new_argv;
+
+    new_argv = stgCallocBytes(argc + 1, sizeof (char *), "copyArgv 1");
+    for (i = 0; i < argc; i++) {
+        new_argv[i] = copyArg(argv[i]);
+    }
+    new_argv[argc] = NULL;
+    return new_argv;
+}
+
+static void freeArgv(int argc, char *argv[])
+{
+    int i;
+    if (argv != NULL) {
+        for (i = 0; i < argc; i++) {
+            stgFree(argv[i]);
+        }
+        stgFree(argv);
+    }
+}
+
 /* -----------------------------------------------------------------------------
    Getting/Setting the program's arguments.
 
@@ -1500,10 +1534,29 @@ void
 setProgArgv(int argc, char *argv[])
 {
     prog_argc = argc;
-    prog_argv = argv;
+    prog_argv = copyArgv(argc,argv);
     setProgName(prog_argv);
 }
 
+static void
+freeProgArgv(void)
+{
+    freeArgv(prog_argc,prog_argv);
+    prog_argc = 0;
+    prog_argv = NULL;
+}
+
+/* ----------------------------------------------------------------------------
+   The full argv - a copy of the original program's argc/argv
+   ------------------------------------------------------------------------- */
+
+void
+setFullProgArgv(int argc, char *argv[])
+{
+    full_prog_argc = argc;
+    full_prog_argv = copyArgv(argc,argv);
+}
+
 /* These functions record and recall the full arguments, including the
    +RTS ... -RTS options. The reason for adding them was so that the
    ghc-inplace program can pass /all/ the arguments on to the real ghc. */
@@ -1515,42 +1568,25 @@ getFullProgArgv(int *argc, char **argv[])
 }
 
 void
-setFullProgArgv(int argc, char *argv[])
-{
-    int i;
-    full_prog_argc = argc;
-    full_prog_argv = stgCallocBytes(argc + 1, sizeof (char *),
-                                    "setFullProgArgv 1");
-    for (i = 0; i < argc; i++) {
-        full_prog_argv[i] = stgMallocBytes(strlen(argv[i]) + 1,
-                                           "setFullProgArgv 2");
-        strcpy(full_prog_argv[i], argv[i]);
-    }
-    full_prog_argv[argc] = NULL;
-}
-
-void
 freeFullProgArgv (void)
 {
-    int i;
-
-    if (full_prog_argv != NULL) {
-        for (i = 0; i < full_prog_argc; i++) {
-            stgFree(full_prog_argv[i]);
-        }
-        stgFree(full_prog_argv);
-    }
-
+    freeArgv(full_prog_argc, full_prog_argv);
     full_prog_argc = 0;
     full_prog_argv = NULL;
 }
 
+/* ----------------------------------------------------------------------------
+   The Win32 argv
+   ------------------------------------------------------------------------- */
+
 #if defined(mingw32_HOST_OS)
 void freeWin32ProgArgv (void);
 
 void
 freeWin32ProgArgv (void)
 {
+    freeArgv(win32_prog_argc, win32_prog_argv);
+
     int i;
 
     if (win32_prog_argv != NULL) {
@@ -1594,3 +1630,29 @@ setWin32ProgArgv(int argc, wchar_t *argv[])
     win32_prog_argv[argc] = NULL;
 }
 #endif
+
+/* ----------------------------------------------------------------------------
+   The RTS argv
+   ------------------------------------------------------------------------- */
+
+static void
+freeRtsArgv(void)
+{
+    freeArgv(rts_argc,rts_argv);
+    rts_argc = 0;
+    rts_argv = NULL;
+}
+
+/* ----------------------------------------------------------------------------
+   All argvs
+   ------------------------------------------------------------------------- */
+
+void freeRtsArgs(void)
+{
+#if defined(mingw32_HOST_OS)
+    freeWin32ProgArgv();
+#endif
+    freeFullProgArgv();
+    freeProgArgv();
+    freeRtsArgv();
+}
index 3ebfef6..a6bfe0a 100644 (file)
@@ -17,6 +17,7 @@
 void initRtsFlagsDefaults (void);
 void setupRtsFlags        (int *argc, char *argv[]);
 void setProgName          (char *argv[]);
+void freeRtsArgs          (void);
 
 #include "EndPrivate.h"
 
index 236d07a..952e806 100644 (file)
@@ -297,9 +297,6 @@ hs_exit_(rtsBool wait_foreign)
     checkFPUStack();
 #endif
 
-    // Free the full argv storage
-    freeFullProgArgv();
-
 #if defined(THREADED_RTS)
     ioManagerDie();
 #endif
@@ -402,6 +399,8 @@ hs_exit_(rtsBool wait_foreign)
     // heap memory (e.g. by being passed a ByteArray#).
     freeStorage(wait_foreign);
 
+    // Free the various argvs
+    freeRtsArgs();
 }
 
 // The real hs_exit():