rts: Replace `nat` with `uint32_t`
[ghc.git] / rts / RtsFlags.c
1 /* -----------------------------------------------------------------------------
2 *
3 * (c) The AQUA Project, Glasgow University, 1994-1997
4 * (c) The GHC Team, 1998-2006
5 *
6 * Functions for parsing the argument list.
7 *
8 * ---------------------------------------------------------------------------*/
9
10 #include "PosixSource.h"
11 #include "Rts.h"
12
13 #include "RtsUtils.h"
14 #include "Profiling.h"
15 #include "RtsFlags.h"
16 #include "sm/OSMem.h"
17 #include "hooks/Hooks.h"
18
19 #ifdef HAVE_CTYPE_H
20 #include <ctype.h>
21 #endif
22
23 #include <string.h>
24
25 #ifdef HAVE_UNISTD_H
26 #include <unistd.h>
27 #endif
28
29 #ifdef HAVE_SYS_TYPES_H
30 #include <sys/types.h>
31 #endif
32
33 // Flag Structure
34 RTS_FLAGS RtsFlags;
35
36 /*
37 * Split argument lists
38 */
39 int prog_argc = 0; /* an "int" so as to match normal "argc" */
40 char **prog_argv = NULL;
41 int full_prog_argc = 0; /* an "int" so as to match normal "argc" */
42 char **full_prog_argv = NULL;
43 char *prog_name = NULL; /* 'basename' of prog_argv[0] */
44 int rts_argc = 0; /* ditto */
45 char **rts_argv = NULL;
46 int rts_argv_size = 0;
47 #if defined(mingw32_HOST_OS)
48 // On Windows, we want to use GetCommandLineW rather than argc/argv,
49 // but we need to mutate the command line arguments for withProgName and
50 // friends. The System.Environment module achieves that using this bit of
51 // shared state:
52 int win32_prog_argc = 0;
53 wchar_t **win32_prog_argv = NULL;
54 #endif
55
56 // The global rtsConfig, set from the RtsConfig supplied by the call
57 // to hs_init_ghc().
58 RtsConfig rtsConfig;
59
60 const RtsConfig defaultRtsConfig = {
61 .rts_opts_enabled = RtsOptsSafeOnly,
62 .rts_opts_suggestions = rtsTrue,
63 .rts_opts = NULL,
64 .rts_hs_main = rtsFalse,
65 .keep_cafs = rtsFalse,
66 .defaultsHook = FlagDefaultsHook,
67 .onExitHook = OnExitHook,
68 .stackOverflowHook = StackOverflowHook,
69 .outOfHeapHook = OutOfHeapHook,
70 .mallocFailHook = MallocFailHook,
71 .gcDoneHook = NULL
72 };
73
74 /*
75 * constants, used later
76 */
77 #define RTS 1
78 #define PGM 0
79
80 /* -----------------------------------------------------------------------------
81 Static function decls
82 -------------------------------------------------------------------------- */
83
84 static void procRtsOpts (int rts_argc0, RtsOptsEnabledEnum enabled);
85
86 static void normaliseRtsOpts (void);
87
88 static void initStatsFile (FILE *f);
89
90 static int openStatsFile (
91 char *filename, const char *FILENAME_FMT, FILE **file_ret);
92
93 static StgWord64 decodeSize (
94 const char *flag, uint32_t offset, StgWord64 min, StgWord64 max);
95
96 static void bad_option (const char *s);
97
98 #ifdef DEBUG
99 static void read_debug_flags(const char *arg);
100 #endif
101
102 #ifdef PROFILING
103 static rtsBool read_heap_profiling_flag(const char *arg);
104 #endif
105
106 #ifdef TRACING
107 static void read_trace_flags(const char *arg);
108 #endif
109
110 static void errorUsage (void) GNU_ATTRIBUTE(__noreturn__);
111
112 static char * copyArg (char *arg);
113 static char ** copyArgv (int argc, char *argv[]);
114 static void freeArgv (int argc, char *argv[]);
115 static void setProgName (char *argv[]);
116
117 static void errorRtsOptsDisabled (const char *s);
118
119 /* -----------------------------------------------------------------------------
120 * Command-line option parsing routines.
121 * ---------------------------------------------------------------------------*/
122
123 void initRtsFlagsDefaults(void)
124 {
125 StgWord64 maxStkSize = 8 * getPhysicalMemorySize() / 10;
126 // if getPhysicalMemorySize fails just move along with an 8MB limit
127 if (maxStkSize == 0)
128 maxStkSize = 8 * 1024 * 1024;
129
130 RtsFlags.GcFlags.statsFile = NULL;
131 RtsFlags.GcFlags.giveStats = NO_GC_STATS;
132
133 RtsFlags.GcFlags.maxStkSize = maxStkSize / sizeof(W_);
134 RtsFlags.GcFlags.initialStkSize = 1024 / sizeof(W_);
135 RtsFlags.GcFlags.stkChunkSize = (32 * 1024) / sizeof(W_);
136 RtsFlags.GcFlags.stkChunkBufferSize = (1 * 1024) / sizeof(W_);
137
138 RtsFlags.GcFlags.minAllocAreaSize = (512 * 1024) / BLOCK_SIZE;
139 RtsFlags.GcFlags.largeAllocLim = 0; /* defaults to minAllocAreasize */
140 RtsFlags.GcFlags.nurseryChunkSize = 0;
141 RtsFlags.GcFlags.minOldGenSize = (1024 * 1024) / BLOCK_SIZE;
142 RtsFlags.GcFlags.maxHeapSize = 0; /* off by default */
143 RtsFlags.GcFlags.heapSizeSuggestion = 0; /* none */
144 RtsFlags.GcFlags.heapSizeSuggestionAuto = rtsFalse;
145 RtsFlags.GcFlags.pcFreeHeap = 3; /* 3% */
146 RtsFlags.GcFlags.oldGenFactor = 2;
147 RtsFlags.GcFlags.generations = 2;
148 RtsFlags.GcFlags.squeezeUpdFrames = rtsTrue;
149 RtsFlags.GcFlags.compact = rtsFalse;
150 RtsFlags.GcFlags.compactThreshold = 30.0;
151 RtsFlags.GcFlags.sweep = rtsFalse;
152 RtsFlags.GcFlags.idleGCDelayTime = USToTime(300000); // 300ms
153 #ifdef THREADED_RTS
154 RtsFlags.GcFlags.doIdleGC = rtsTrue;
155 #else
156 RtsFlags.GcFlags.doIdleGC = rtsFalse;
157 #endif
158 RtsFlags.GcFlags.heapBase = 0; /* means don't care */
159 RtsFlags.GcFlags.allocLimitGrace = (100*1024) / BLOCK_SIZE;
160
161 #ifdef DEBUG
162 RtsFlags.DebugFlags.scheduler = rtsFalse;
163 RtsFlags.DebugFlags.interpreter = rtsFalse;
164 RtsFlags.DebugFlags.weak = rtsFalse;
165 RtsFlags.DebugFlags.gccafs = rtsFalse;
166 RtsFlags.DebugFlags.gc = rtsFalse;
167 RtsFlags.DebugFlags.block_alloc = rtsFalse;
168 RtsFlags.DebugFlags.sanity = rtsFalse;
169 RtsFlags.DebugFlags.stable = rtsFalse;
170 RtsFlags.DebugFlags.stm = rtsFalse;
171 RtsFlags.DebugFlags.prof = rtsFalse;
172 RtsFlags.DebugFlags.apply = rtsFalse;
173 RtsFlags.DebugFlags.linker = rtsFalse;
174 RtsFlags.DebugFlags.squeeze = rtsFalse;
175 RtsFlags.DebugFlags.hpc = rtsFalse;
176 RtsFlags.DebugFlags.sparks = rtsFalse;
177 #endif
178
179 #if defined(PROFILING)
180 RtsFlags.CcFlags.doCostCentres = 0;
181 #endif /* PROFILING */
182
183 RtsFlags.ProfFlags.doHeapProfile = rtsFalse;
184 RtsFlags.ProfFlags. heapProfileInterval = USToTime(100000); // 100ms
185
186 #ifdef PROFILING
187 RtsFlags.ProfFlags.includeTSOs = rtsFalse;
188 RtsFlags.ProfFlags.showCCSOnException = rtsFalse;
189 RtsFlags.ProfFlags.maxRetainerSetSize = 8;
190 RtsFlags.ProfFlags.ccsLength = 25;
191 RtsFlags.ProfFlags.modSelector = NULL;
192 RtsFlags.ProfFlags.descrSelector = NULL;
193 RtsFlags.ProfFlags.typeSelector = NULL;
194 RtsFlags.ProfFlags.ccSelector = NULL;
195 RtsFlags.ProfFlags.ccsSelector = NULL;
196 RtsFlags.ProfFlags.retainerSelector = NULL;
197 RtsFlags.ProfFlags.bioSelector = NULL;
198 #endif
199
200 #ifdef TRACING
201 RtsFlags.TraceFlags.tracing = TRACE_NONE;
202 RtsFlags.TraceFlags.timestamp = rtsFalse;
203 RtsFlags.TraceFlags.scheduler = rtsFalse;
204 RtsFlags.TraceFlags.gc = rtsFalse;
205 RtsFlags.TraceFlags.sparks_sampled= rtsFalse;
206 RtsFlags.TraceFlags.sparks_full = rtsFalse;
207 RtsFlags.TraceFlags.user = rtsFalse;
208 #endif
209
210 #ifdef PROFILING
211 // When profiling we want a lot more ticks
212 RtsFlags.MiscFlags.tickInterval = USToTime(1000); // 1ms
213 #else
214 RtsFlags.MiscFlags.tickInterval = DEFAULT_TICK_INTERVAL;
215 #endif
216 RtsFlags.ConcFlags.ctxtSwitchTime = USToTime(20000); // 20ms
217
218 RtsFlags.MiscFlags.install_signal_handlers = rtsTrue;
219 RtsFlags.MiscFlags.machineReadable = rtsFalse;
220 RtsFlags.MiscFlags.linkerMemBase = 0;
221
222 #ifdef THREADED_RTS
223 RtsFlags.ParFlags.nNodes = 1;
224 RtsFlags.ParFlags.migrate = rtsTrue;
225 RtsFlags.ParFlags.parGcEnabled = 1;
226 RtsFlags.ParFlags.parGcGen = 0;
227 RtsFlags.ParFlags.parGcLoadBalancingEnabled = rtsTrue;
228 RtsFlags.ParFlags.parGcLoadBalancingGen = 1;
229 RtsFlags.ParFlags.parGcNoSyncWithIdle = 0;
230 RtsFlags.ParFlags.parGcThreads = 0; /* defaults to -N */
231 RtsFlags.ParFlags.setAffinity = 0;
232 #endif
233
234 #if defined(THREADED_RTS)
235 RtsFlags.ParFlags.maxLocalSparks = 4096;
236 #endif /* THREADED_RTS */
237
238 #ifdef TICKY_TICKY
239 RtsFlags.TickyFlags.showTickyStats = rtsFalse;
240 RtsFlags.TickyFlags.tickyFile = NULL;
241 #endif
242 }
243
244 static const char *
245 usage_text[] = {
246 "",
247 "Usage: <prog> <args> [+RTS <rtsopts> | -RTS <args>] ... --RTS <args>",
248 "",
249 " +RTS Indicates run time system options follow",
250 " -RTS Indicates program arguments follow",
251 " --RTS Indicates that ALL subsequent arguments will be given to the",
252 " program (including any of these RTS flags)",
253 "",
254 "The following run time system options are available:",
255 "",
256 " -? Prints this message and exits; the program is not executed",
257 " --info Print information about the RTS used by this program",
258 "",
259 " -K<size> Sets the maximum stack size (default: 80% of the heap)",
260 " Egs: -K32k -K512k -K8M",
261 " -ki<size> Sets the initial thread stack size (default 1k) Egs: -ki4k -ki2m",
262 " -kc<size> Sets the stack chunk size (default 32k)",
263 " -kb<size> Sets the stack chunk buffer size (default 1k)",
264 "",
265 " -A<size> Sets the minimum allocation area size (default 512k) Egs: -A1m -A10k",
266 " -AL<size> Sets the amount of large-object memory that can be allocated",
267 " before a GC is triggered (default: the value of -A)",
268 " -n<size> Allocation area chunk size (0 = disabled, default: 0)",
269 " -O<size> Sets the minimum size of the old generation (default 1M)",
270 " -M<size> Sets the maximum heap size (default unlimited) Egs: -M256k -M1G",
271 " -H<size> Sets the minimum heap size (default 0M) Egs: -H24m -H1G",
272 " -m<n> Minimum % of heap which must be available (default 3%)",
273 " -G<n> Number of generations (default: 2)",
274 " -c<n> Use in-place compaction instead of copying in the oldest generation",
275 " when live data is at least <n>% of the maximum heap size set with",
276 " -M (default: 30%)",
277 " -c Use in-place compaction for all oldest generation collections",
278 " (the default is to use copying)",
279 " -w Use mark-region for the oldest generation (experimental)",
280 #if defined(THREADED_RTS)
281 " -I<sec> Perform full GC after <sec> idle time (default: 0.3, 0 == off)",
282 #endif
283 "",
284 " -T Collect GC statistics (useful for in-program statistics access)",
285 " -t[<file>] One-line GC statistics (if <file> omitted, uses stderr)",
286 " -s[<file>] Summary GC statistics (if <file> omitted, uses stderr)",
287 " -S[<file>] Detailed GC statistics (if <file> omitted, uses stderr)",
288 "",
289 "",
290 " -Z Don't squeeze out update frames on stack overflow",
291 " -B Sound the bell at the start of each garbage collection",
292 #if defined(PROFILING)
293 "",
294 " -p Time/allocation profile (output file <program>.prof)",
295 " -P More detailed Time/Allocation profile",
296 " -Pa Give information about *all* cost centres",
297 "",
298 " -h<break-down> Heap residency profile (hp2ps) (output file <program>.hp)",
299 " break-down: c = cost centre stack (default)",
300 " m = module",
301 " d = closure description",
302 " y = type description",
303 " r = retainer",
304 " b = biography (LAG,DRAG,VOID,USE)",
305 " A subset of closures may be selected thusly:",
306 " -hc<cc>,... specific cost centre(s) (top of stack only)",
307 " -hC<cc>,... specific cost centre(s) (anywhere in stack)",
308 " -hm<mod>... all cost centres from the specified modules(s)",
309 " -hd<des>,... closures with specified closure descriptions",
310 " -hy<typ>... closures with specified type descriptions",
311 " -hr<cc>... closures with specified retainers",
312 " -hb<bio>... closures with specified biographies (lag,drag,void,use)",
313 "",
314 " -R<size> Set the maximum retainer set size (default: 8)",
315 "",
316 " -L<chars> Maximum length of a cost-centre stack in a heap profile",
317 " (default: 25)",
318 "",
319 " -xt Include threads (TSOs) in a heap profile",
320 "",
321 " -xc Show current cost centre stack on raising an exception",
322 #endif /* PROFILING */
323
324 #ifdef TRACING
325 "",
326 " -l[flags] Log events in binary format to the file <program>.eventlog",
327 # ifdef DEBUG
328 " -v[flags] Log events to stderr",
329 # endif
330 " where [flags] can contain:",
331 " s scheduler events",
332 " g GC and heap events",
333 " p par spark events (sampled)",
334 " f par spark events (full detail)",
335 " u user events (emitted from Haskell code)",
336 " a all event classes above",
337 # ifdef DEBUG
338 " t add time stamps (only useful with -v)",
339 # endif
340 " -x disable an event class, for any flag above",
341 " the initial enabled event classes are 'sgpu'",
342 #endif
343
344 #if !defined(PROFILING)
345 "",
346 " -h Heap residency profile (output file <program>.hp)",
347 #endif
348 " -i<sec> Time between heap profile samples (seconds, default: 0.1)",
349 "",
350 #if defined(TICKY_TICKY)
351 " -r<file> Produce ticky-ticky statistics (with -rstderr for stderr)",
352 "",
353 #endif
354 " -C<secs> Context-switch interval in seconds.",
355 " 0 or no argument means switch as often as possible.",
356 " Default: 0.02 sec.",
357 " -V<secs> Master tick interval in seconds (0 == disable timer).",
358 " This sets the resolution for -C and the heap profile timer -i,",
359 " and is the frequence of time profile samples.",
360 #ifdef PROFILING
361 " Default: 0.001 sec.",
362 #else
363 " Default: 0.01 sec.",
364 #endif
365 "",
366 #if defined(DEBUG)
367 " -Ds DEBUG: scheduler",
368 " -Di DEBUG: interpreter",
369 " -Dw DEBUG: weak",
370 " -DG DEBUG: gccafs",
371 " -Dg DEBUG: gc",
372 " -Db DEBUG: block",
373 " -DS DEBUG: sanity",
374 " -Dt DEBUG: stable",
375 " -Dp DEBUG: prof",
376 " -Da DEBUG: apply",
377 " -Dl DEBUG: linker",
378 " -Dm DEBUG: stm",
379 " -Dz DEBUG: stack squeezing",
380 " -Dc DEBUG: program coverage",
381 " -Dr DEBUG: sparks",
382 "",
383 " NOTE: DEBUG events are sent to stderr by default; add -l to create a",
384 " binary event log file instead.",
385 "",
386 #endif /* DEBUG */
387 #if defined(THREADED_RTS) && !defined(NOSMP)
388 " -N[<n>] Use <n> processors (default: 1, -N alone determines",
389 " the number of processors to use automatically)",
390 " -maxN[<n>] Use up to <n> processors automatically",
391 " -qg[<n>] Use parallel GC only for generations >= <n>",
392 " (default: 0, -qg alone turns off parallel GC)",
393 " -qb[<n>] Use load-balancing in the parallel GC only for generations >= <n>",
394 " (default: 1, -qb alone turns off load-balancing)",
395 " -qn<n> Use <n> threads for parallel GC (defaults to value of -N)",
396 " -qa Use the OS to set thread affinity (experimental)",
397 " -qm Don't automatically migrate threads between CPUs",
398 " -qi<n> If a processor has been idle for the last <n> GCs, do not",
399 " wake it up for a non-load-balancing parallel GC.",
400 " (0 disables, default: 0)",
401 #endif
402 " --install-signal-handlers=<yes|no>",
403 " Install signal handlers (default: yes)",
404 #if defined(THREADED_RTS)
405 " -e<n> Maximum number of outstanding local sparks (default: 4096)",
406 #endif
407 #if defined(x86_64_HOST_ARCH)
408 " -xm Base address to mmap memory in the GHCi linker",
409 " (hex; must be <80000000)",
410 #endif
411 " -xq The allocation limit given to a thread after it receives",
412 " an AllocationLimitExceeded exception. (default: 100k)",
413 "",
414 "RTS options may also be specified using the GHCRTS environment variable.",
415 "",
416 "Other RTS options may be available for programs compiled a different way.",
417 "The GHC User's Guide has full details.",
418 "",
419 0
420 };
421
422 STATIC_INLINE rtsBool strequal(const char *a, const char * b)
423 {
424 return(strcmp(a, b) == 0);
425 }
426
427 // We can't predict up front how much space we'll need for rts_argv,
428 // because it involves parsing ghc_rts_opts and GHCRTS, so we
429 // expand it on demand.
430 static void appendRtsArg (char *arg)
431 {
432 if (rts_argc == rts_argv_size) {
433 rts_argv_size *= 2;
434 rts_argv = stgReallocBytes(rts_argv, rts_argv_size * sizeof (char *),
435 "RtsFlags.c:appendRtsArg");
436 }
437 rts_argv[rts_argc++] = arg;
438 }
439
440 static void splitRtsFlags(const char *s)
441 {
442 const char *c1, *c2;
443 char *t;
444
445 c1 = s;
446 do {
447 while (isspace(*c1)) { c1++; };
448 c2 = c1;
449 while (!isspace(*c2) && *c2 != '\0') { c2++; };
450
451 if (c1 == c2) { break; }
452
453 t = stgMallocBytes(c2-c1+1, "RtsFlags.c:splitRtsFlags()");
454 strncpy(t, c1, c2-c1);
455 t[c2-c1] = '\0';
456 appendRtsArg(t);
457
458 c1 = c2;
459 } while (*c1 != '\0');
460 }
461
462 static void errorRtsOptsDisabled(const char *s)
463 {
464 char *advice;
465 if (rtsConfig.rts_hs_main) {
466 advice = "Link with -rtsopts to enable them.";
467 } else {
468 advice = "Use hs_init_with_rtsopts() to enable them.";
469 }
470 errorBelch(s, advice);
471 }
472
473 /* -----------------------------------------------------------------------------
474 Parse the command line arguments, collecting options for the RTS.
475
476 On return:
477 - argv[] is *modified*, any RTS options have been stripped out
478 - *argc contains the new count of arguments in argv[]
479
480 - rts_argv[] (global) contains a copy of the collected RTS args
481 - rts_argc (global) contains the count of args in rts_argv
482
483 - prog_argv[] (global) contains a copy of the non-RTS args (== argv)
484 - prog_argc (global) contains the count of args in prog_argv
485
486 - prog_name (global) contains the basename of prog_argv[0]
487
488 - rtsConfig (global) contains the supplied RtsConfig
489
490 -------------------------------------------------------------------------- */
491
492 void setupRtsFlags (int *argc, char *argv[], RtsConfig rts_config)
493 {
494 uint32_t mode;
495 uint32_t total_arg;
496 uint32_t arg, rts_argc0;
497
498 rtsConfig = rts_config;
499
500 setProgName (argv);
501 total_arg = *argc;
502 arg = 1;
503
504 if (*argc > 1) { *argc = 1; };
505 rts_argc = 0;
506
507 rts_argv_size = total_arg + 1;
508 rts_argv = stgMallocBytes(rts_argv_size * sizeof (char *), "setupRtsFlags");
509
510 rts_argc0 = rts_argc;
511
512 // process arguments from the -with-rtsopts compile-time flag first
513 // (arguments from the GHCRTS environment variable and the command
514 // line override these).
515 {
516 if (rtsConfig.rts_opts != NULL) {
517 splitRtsFlags(rtsConfig.rts_opts);
518 // opts from rts_opts are always enabled:
519 procRtsOpts(rts_argc0, RtsOptsAll);
520 rts_argc0 = rts_argc;
521 }
522 }
523
524 // process arguments from the GHCRTS environment variable next
525 // (arguments from the command line override these).
526 {
527 char *ghc_rts = getenv("GHCRTS");
528
529 if (ghc_rts != NULL) {
530 if (rtsConfig.rts_opts_enabled == RtsOptsNone) {
531 errorRtsOptsDisabled(
532 "Warning: Ignoring GHCRTS variable as RTS options are disabled.\n %s");
533 // We don't actually exit, just warn
534 } else {
535 splitRtsFlags(ghc_rts);
536 procRtsOpts(rts_argc0, rtsConfig.rts_opts_enabled);
537 rts_argc0 = rts_argc;
538 }
539 }
540 }
541
542 // Split arguments (argv) into PGM (argv) and RTS (rts_argv) parts
543 // argv[0] must be PGM argument -- leave in argv
544
545 for (mode = PGM; arg < total_arg; arg++) {
546 // The '--RTS' argument disables all future +RTS ... -RTS processing.
547 if (strequal("--RTS", argv[arg])) {
548 arg++;
549 break;
550 }
551 // The '--' argument is passed through to the program, but
552 // disables all further +RTS ... -RTS processing.
553 else if (strequal("--", argv[arg])) {
554 break;
555 }
556 else if (strequal("+RTS", argv[arg])) {
557 mode = RTS;
558 }
559 else if (strequal("-RTS", argv[arg])) {
560 mode = PGM;
561 }
562 else if (mode == RTS) {
563 appendRtsArg(copyArg(argv[arg]));
564 }
565 else {
566 argv[(*argc)++] = argv[arg];
567 }
568 }
569 // process remaining program arguments
570 for (; arg < total_arg; arg++) {
571 argv[(*argc)++] = argv[arg];
572 }
573 argv[*argc] = (char *) 0;
574
575 procRtsOpts(rts_argc0, rtsConfig.rts_opts_enabled);
576
577 appendRtsArg((char *)0);
578 rts_argc--; // appendRtsArg will have bumped it for the NULL (#7227)
579
580 normaliseRtsOpts();
581
582 setProgArgv(*argc, argv);
583
584 if (RtsFlags.GcFlags.statsFile != NULL) {
585 initStatsFile (RtsFlags.GcFlags.statsFile);
586 }
587 #ifdef TICKY_TICKY
588 if (RtsFlags.TickyFlags.tickyFile != NULL) {
589 initStatsFile (RtsFlags.TickyFlags.tickyFile);
590 }
591 #endif
592 }
593
594 /* -----------------------------------------------------------------------------
595 * procRtsOpts: Process rts_argv between rts_argc0 and rts_argc.
596 * -------------------------------------------------------------------------- */
597
598 #if defined(HAVE_UNISTD_H) && defined(HAVE_SYS_TYPES_H) && !defined(mingw32_HOST_OS)
599 static void checkSuid(RtsOptsEnabledEnum enabled)
600 {
601 if (enabled == RtsOptsSafeOnly) {
602 /* This doesn't cover linux/posix capabilities like CAP_DAC_OVERRIDE,
603 we'd have to link with -lcap for that. */
604 if ((getuid() != geteuid()) || (getgid() != getegid())) {
605 errorRtsOptsDisabled(
606 "RTS options are disabled for setuid binaries. %s");
607 stg_exit(EXIT_FAILURE);
608 }
609 }
610 }
611 #else
612 static void checkSuid (RtsOptsEnabledEnum enabled STG_UNUSED)
613 {
614 }
615 #endif
616
617 static void checkUnsafe(RtsOptsEnabledEnum enabled)
618 {
619 if (enabled == RtsOptsSafeOnly) {
620 errorRtsOptsDisabled("Most RTS options are disabled. %s");
621 stg_exit(EXIT_FAILURE);
622 }
623 }
624
625 static void procRtsOpts (int rts_argc0,
626 RtsOptsEnabledEnum rtsOptsEnabled)
627 {
628 rtsBool error = rtsFalse;
629 int arg;
630 int unchecked_arg_start;
631
632 if (!(rts_argc0 < rts_argc)) return;
633
634 if (rtsOptsEnabled == RtsOptsNone) {
635 errorRtsOptsDisabled("RTS options are disabled. %s");
636 stg_exit(EXIT_FAILURE);
637 }
638
639 checkSuid(rtsOptsEnabled);
640
641 // Process RTS (rts_argv) part: mainly to determine statsfile
642 for (arg = rts_argc0; arg < rts_argc; arg++) {
643
644 /* We handle RtsOptsSafeOnly mode by declaring each option as
645 either OPTION_SAFE or OPTION_UNSAFE. To make sure we cover
646 every branch we use an option_checked flag which is reset
647 at the start each iteration and checked at the end. */
648 rtsBool option_checked = rtsFalse;
649
650 // See Note [OPTION_SAFE vs OPTION_UNSAFE].
651 #define OPTION_SAFE option_checked = rtsTrue;
652 #define OPTION_UNSAFE checkUnsafe(rtsOptsEnabled); option_checked = rtsTrue;
653
654 if (rts_argv[arg][0] != '-') {
655 fflush(stdout);
656 errorBelch("unexpected RTS argument: %s", rts_argv[arg]);
657 error = rtsTrue;
658
659 } else {
660 /* 0 is dash, 1 is first letter */
661 /* see Trac #9839 */
662 unchecked_arg_start = 1;
663 switch(rts_argv[arg][1]) {
664
665 /* process: general args, then PROFILING-only ones, then
666 CONCURRENT-only, TICKY-only (same order as defined in
667 RtsFlags.lh); within those groups, mostly in
668 case-insensitive alphabetical order. Final group is
669 x*, which allows for more options.
670 */
671
672 #ifdef TICKY_TICKY
673 # define TICKY_BUILD_ONLY(x) x
674 #else
675 # define TICKY_BUILD_ONLY(x) \
676 errorBelch("the flag %s requires the program to be built with -ticky", \
677 rts_argv[arg]); \
678 error = rtsTrue;
679 #endif
680
681 #ifdef PROFILING
682 # define PROFILING_BUILD_ONLY(x) x
683 #else
684 # define PROFILING_BUILD_ONLY(x) \
685 errorBelch("the flag %s requires the program to be built with -prof", \
686 rts_argv[arg]); \
687 error = rtsTrue;
688 #endif
689
690 #ifdef TRACING
691 # define TRACING_BUILD_ONLY(x) x
692 #else
693 # define TRACING_BUILD_ONLY(x) \
694 errorBelch("the flag %s requires the program to be built with -eventlog or -debug", \
695 rts_argv[arg]); \
696 error = rtsTrue;
697 #endif
698
699 #ifdef THREADED_RTS
700 # define THREADED_BUILD_ONLY(x) x
701 #else
702 # define THREADED_BUILD_ONLY(x) \
703 errorBelch("the flag %s requires the program to be built with -threaded", \
704 rts_argv[arg]); \
705 error = rtsTrue;
706 #endif
707
708 #ifdef DEBUG
709 # define DEBUG_BUILD_ONLY(x) x
710 #else
711 # define DEBUG_BUILD_ONLY(x) \
712 errorBelch("the flag %s requires the program to be built with -debug", \
713 rts_argv[arg]); \
714 error = rtsTrue;
715 #endif
716
717 /* =========== GENERAL ========================== */
718 case '?':
719 OPTION_SAFE;
720 error = rtsTrue;
721 break;
722
723 /* This isn't going to allow us to keep related options
724 together as we add more --* flags. We really need a
725 proper options parser. */
726 case '-':
727 if (strequal("install-signal-handlers=yes",
728 &rts_argv[arg][2])) {
729 OPTION_UNSAFE;
730 RtsFlags.MiscFlags.install_signal_handlers = rtsTrue;
731 }
732 else if (strequal("install-signal-handlers=no",
733 &rts_argv[arg][2])) {
734 OPTION_UNSAFE;
735 RtsFlags.MiscFlags.install_signal_handlers = rtsFalse;
736 }
737 else if (strequal("machine-readable",
738 &rts_argv[arg][2])) {
739 OPTION_UNSAFE;
740 RtsFlags.MiscFlags.machineReadable = rtsTrue;
741 }
742 else if (strequal("info",
743 &rts_argv[arg][2])) {
744 OPTION_SAFE;
745 printRtsInfo();
746 stg_exit(0);
747 }
748 else {
749 OPTION_SAFE;
750 errorBelch("unknown RTS option: %s",rts_argv[arg]);
751 error = rtsTrue;
752 }
753 break;
754 case 'A':
755 OPTION_UNSAFE;
756 if (rts_argv[arg][2] == 'L') {
757 RtsFlags.GcFlags.largeAllocLim
758 = decodeSize(rts_argv[arg], 3, 2*BLOCK_SIZE,
759 HS_INT_MAX) / BLOCK_SIZE;
760 } else {
761 // minimum two blocks in the nursery, so that we have one
762 // to grab for allocate().
763 RtsFlags.GcFlags.minAllocAreaSize
764 = decodeSize(rts_argv[arg], 2, 2*BLOCK_SIZE,
765 HS_INT_MAX) / BLOCK_SIZE;
766 }
767 break;
768 case 'n':
769 OPTION_UNSAFE;
770 RtsFlags.GcFlags.nurseryChunkSize
771 = decodeSize(rts_argv[arg], 2, 2*BLOCK_SIZE, HS_INT_MAX)
772 / BLOCK_SIZE;
773 break;
774
775 case 'B':
776 OPTION_UNSAFE;
777 RtsFlags.GcFlags.ringBell = rtsTrue;
778 unchecked_arg_start++;
779 goto check_rest;
780
781 case 'c':
782 OPTION_UNSAFE;
783 if (rts_argv[arg][2] != '\0') {
784 RtsFlags.GcFlags.compactThreshold =
785 atof(rts_argv[arg]+2);
786 } else {
787 RtsFlags.GcFlags.compact = rtsTrue;
788 }
789 break;
790
791 case 'w':
792 OPTION_UNSAFE;
793 RtsFlags.GcFlags.sweep = rtsTrue;
794 unchecked_arg_start++;
795 goto check_rest;
796
797 case 'F':
798 OPTION_UNSAFE;
799 RtsFlags.GcFlags.oldGenFactor = atof(rts_argv[arg]+2);
800
801 if (RtsFlags.GcFlags.oldGenFactor < 0)
802 bad_option( rts_argv[arg] );
803 break;
804
805 case 'D':
806 OPTION_SAFE;
807 DEBUG_BUILD_ONLY(read_debug_flags(rts_argv[arg]);)
808 break;
809
810 case 'K':
811 OPTION_UNSAFE;
812 RtsFlags.GcFlags.maxStkSize =
813 decodeSize(rts_argv[arg], 2, sizeof(W_), HS_WORD_MAX)
814 / sizeof(W_);
815 break;
816
817 case 'k':
818 OPTION_UNSAFE;
819 switch(rts_argv[arg][2]) {
820 case 'c':
821 RtsFlags.GcFlags.stkChunkSize =
822 decodeSize(rts_argv[arg], 3, sizeof(W_), HS_WORD_MAX)
823 / sizeof(W_);
824 break;
825 case 'b':
826 RtsFlags.GcFlags.stkChunkBufferSize =
827 decodeSize(rts_argv[arg], 3, sizeof(W_), HS_WORD_MAX)
828 / sizeof(W_);
829 break;
830 case 'i':
831 RtsFlags.GcFlags.initialStkSize =
832 decodeSize(rts_argv[arg], 3, sizeof(W_), HS_WORD_MAX)
833 / sizeof(W_);
834 break;
835 default:
836 RtsFlags.GcFlags.initialStkSize =
837 decodeSize(rts_argv[arg], 2, sizeof(W_), HS_WORD_MAX)
838 / sizeof(W_);
839 break;
840 }
841 break;
842
843 case 'M':
844 OPTION_UNSAFE;
845 RtsFlags.GcFlags.maxHeapSize =
846 decodeSize(rts_argv[arg], 2, BLOCK_SIZE, HS_WORD_MAX)
847 / BLOCK_SIZE;
848 /* user give size in *bytes* but "maxHeapSize" is in
849 * *blocks* */
850 break;
851
852 case 'm':
853 /* Case for maxN feature request ticket #10728, it's a little
854 odd being so far from the N case. */
855 #if !defined(NOSMP)
856 if (strncmp("maxN", &rts_argv[arg][1], 4) == 0) {
857 OPTION_SAFE;
858 THREADED_BUILD_ONLY(
859 int nNodes;
860 int proc = (int)getNumberOfProcessors();
861
862 nNodes = strtol(rts_argv[arg]+5, (char **) NULL, 10);
863 if (nNodes > proc) { nNodes = proc; }
864
865 if (nNodes <= 0) {
866 errorBelch("bad value for -maxN");
867 error = rtsTrue;
868 }
869 #if defined(PROFILING)
870 RtsFlags.ParFlags.nNodes = 1;
871 #else
872 RtsFlags.ParFlags.nNodes = (uint32_t)nNodes;
873 #endif
874 ) break;
875 } else {
876 #endif
877 OPTION_UNSAFE;
878 RtsFlags.GcFlags.pcFreeHeap = atof(rts_argv[arg]+2);
879
880 /* -m was allowing bad flags to go unreported */
881 if (RtsFlags.GcFlags.pcFreeHeap == 0.0 &&
882 rts_argv[arg][2] != '0')
883 bad_option( rts_argv[arg] );
884
885 if (RtsFlags.GcFlags.pcFreeHeap < 0 ||
886 RtsFlags.GcFlags.pcFreeHeap > 100)
887 bad_option( rts_argv[arg] );
888 break;
889 #if !defined(NOSMP)
890 }
891 #endif
892 case 'G':
893 OPTION_UNSAFE;
894 RtsFlags.GcFlags.generations =
895 decodeSize(rts_argv[arg], 2, 1, HS_INT_MAX);
896 break;
897
898 case 'H':
899 OPTION_UNSAFE;
900 if (rts_argv[arg][2] == '\0') {
901 RtsFlags.GcFlags.heapSizeSuggestionAuto = rtsTrue;
902 } else {
903 RtsFlags.GcFlags.heapSizeSuggestion = (uint32_t)
904 (decodeSize(rts_argv[arg], 2, BLOCK_SIZE, HS_WORD_MAX)
905 / BLOCK_SIZE);
906 }
907 break;
908
909 case 'O':
910 OPTION_UNSAFE;
911 RtsFlags.GcFlags.minOldGenSize =
912 (uint32_t)(decodeSize(rts_argv[arg], 2, BLOCK_SIZE,
913 HS_WORD_MAX)
914 / BLOCK_SIZE);
915 break;
916
917 case 'I': /* idle GC delay */
918 OPTION_UNSAFE;
919 if (rts_argv[arg][2] == '\0') {
920 /* use default */
921 } else {
922 Time t = fsecondsToTime(atof(rts_argv[arg]+2));
923 if (t == 0) {
924 RtsFlags.GcFlags.doIdleGC = rtsFalse;
925 } else {
926 RtsFlags.GcFlags.doIdleGC = rtsTrue;
927 RtsFlags.GcFlags.idleGCDelayTime = t;
928 }
929 }
930 break;
931
932 case 'T':
933 OPTION_SAFE;
934 RtsFlags.GcFlags.giveStats = COLLECT_GC_STATS;
935 unchecked_arg_start++;
936 goto check_rest; /* Don't initialize statistics file. */
937
938 case 'S':
939 OPTION_SAFE; /* but see below */
940 RtsFlags.GcFlags.giveStats = VERBOSE_GC_STATS;
941 goto stats;
942
943 case 's':
944 OPTION_SAFE; /* but see below */
945 RtsFlags.GcFlags.giveStats = SUMMARY_GC_STATS;
946 goto stats;
947
948 case 't':
949 OPTION_SAFE; /* but see below */
950 RtsFlags.GcFlags.giveStats = ONELINE_GC_STATS;
951 goto stats;
952
953 stats:
954 {
955 int r;
956 if (rts_argv[arg][2] != '\0') {
957 OPTION_UNSAFE;
958 }
959 r = openStatsFile(rts_argv[arg]+2, NULL,
960 &RtsFlags.GcFlags.statsFile);
961 if (r == -1) { error = rtsTrue; }
962 }
963 break;
964
965 case 'Z':
966 OPTION_UNSAFE;
967 RtsFlags.GcFlags.squeezeUpdFrames = rtsFalse;
968 unchecked_arg_start++;
969 goto check_rest;
970
971 /* =========== PROFILING ========================== */
972
973 case 'P': /* detailed cost centre profiling (time/alloc) */
974 case 'p': /* cost centre profiling (time/alloc) */
975 OPTION_SAFE;
976 PROFILING_BUILD_ONLY(
977 switch (rts_argv[arg][2]) {
978 case 'a':
979 RtsFlags.CcFlags.doCostCentres = COST_CENTRES_ALL;
980 if (rts_argv[arg][3] != '\0') {
981 errorBelch("flag -Pa given an argument"
982 " when none was expected: %s"
983 ,rts_argv[arg]);
984 error = rtsTrue;
985 }
986 break;
987 case '\0':
988 if (rts_argv[arg][1] == 'P') {
989 RtsFlags.CcFlags.doCostCentres =
990 COST_CENTRES_VERBOSE;
991 } else {
992 RtsFlags.CcFlags.doCostCentres =
993 COST_CENTRES_SUMMARY;
994 }
995 break;
996 default:
997 unchecked_arg_start++;
998 goto check_rest;
999 }
1000 ) break;
1001
1002 case 'R':
1003 OPTION_SAFE;
1004 PROFILING_BUILD_ONLY(
1005 RtsFlags.ProfFlags.maxRetainerSetSize =
1006 atof(rts_argv[arg]+2);
1007 ) break;
1008 case 'L':
1009 OPTION_SAFE;
1010 PROFILING_BUILD_ONLY(
1011 RtsFlags.ProfFlags.ccsLength = atof(rts_argv[arg]+2);
1012 if(RtsFlags.ProfFlags.ccsLength <= 0) {
1013 bad_option(rts_argv[arg]);
1014 }
1015 ) break;
1016 case 'h': /* serial heap profile */
1017 #if !defined(PROFILING)
1018 switch (rts_argv[arg][2]) {
1019 case '\0':
1020 case 'T':
1021 OPTION_UNSAFE;
1022 RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_CLOSURE_TYPE;
1023 break;
1024 default:
1025 OPTION_SAFE;
1026 PROFILING_BUILD_ONLY();
1027 }
1028 #else
1029 OPTION_SAFE;
1030 PROFILING_BUILD_ONLY(
1031 error = read_heap_profiling_flag(rts_argv[arg]);
1032 );
1033 #endif /* PROFILING */
1034 break;
1035
1036 case 'i': /* heap sample interval */
1037 OPTION_UNSAFE;
1038 if (rts_argv[arg][2] == '\0') {
1039 /* use default */
1040 } else {
1041 RtsFlags.ProfFlags.heapProfileInterval =
1042 fsecondsToTime(atof(rts_argv[arg]+2));
1043 }
1044 break;
1045
1046 /* =========== CONCURRENT ========================= */
1047 case 'C': /* context switch interval */
1048 OPTION_UNSAFE;
1049 if (rts_argv[arg][2] == '\0')
1050 RtsFlags.ConcFlags.ctxtSwitchTime = 0;
1051 else {
1052 RtsFlags.ConcFlags.ctxtSwitchTime =
1053 fsecondsToTime(atof(rts_argv[arg]+2));
1054 }
1055 break;
1056
1057 case 'V': /* master tick interval */
1058 OPTION_UNSAFE;
1059 if (rts_argv[arg][2] == '\0') {
1060 // turns off ticks completely
1061 RtsFlags.MiscFlags.tickInterval = 0;
1062 } else {
1063 RtsFlags.MiscFlags.tickInterval =
1064 fsecondsToTime(atof(rts_argv[arg]+2));
1065 }
1066 break;
1067
1068 #if !defined(NOSMP)
1069 case 'N':
1070 OPTION_SAFE;
1071 THREADED_BUILD_ONLY(
1072 if (rts_argv[arg][2] == '\0') {
1073 #if defined(PROFILING)
1074 RtsFlags.ParFlags.nNodes = 1;
1075 #else
1076 RtsFlags.ParFlags.nNodes = getNumberOfProcessors();
1077 #endif
1078 } else {
1079 int nNodes;
1080 OPTION_SAFE; /* but see extra checks below... */
1081
1082 nNodes = strtol(rts_argv[arg]+2, (char **) NULL, 10);
1083
1084 if (nNodes <= 0) {
1085 errorBelch("bad value for -N");
1086 error = rtsTrue;
1087 }
1088 if (rtsOptsEnabled == RtsOptsSafeOnly &&
1089 nNodes > (int)getNumberOfProcessors()) {
1090 errorRtsOptsDisabled("Using large values for -N is not allowed by default. %s");
1091 stg_exit(EXIT_FAILURE);
1092 }
1093 RtsFlags.ParFlags.nNodes = (uint32_t)nNodes;
1094 }
1095 ) break;
1096
1097 case 'g':
1098 OPTION_UNSAFE;
1099 THREADED_BUILD_ONLY(
1100 switch (rts_argv[arg][2]) {
1101 case '1':
1102 // backwards compat only
1103 RtsFlags.ParFlags.parGcEnabled = rtsFalse;
1104 break;
1105 default:
1106 errorBelch("unknown RTS option: %s",rts_argv[arg]);
1107 error = rtsTrue;
1108 break;
1109 }
1110 ) break;
1111
1112 case 'q':
1113 OPTION_UNSAFE;
1114 THREADED_BUILD_ONLY(
1115 switch (rts_argv[arg][2]) {
1116 case '\0':
1117 errorBelch("incomplete RTS option: %s",rts_argv[arg]);
1118 error = rtsTrue;
1119 break;
1120 case 'g':
1121 if (rts_argv[arg][3] == '\0') {
1122 RtsFlags.ParFlags.parGcEnabled = rtsFalse;
1123 } else {
1124 RtsFlags.ParFlags.parGcEnabled = rtsTrue;
1125 RtsFlags.ParFlags.parGcGen
1126 = strtol(rts_argv[arg]+3, (char **) NULL, 10);
1127 }
1128 break;
1129 case 'b':
1130 if (rts_argv[arg][3] == '\0') {
1131 RtsFlags.ParFlags.parGcLoadBalancingEnabled =
1132 rtsFalse;
1133 }
1134 else {
1135 RtsFlags.ParFlags.parGcLoadBalancingEnabled =
1136 rtsTrue;
1137 RtsFlags.ParFlags.parGcLoadBalancingGen
1138 = strtol(rts_argv[arg]+3, (char **) NULL, 10);
1139 }
1140 break;
1141 case 'i':
1142 RtsFlags.ParFlags.parGcNoSyncWithIdle
1143 = strtol(rts_argv[arg]+3, (char **) NULL, 10);
1144 break;
1145 case 'n': {
1146 int threads;
1147 threads = strtol(rts_argv[arg]+3, (char **) NULL, 10);
1148 if (threads <= 0) {
1149 errorBelch("-qn must be 1 or greater");
1150 error = rtsTrue;
1151 } else {
1152 RtsFlags.ParFlags.parGcThreads = threads;
1153 }
1154 break;
1155 }
1156 case 'a':
1157 RtsFlags.ParFlags.setAffinity = rtsTrue;
1158 break;
1159 case 'm':
1160 RtsFlags.ParFlags.migrate = rtsFalse;
1161 break;
1162 case 'w':
1163 // -qw was removed; accepted for backwards compat
1164 break;
1165 default:
1166 errorBelch("unknown RTS option: %s",rts_argv[arg]);
1167 error = rtsTrue;
1168 break;
1169 }
1170 ) break;
1171 #endif
1172 /* =========== PARALLEL =========================== */
1173 case 'e':
1174 OPTION_UNSAFE;
1175 THREADED_BUILD_ONLY(
1176 if (rts_argv[arg][2] != '\0') {
1177 RtsFlags.ParFlags.maxLocalSparks
1178 = strtol(rts_argv[arg]+2, (char **) NULL, 10);
1179 if (RtsFlags.ParFlags.maxLocalSparks <= 0) {
1180 errorBelch("bad value for -e");
1181 error = rtsTrue;
1182 }
1183 }
1184 ) break;
1185
1186 /* =========== TICKY ============================== */
1187
1188 case 'r': /* Basic profiling stats */
1189 OPTION_SAFE;
1190 TICKY_BUILD_ONLY(
1191
1192 RtsFlags.TickyFlags.showTickyStats = rtsTrue;
1193
1194 {
1195 int r;
1196 if (rts_argv[arg][2] != '\0') {
1197 OPTION_UNSAFE;
1198 }
1199 r = openStatsFile(rts_argv[arg]+2,
1200 TICKY_FILENAME_FMT,
1201 &RtsFlags.TickyFlags.tickyFile);
1202 if (r == -1) { error = rtsTrue; }
1203 }
1204 ) break;
1205
1206 /* =========== TRACING ---------=================== */
1207
1208 case 'l':
1209 OPTION_SAFE;
1210 TRACING_BUILD_ONLY(
1211 RtsFlags.TraceFlags.tracing = TRACE_EVENTLOG;
1212 read_trace_flags(&rts_argv[arg][2]);
1213 );
1214 break;
1215
1216 case 'v':
1217 OPTION_SAFE;
1218 DEBUG_BUILD_ONLY(
1219 RtsFlags.TraceFlags.tracing = TRACE_STDERR;
1220 read_trace_flags(&rts_argv[arg][2]);
1221 );
1222 break;
1223
1224 /* =========== EXTENDED OPTIONS =================== */
1225
1226 case 'x': /* Extend the argument space */
1227 unchecked_arg_start++;
1228 switch(rts_argv[arg][2]) {
1229 case '\0':
1230 OPTION_SAFE;
1231 errorBelch("incomplete RTS option: %s",rts_argv[arg]);
1232 error = rtsTrue;
1233 break;
1234
1235 case 'b': /* heapBase in hex; undocumented */
1236 OPTION_UNSAFE;
1237 if (rts_argv[arg][3] != '\0') {
1238 RtsFlags.GcFlags.heapBase
1239 = strtol(rts_argv[arg]+3, (char **) NULL, 16);
1240 } else {
1241 errorBelch("-xb: requires argument");
1242 error = rtsTrue;
1243 }
1244 break;
1245
1246 #if defined(x86_64_HOST_ARCH)
1247 case 'm': /* linkerMemBase */
1248 OPTION_UNSAFE;
1249 if (rts_argv[arg][3] != '\0') {
1250 RtsFlags.MiscFlags.linkerMemBase
1251 = strtol(rts_argv[arg]+3, (char **) NULL, 16);
1252 if (RtsFlags.MiscFlags.linkerMemBase > 0x80000000) {
1253 errorBelch("-xm: value must be <80000000");
1254 error = rtsTrue;
1255 }
1256 } else {
1257 RtsFlags.MiscFlags.linkerMemBase = 0;
1258 }
1259 break;
1260 #endif
1261
1262 case 'c': /* Debugging tool: show current cost centre on
1263 an exception */
1264 OPTION_SAFE;
1265 PROFILING_BUILD_ONLY(
1266 RtsFlags.ProfFlags.showCCSOnException = rtsTrue;
1267 );
1268 unchecked_arg_start++;
1269 goto check_rest;
1270
1271 case 't': /* Include memory used by TSOs in a heap profile */
1272 OPTION_SAFE;
1273 PROFILING_BUILD_ONLY(
1274 RtsFlags.ProfFlags.includeTSOs = rtsTrue;
1275 );
1276 unchecked_arg_start++;
1277 goto check_rest;
1278
1279 /*
1280 * The option prefix '-xx' is reserved for future
1281 * extension. KSW 1999-11.
1282 */
1283
1284 case 'q':
1285 OPTION_UNSAFE;
1286 RtsFlags.GcFlags.allocLimitGrace
1287 = decodeSize(rts_argv[arg], 3, BLOCK_SIZE, HS_INT_MAX)
1288 / BLOCK_SIZE;
1289 break;
1290
1291 default:
1292 OPTION_SAFE;
1293 errorBelch("unknown RTS option: %s",rts_argv[arg]);
1294 error = rtsTrue;
1295 break;
1296 }
1297 break; /* defensive programming */
1298
1299 /* check the rest to be sure there is nothing afterwards.*/
1300 /* see Trac #9839 */
1301 check_rest:
1302 {
1303 /* start checking from the first unchecked position,
1304 * not from index 2*/
1305 /* see Trac #9839 */
1306 if (rts_argv[arg][unchecked_arg_start] != '\0') {
1307 errorBelch("flag -%c given an argument"
1308 " when none was expected: %s",
1309 rts_argv[arg][1],rts_argv[arg]);
1310 error = rtsTrue;
1311 }
1312 break;
1313 }
1314
1315 /* =========== OH DEAR ============================ */
1316 default:
1317 OPTION_SAFE;
1318 errorBelch("unknown RTS option: %s",rts_argv[arg]);
1319 error = rtsTrue;
1320 break;
1321 }
1322
1323 if (!option_checked) {
1324 /* Naughty! Someone didn't use OPTION_UNSAFE / OPTION_SAFE for
1325 an option above */
1326 errorBelch("Internal error in the RTS options parser");
1327 stg_exit(EXIT_FAILURE);
1328 }
1329 }
1330 }
1331
1332 if (error) errorUsage();
1333 }
1334
1335 /* -----------------------------------------------------------------------------
1336 * normaliseRtsOpts: Set some derived values, and make sure things are
1337 * within sensible ranges.
1338 * -------------------------------------------------------------------------- */
1339
1340 static void normaliseRtsOpts (void)
1341 {
1342 if (RtsFlags.MiscFlags.tickInterval < 0) {
1343 RtsFlags.MiscFlags.tickInterval = DEFAULT_TICK_INTERVAL;
1344 }
1345
1346 // If the master timer is disabled, turn off the other timers.
1347 if (RtsFlags.MiscFlags.tickInterval == 0) {
1348 RtsFlags.ConcFlags.ctxtSwitchTime = 0;
1349 RtsFlags.GcFlags.idleGCDelayTime = 0;
1350 RtsFlags.ProfFlags.heapProfileInterval = 0;
1351 }
1352
1353 // Determine what tick interval we should use for the RTS timer
1354 // by taking the shortest of the various intervals that we need to
1355 // monitor.
1356 if (RtsFlags.ConcFlags.ctxtSwitchTime > 0) {
1357 RtsFlags.MiscFlags.tickInterval =
1358 stg_min(RtsFlags.ConcFlags.ctxtSwitchTime,
1359 RtsFlags.MiscFlags.tickInterval);
1360 }
1361
1362 if (RtsFlags.GcFlags.idleGCDelayTime > 0) {
1363 RtsFlags.MiscFlags.tickInterval =
1364 stg_min(RtsFlags.GcFlags.idleGCDelayTime,
1365 RtsFlags.MiscFlags.tickInterval);
1366 }
1367
1368 if (RtsFlags.ProfFlags.heapProfileInterval > 0) {
1369 RtsFlags.MiscFlags.tickInterval =
1370 stg_min(RtsFlags.ProfFlags.heapProfileInterval,
1371 RtsFlags.MiscFlags.tickInterval);
1372 }
1373
1374 if (RtsFlags.ConcFlags.ctxtSwitchTime > 0) {
1375 RtsFlags.ConcFlags.ctxtSwitchTicks =
1376 RtsFlags.ConcFlags.ctxtSwitchTime /
1377 RtsFlags.MiscFlags.tickInterval;
1378 } else {
1379 RtsFlags.ConcFlags.ctxtSwitchTicks = 0;
1380 }
1381
1382 if (RtsFlags.ProfFlags.heapProfileInterval > 0) {
1383 RtsFlags.ProfFlags.heapProfileIntervalTicks =
1384 RtsFlags.ProfFlags.heapProfileInterval /
1385 RtsFlags.MiscFlags.tickInterval;
1386 } else {
1387 RtsFlags.ProfFlags.heapProfileIntervalTicks = 0;
1388 }
1389
1390 if (RtsFlags.GcFlags.stkChunkBufferSize >
1391 RtsFlags.GcFlags.stkChunkSize / 2) {
1392 errorBelch("stack chunk buffer size (-kb) must be less than 50%%\n"
1393 "of the stack chunk size (-kc)");
1394 errorUsage();
1395 }
1396
1397 #ifdef THREADED_RTS
1398 if (RtsFlags.ParFlags.parGcThreads > RtsFlags.ParFlags.nNodes) {
1399 errorBelch("GC threads (-qn) must be between 1 and the value of -N");
1400 errorUsage();
1401 }
1402 #endif
1403 }
1404
1405 static void errorUsage (void)
1406 {
1407 const char **p;
1408
1409 fflush(stdout);
1410 for (p = usage_text; *p; p++)
1411 errorBelch("%s", *p);
1412 stg_exit(EXIT_FAILURE);
1413 }
1414
1415 static void
1416 stats_fprintf(FILE *f, char *s, ...)
1417 {
1418 va_list ap;
1419 va_start(ap,s);
1420 if (f == NULL) {
1421 vdebugBelch(s, ap);
1422 } else {
1423 vfprintf(f, s, ap);
1424 }
1425 va_end(ap);
1426 }
1427
1428 /* -----------------------------------------------------------------------------
1429 * openStatsFile: open a file in which to put some runtime stats
1430 * -------------------------------------------------------------------------- */
1431
1432 static int // return -1 on error
1433 openStatsFile (char *filename, // filename, or NULL
1434 const char *filename_fmt, // if filename == NULL, use
1435 // this fmt with sprintf to
1436 // generate the filename. %s
1437 // expands to the program name.
1438 FILE **file_ret) // return the FILE*
1439 {
1440 FILE *f = NULL;
1441
1442 if (strequal(filename, "stderr")
1443 || (filename_fmt == NULL && *filename == '\0')) {
1444 f = NULL; /* NULL means use debugBelch */
1445 } else {
1446 if (*filename != '\0') { /* stats file specified */
1447 f = fopen(filename,"w");
1448 } else {
1449 /* default <program>.<ext> */
1450 char stats_filename[STATS_FILENAME_MAXLEN];
1451 sprintf(stats_filename, filename_fmt, prog_name);
1452 f = fopen(stats_filename,"w");
1453 }
1454 if (f == NULL) {
1455 errorBelch("Can't open stats file %s\n", filename);
1456 return -1;
1457 }
1458 }
1459 *file_ret = f;
1460
1461 return 0;
1462 }
1463
1464 /* -----------------------------------------------------------------------------
1465 * initStatsFile: write a line to the file containing the program name
1466 * and the arguments it was invoked with.
1467 -------------------------------------------------------------------------- */
1468
1469 static void initStatsFile (FILE *f)
1470 {
1471 /* Write prog_argv and rts_argv into start of stats file */
1472 int count;
1473 for (count = 0; count < prog_argc; count++) {
1474 stats_fprintf(f, "%s ", prog_argv[count]);
1475 }
1476 stats_fprintf(f, "+RTS ");
1477 for (count = 0; count < rts_argc; count++)
1478 stats_fprintf(f, "%s ", rts_argv[count]);
1479 stats_fprintf(f, "\n");
1480 }
1481
1482 /* -----------------------------------------------------------------------------
1483 * decodeSize: parse a string containing a size, like 300K or 1.2M
1484 -------------------------------------------------------------------------- */
1485
1486 static StgWord64
1487 decodeSize(const char *flag, uint32_t offset, StgWord64 min, StgWord64 max)
1488 {
1489 char c;
1490 const char *s;
1491 StgDouble m;
1492 StgWord64 val;
1493
1494 s = flag + offset;
1495
1496 if (!*s)
1497 {
1498 m = 0;
1499 }
1500 else
1501 {
1502 m = atof(s);
1503 c = s[strlen(s)-1];
1504
1505 if (c == 'g' || c == 'G')
1506 m *= 1024*1024*1024;
1507 else if (c == 'm' || c == 'M')
1508 m *= 1024*1024;
1509 else if (c == 'k' || c == 'K')
1510 m *= 1024;
1511 else if (c == 'w' || c == 'W')
1512 m *= sizeof(W_);
1513 }
1514
1515 val = (StgWord64)m;
1516
1517 if (m < 0 || val < min || val > max) {
1518 // printf doesn't like 64-bit format specs on Windows
1519 // apparently, so fall back to unsigned long.
1520 errorBelch("error in RTS option %s: size outside allowed range (%" FMT_Word " - %" FMT_Word ")", flag, (W_)min, (W_)max);
1521 stg_exit(EXIT_FAILURE);
1522 }
1523
1524 return val;
1525 }
1526
1527 #ifdef DEBUG
1528 static void read_debug_flags(const char* arg)
1529 {
1530 // Already parsed "-D"
1531 const char *c;
1532 for (c = arg + 2; *c != '\0'; c++) {
1533 switch (*c) {
1534 case 's':
1535 RtsFlags.DebugFlags.scheduler = rtsTrue;
1536 break;
1537 case 'i':
1538 RtsFlags.DebugFlags.interpreter = rtsTrue;
1539 break;
1540 case 'w':
1541 RtsFlags.DebugFlags.weak = rtsTrue;
1542 break;
1543 case 'G':
1544 RtsFlags.DebugFlags.gccafs = rtsTrue;
1545 break;
1546 case 'g':
1547 RtsFlags.DebugFlags.gc = rtsTrue;
1548 break;
1549 case 'b':
1550 RtsFlags.DebugFlags.block_alloc = rtsTrue;
1551 break;
1552 case 'S':
1553 RtsFlags.DebugFlags.sanity = rtsTrue;
1554 break;
1555 case 't':
1556 RtsFlags.DebugFlags.stable = rtsTrue;
1557 break;
1558 case 'p':
1559 RtsFlags.DebugFlags.prof = rtsTrue;
1560 break;
1561 case 'l':
1562 RtsFlags.DebugFlags.linker = rtsTrue;
1563 break;
1564 case 'a':
1565 RtsFlags.DebugFlags.apply = rtsTrue;
1566 break;
1567 case 'm':
1568 RtsFlags.DebugFlags.stm = rtsTrue;
1569 break;
1570 case 'z':
1571 RtsFlags.DebugFlags.squeeze = rtsTrue;
1572 break;
1573 case 'c':
1574 RtsFlags.DebugFlags.hpc = rtsTrue;
1575 break;
1576 case 'r':
1577 RtsFlags.DebugFlags.sparks = rtsTrue;
1578 break;
1579 default:
1580 bad_option( arg );
1581 }
1582 }
1583 // -Dx also turns on -v. Use -l to direct trace
1584 // events to the .eventlog file instead.
1585 RtsFlags.TraceFlags.tracing = TRACE_STDERR;
1586 }
1587 #endif
1588
1589 #ifdef PROFILING
1590 // Parse a "-h" flag, returning whether the parse resulted in an error.
1591 static rtsBool read_heap_profiling_flag(const char *arg_in)
1592 {
1593 // Already parsed "-h"
1594
1595 // For historical reasons the parser here mutates the arguments.
1596 // However, for sanity we want to guarantee const-correctness and parsing
1597 // really ought to be an immutable operation. To avoid rewriting the parser
1598 // we just operate on a temporary copy of the argument.
1599 char *arg = strdup(arg_in);
1600 rtsBool error = rtsFalse;
1601 switch (arg[2]) {
1602 case '\0':
1603 case 'C':
1604 case 'c':
1605 case 'M':
1606 case 'm':
1607 case 'D':
1608 case 'd':
1609 case 'Y':
1610 case 'y':
1611 case 'R':
1612 case 'r':
1613 case 'B':
1614 case 'b':
1615 if (arg[2] != '\0' && arg[3] != '\0') {
1616 {
1617 char *left = strchr(arg, '{');
1618 char *right = strrchr(arg, '}');
1619
1620 // curly braces are optional, for
1621 // backwards compat.
1622 if (left)
1623 left = left+1;
1624 else
1625 left = arg + 3;
1626
1627 if (!right)
1628 right = arg + strlen(arg);
1629
1630 char *selector = stgStrndup(left, right - left + 1);
1631
1632 switch (arg[2]) {
1633 case 'c': // cost centre label select
1634 RtsFlags.ProfFlags.ccSelector = selector;
1635 break;
1636 case 'C':
1637 RtsFlags.ProfFlags.ccsSelector = selector;
1638 break;
1639 case 'M':
1640 case 'm': // cost centre module select
1641 RtsFlags.ProfFlags.modSelector = selector;
1642 break;
1643 case 'D':
1644 case 'd': // closure descr select
1645 RtsFlags.ProfFlags.descrSelector = selector;
1646 break;
1647 case 'Y':
1648 case 'y': // closure type select
1649 RtsFlags.ProfFlags.typeSelector = selector;
1650 break;
1651 case 'R':
1652 case 'r': // retainer select
1653 RtsFlags.ProfFlags.retainerSelector = selector;
1654 break;
1655 case 'B':
1656 case 'b': // biography select
1657 RtsFlags.ProfFlags.bioSelector = selector;
1658 break;
1659 default:
1660 free(selector);
1661 }
1662 }
1663 break;
1664 }
1665
1666 if (RtsFlags.ProfFlags.doHeapProfile != 0) {
1667 errorBelch("multiple heap profile options");
1668 error = rtsTrue;
1669 break;
1670 }
1671
1672 switch (arg[2]) {
1673 case '\0':
1674 case 'C':
1675 case 'c':
1676 RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_CCS;
1677 break;
1678 case 'M':
1679 case 'm':
1680 RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_MOD;
1681 break;
1682 case 'D':
1683 case 'd':
1684 RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_DESCR;
1685 break;
1686 case 'Y':
1687 case 'y':
1688 RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_TYPE;
1689 break;
1690 case 'R':
1691 case 'r':
1692 RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_RETAINER;
1693 break;
1694 case 'B':
1695 case 'b':
1696 RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_LDV;
1697 break;
1698 }
1699 break;
1700
1701 default:
1702 errorBelch("invalid heap profile option: %s", arg);
1703 error = rtsTrue;
1704 }
1705
1706 free(arg);
1707 return error;
1708 }
1709 #endif
1710
1711 #if defined(TRACING)
1712 static void read_trace_flags(const char *arg)
1713 {
1714 const char *c;
1715 rtsBool enabled = rtsTrue;
1716 /* Syntax for tracing flags currently looks like:
1717 *
1718 * -l To turn on eventlog tracing with default trace classes
1719 * -lx Turn on class 'x' (for some class listed below)
1720 * -l-x Turn off class 'x'
1721 * -la Turn on all classes
1722 * -l-a Turn off all classes
1723 *
1724 * This lets users say things like:
1725 * -la-p "all but sparks"
1726 * -l-ap "only sparks"
1727 */
1728
1729 /* Start by turning on the default tracing flags.
1730 *
1731 * Currently this is all the trace classes, except full-detail sparks.
1732 * Similarly, in future we might default to slightly less verbose
1733 * scheduler or GC tracing.
1734 */
1735 RtsFlags.TraceFlags.scheduler = rtsTrue;
1736 RtsFlags.TraceFlags.gc = rtsTrue;
1737 RtsFlags.TraceFlags.sparks_sampled = rtsTrue;
1738 RtsFlags.TraceFlags.user = rtsTrue;
1739
1740 for (c = arg; *c != '\0'; c++) {
1741 switch(*c) {
1742 case '\0':
1743 break;
1744 case '-':
1745 enabled = rtsFalse;
1746 break;
1747 case 'a':
1748 RtsFlags.TraceFlags.scheduler = enabled;
1749 RtsFlags.TraceFlags.gc = enabled;
1750 RtsFlags.TraceFlags.sparks_sampled = enabled;
1751 RtsFlags.TraceFlags.sparks_full = enabled;
1752 RtsFlags.TraceFlags.user = enabled;
1753 enabled = rtsTrue;
1754 break;
1755
1756 case 's':
1757 RtsFlags.TraceFlags.scheduler = enabled;
1758 enabled = rtsTrue;
1759 break;
1760 case 'p':
1761 RtsFlags.TraceFlags.sparks_sampled = enabled;
1762 enabled = rtsTrue;
1763 break;
1764 case 'f':
1765 RtsFlags.TraceFlags.sparks_full = enabled;
1766 enabled = rtsTrue;
1767 break;
1768 case 't':
1769 RtsFlags.TraceFlags.timestamp = enabled;
1770 enabled = rtsTrue;
1771 break;
1772 case 'g':
1773 RtsFlags.TraceFlags.gc = enabled;
1774 enabled = rtsTrue;
1775 break;
1776 case 'u':
1777 RtsFlags.TraceFlags.user = enabled;
1778 enabled = rtsTrue;
1779 break;
1780 default:
1781 errorBelch("unknown trace option: %c",*c);
1782 break;
1783 }
1784 }
1785 }
1786 #endif
1787
1788 static void GNU_ATTRIBUTE(__noreturn__)
1789 bad_option(const char *s)
1790 {
1791 errorBelch("bad RTS option: %s", s);
1792 stg_exit(EXIT_FAILURE);
1793 }
1794
1795 /* ----------------------------------------------------------------------------
1796 Copying and freeing argc/argv
1797 ------------------------------------------------------------------------- */
1798
1799 static char * copyArg(char *arg)
1800 {
1801 char *new_arg = stgMallocBytes(strlen(arg) + 1, "copyArg");
1802 strcpy(new_arg, arg);
1803 return new_arg;
1804 }
1805
1806 static char ** copyArgv(int argc, char *argv[])
1807 {
1808 int i;
1809 char **new_argv;
1810
1811 new_argv = stgCallocBytes(argc + 1, sizeof (char *), "copyArgv 1");
1812 for (i = 0; i < argc; i++) {
1813 new_argv[i] = copyArg(argv[i]);
1814 }
1815 new_argv[argc] = NULL;
1816 return new_argv;
1817 }
1818
1819 static void freeArgv(int argc, char *argv[])
1820 {
1821 int i;
1822 if (argv != NULL) {
1823 for (i = 0; i < argc; i++) {
1824 stgFree(argv[i]);
1825 }
1826 stgFree(argv);
1827 }
1828 }
1829
1830 /* -----------------------------------------------------------------------------
1831 Getting/Setting the program's arguments.
1832
1833 These are used by System.Environment, and parts of the RTS.
1834 -------------------------------------------------------------------------- */
1835
1836 void
1837 setProgName(char *argv[])
1838 {
1839 char *last_slash;
1840
1841 if (argv[0] == NULL) { // #7037
1842 prog_name = "";
1843 return;
1844 }
1845
1846 /* Remove directory from argv[0] -- default files in current directory */
1847 #if !defined(mingw32_HOST_OS)
1848 if ( (last_slash = (char *) strrchr(argv[0], '/')) != NULL ) {
1849 prog_name = last_slash+1;
1850 } else {
1851 prog_name = argv[0];
1852 }
1853 #else
1854 last_slash = argv[0] + (strlen(argv[0]) - 1);
1855 while ( last_slash > argv[0] ) {
1856 if ( *last_slash == '/' || *last_slash == '\\' ) {
1857 prog_name = last_slash+1;
1858 return;
1859 }
1860 last_slash--;
1861 }
1862 prog_name = argv[0];
1863 #endif
1864 }
1865
1866 void
1867 getProgArgv(int *argc, char **argv[])
1868 {
1869 if (argc) { *argc = prog_argc; }
1870 if (argv) { *argv = prog_argv; }
1871 }
1872
1873 void
1874 setProgArgv(int argc, char *argv[])
1875 {
1876 prog_argc = argc;
1877 prog_argv = copyArgv(argc,argv);
1878 setProgName(prog_argv);
1879 }
1880
1881 static void
1882 freeProgArgv(void)
1883 {
1884 freeArgv(prog_argc,prog_argv);
1885 prog_argc = 0;
1886 prog_argv = NULL;
1887 }
1888
1889 /* ----------------------------------------------------------------------------
1890 The full argv - a copy of the original program's argc/argv
1891 ------------------------------------------------------------------------- */
1892
1893 void
1894 setFullProgArgv(int argc, char *argv[])
1895 {
1896 full_prog_argc = argc;
1897 full_prog_argv = copyArgv(argc,argv);
1898 }
1899
1900 /* These functions record and recall the full arguments, including the
1901 +RTS ... -RTS options. The reason for adding them was so that the
1902 ghc-inplace program can pass /all/ the arguments on to the real ghc. */
1903 void
1904 getFullProgArgv(int *argc, char **argv[])
1905 {
1906 if (argc) { *argc = full_prog_argc; }
1907 if (argv) { *argv = full_prog_argv; }
1908 }
1909
1910 void
1911 freeFullProgArgv (void)
1912 {
1913 freeArgv(full_prog_argc, full_prog_argv);
1914 full_prog_argc = 0;
1915 full_prog_argv = NULL;
1916 }
1917
1918 /* ----------------------------------------------------------------------------
1919 The Win32 argv
1920 ------------------------------------------------------------------------- */
1921
1922 #if defined(mingw32_HOST_OS)
1923 void freeWin32ProgArgv (void);
1924
1925 void
1926 freeWin32ProgArgv (void)
1927 {
1928 int i;
1929
1930 if (win32_prog_argv != NULL) {
1931 for (i = 0; i < win32_prog_argc; i++) {
1932 stgFree(win32_prog_argv[i]);
1933 }
1934 stgFree(win32_prog_argv);
1935 }
1936
1937 win32_prog_argc = 0;
1938 win32_prog_argv = NULL;
1939 }
1940
1941 void
1942 getWin32ProgArgv(int *argc, wchar_t **argv[])
1943 {
1944 *argc = win32_prog_argc;
1945 *argv = win32_prog_argv;
1946 }
1947
1948 void
1949 setWin32ProgArgv(int argc, wchar_t *argv[])
1950 {
1951 int i;
1952
1953 freeWin32ProgArgv();
1954
1955 win32_prog_argc = argc;
1956 if (argv == NULL) {
1957 win32_prog_argv = NULL;
1958 return;
1959 }
1960
1961 win32_prog_argv = stgCallocBytes(argc + 1, sizeof (wchar_t *),
1962 "setWin32ProgArgv 1");
1963 for (i = 0; i < argc; i++) {
1964 win32_prog_argv[i] = stgMallocBytes((wcslen(argv[i]) + 1) * sizeof(wchar_t),
1965 "setWin32ProgArgv 2");
1966 wcscpy(win32_prog_argv[i], argv[i]);
1967 }
1968 win32_prog_argv[argc] = NULL;
1969 }
1970 #endif
1971
1972 /* ----------------------------------------------------------------------------
1973 The RTS argv
1974 ------------------------------------------------------------------------- */
1975
1976 static void
1977 freeRtsArgv(void)
1978 {
1979 freeArgv(rts_argc,rts_argv);
1980 rts_argc = 0;
1981 rts_argv = NULL;
1982 rts_argv_size = 0;
1983 }
1984
1985 /* ----------------------------------------------------------------------------
1986 All argvs
1987 ------------------------------------------------------------------------- */
1988
1989 void freeRtsArgs(void)
1990 {
1991 #if defined(mingw32_HOST_OS)
1992 freeWin32ProgArgv();
1993 #endif
1994 freeFullProgArgv();
1995 freeProgArgv();
1996 freeRtsArgv();
1997 }
1998
1999
2000 /*
2001 Note [OPTION_SAFE vs OPTION_UNSAFE]
2002
2003 Ticket #3910 originally pointed out that the RTS options are a potential
2004 security problem. For example the -t -s or -S flags can be used to
2005 overwrite files. This would be bad in the context of CGI scripts or
2006 setuid binaries. So we introduced a system where +RTS processing is more
2007 or less disabled unless you pass the -rtsopts flag at link time.
2008
2009 This scheme is safe enough but it also really annoyes users. They have
2010 to use -rtsopts in many circumstances: with -threaded to use -N, with
2011 -eventlog to use -l, with -prof to use any of the profiling flags. Many
2012 users just set -rtsopts globally or in project .cabal files. Apart from
2013 annoying users it reduces security because it means that deployed
2014 binaries will have all RTS options enabled rather than just profiling
2015 ones.
2016
2017 So now, we relax the set of RTS options that are available in the
2018 default -rtsopts=some case. For "deployment" ways like vanilla and
2019 -threaded we remain quite conservative. Only --info -? --help are
2020 allowed for vanilla. For -threaded, -N and -N<x> are allowed with a
2021 check that x <= num cpus.
2022
2023 For "developer" ways like -debug, -eventlog, -prof, we allow all the
2024 options that are special to that way. Some of these allow writing files,
2025 but the file written is not directly under the control of the attacker.
2026 For the setuid case (where the attacker would have control over binary
2027 name, current dir, local symlinks etc) we check if the process is
2028 running setuid/setgid and refuse all RTS option processing. Users would
2029 need to use -rtsopts=all in this case.
2030
2031 We are making the assumption that developers will not deploy binaries
2032 built in the -debug, -eventlog, -prof ways. And even if they do, the
2033 damage should be limited to DOS, information disclosure and writing
2034 files like <progname>.eventlog, not arbitrary files.
2035 */