From a6e8418a71b14ef85ee7134be654689b17765f03 Mon Sep 17 00:00:00 2001 From: Simon Marlow Date: Wed, 25 May 2011 10:00:29 +0100 Subject: [PATCH] prog_argv and rts_argv now contain *copies* of the args passed to 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 | 3 - includes/rts/Flags.h | 4 +- rts/RtsFlags.c | 152 +++++++++++++++++++++++++++++++++++--------------- rts/RtsFlags.h | 1 + rts/RtsStartup.c | 5 +- 5 files changed, 112 insertions(+), 53 deletions(-) diff --git a/includes/Rts.h b/includes/Rts.h index 3a6c6f2..91ec76d 100644 --- a/includes/Rts.h +++ b/includes/Rts.h @@ -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; \ diff --git a/includes/rts/Flags.h b/includes/rts/Flags.h index b4e7b64..42ca671 100644 --- a/includes/rts/Flags.h +++ b/includes/rts/Flags.h @@ -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 */ diff --git a/rts/RtsFlags.c b/rts/RtsFlags.c index 1408070..9c0ec9e 100644 --- a/rts/RtsFlags.c +++ b/rts/RtsFlags.c @@ -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(); +} diff --git a/rts/RtsFlags.h b/rts/RtsFlags.h index 3ebfef6..a6bfe0a 100644 --- a/rts/RtsFlags.h +++ b/rts/RtsFlags.h @@ -17,6 +17,7 @@ void initRtsFlagsDefaults (void); void setupRtsFlags (int *argc, char *argv[]); void setProgName (char *argv[]); +void freeRtsArgs (void); #include "EndPrivate.h" diff --git a/rts/RtsStartup.c b/rts/RtsStartup.c index 236d07a..952e806 100644 --- a/rts/RtsStartup.c +++ b/rts/RtsStartup.c @@ -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(): -- 1.7.10.4