[t][TT#1509] Prevent core dumps by preventing negative length array creation. Tests...
[parrot.git] / src / main.c
blob34b04365864cbc0fdaeaa1e0d170d071164fa2c9
1 /*
2 Copyright (C) 2007-2010, Parrot Foundation.
3 $Id$
5 =head1 NAME
7 src/main.c - the Entry Point to Parrot Programs
9 =head1 DESCRIPTION
11 Start Parrot
13 =head2 Functions
15 =over 4
17 =cut
21 #include <stdio.h>
23 #include "parrot/parrot.h"
24 #include "parrot/embed.h"
25 #include "parrot/imcc.h"
26 #include "parrot/longopt.h"
27 #include "parrot/runcore_api.h"
28 #include "pmc/pmc_callcontext.h"
30 /* For gc_sys_type_enum */
31 #include "gc/gc_private.h"
33 /* HEADERIZER HFILE: none */
35 /* HEADERIZER BEGIN: static */
36 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
38 static void help(void);
39 static void help_debug(void);
40 PARROT_WARN_UNUSED_RESULT
41 PARROT_PURE_FUNCTION
42 static int is_all_hex_digits(ARGIN(const char *s))
43 __attribute__nonnull__(1);
45 static void Parrot_version(PARROT_INTERP)
46 __attribute__nonnull__(1);
48 PARROT_CAN_RETURN_NULL
49 static const char * parseflags(PARROT_INTERP,
50 ARGIN(int *argc),
51 ARGIN(char **argv[]),
52 ARGIN(Parrot_Run_core_t *core),
53 ARGIN(Parrot_trace_flags *trace))
54 __attribute__nonnull__(1)
55 __attribute__nonnull__(2)
56 __attribute__nonnull__(3)
57 __attribute__nonnull__(4)
58 __attribute__nonnull__(5);
60 static void parseflags_minimal(PARROT_INTERP, int argc, ARGIN(char *argv[]))
61 __attribute__nonnull__(1)
62 __attribute__nonnull__(3);
64 static void usage(ARGMOD(FILE *fp))
65 __attribute__nonnull__(1)
66 FUNC_MODIFIES(*fp);
68 #define ASSERT_ARGS_help __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
69 #define ASSERT_ARGS_help_debug __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
70 #define ASSERT_ARGS_is_all_hex_digits __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
71 PARROT_ASSERT_ARG(s))
72 #define ASSERT_ARGS_Parrot_version __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
73 PARROT_ASSERT_ARG(interp))
74 #define ASSERT_ARGS_parseflags __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
75 PARROT_ASSERT_ARG(interp) \
76 , PARROT_ASSERT_ARG(argc) \
77 , PARROT_ASSERT_ARG(argv) \
78 , PARROT_ASSERT_ARG(core) \
79 , PARROT_ASSERT_ARG(trace))
80 #define ASSERT_ARGS_parseflags_minimal __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
81 PARROT_ASSERT_ARG(interp) \
82 , PARROT_ASSERT_ARG(argv))
83 #define ASSERT_ARGS_usage __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
84 PARROT_ASSERT_ARG(fp))
85 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
86 /* HEADERIZER END: static */
90 =item C<int main(int argc, char * argv[])>
92 The entry point from the command line into Parrot.
94 =cut
98 int
99 main(int argc, char * argv[])
101 int stacktop;
102 const char *sourcefile;
103 const char *execname;
104 Interp *interp;
105 int status;
107 Parrot_Run_core_t core = PARROT_SLOW_CORE;
108 Parrot_trace_flags trace = PARROT_NO_TRACE;
110 /* internationalization setup */
111 /* setlocale(LC_ALL, ""); */
112 PARROT_BINDTEXTDOMAIN(PACKAGE, LOCALEDIR);
113 PARROT_TEXTDOMAIN(PACKAGE);
115 Parrot_set_config_hash();
117 interp = allocate_interpreter(NULL, PARROT_NO_FLAGS);
119 /* We parse the arguments, but first store away the name of the Parrot
120 executable, since parsing destroys that and we want to make it
121 available. */
122 execname = argv[0];
124 /* Parse minimal subset of flags */
125 parseflags_minimal(interp, argc, argv);
127 /* Now initialize interpreter */
128 initialize_interpreter(interp, (void*)&stacktop);
129 imcc_initialize(interp);
131 { /* EXPERIMENTAL: add library and include paths from environment */
132 PMC *env = Parrot_pmc_new(interp, enum_class_Env);
133 STRING *path = VTABLE_get_string_keyed_str(interp, env,
134 Parrot_str_new_constant(interp, "PARROT_LIBRARY"));
135 if (!Parrot_str_is_null(interp, path) && Parrot_str_length(interp, path) > 0)
136 Parrot_lib_add_path(interp, path, PARROT_LIB_PATH_LIBRARY);
137 path = VTABLE_get_string_keyed_str(interp, env,
138 Parrot_str_new_constant(interp, "PARROT_INCLUDE"));
139 if (!Parrot_str_is_null(interp, path) && Parrot_str_length(interp, path) > 0)
140 Parrot_lib_add_path(interp, path, PARROT_LIB_PATH_INCLUDE);
143 /* Parse flags */
144 sourcefile = parseflags(interp, &argc, &argv, &core, &trace);
146 Parrot_set_trace(interp, trace);
147 Parrot_set_run_core(interp, (Parrot_Run_core_t) core);
148 Parrot_set_executable_name(interp, Parrot_str_new(interp, execname, 0));
150 status = imcc_run(interp, sourcefile, argc, argv);
151 UNUSED(status);
153 /* Clean-up after ourselves */
154 Parrot_destroy(interp);
155 Parrot_exit(interp, 0);
158 #define OPT_GC_DEBUG 128
159 #define OPT_DESTROY_FLAG 129
160 #define OPT_HELP_DEBUG 130
161 #define OPT_PBC_OUTPUT 131
162 #define OPT_RUNTIME_PREFIX 132
164 #define SET_FLAG(flag) Parrot_set_flag(interp, (flag))
165 #define SET_DEBUG(flag) Parrot_set_debug(interp, (flag))
166 #define SET_TRACE(flag) Parrot_set_trace(interp, (flag))
168 static struct longopt_opt_decl options[] = {
169 { '.', '.', (OPTION_flags)0, { "--wait" } },
170 { 'D', 'D', OPTION_optional_FLAG, { "--parrot-debug" } },
171 { 'E', 'E', (OPTION_flags)0, { "--pre-process-only" } },
172 { 'G', 'G', (OPTION_flags)0, { "--no-gc" } },
173 { 'H', 'H', OPTION_required_FLAG, { "--hash-seed" } },
174 { 'I', 'I', OPTION_required_FLAG, { "--include" } },
175 { 'L', 'L', OPTION_required_FLAG, { "--library" } },
176 { 'O', 'O', OPTION_optional_FLAG, { "--optimize" } },
177 { 'R', 'R', OPTION_required_FLAG, { "--runcore" } },
178 { 'g', 'g', OPTION_required_FLAG, { "--gc" } },
179 { 'V', 'V', (OPTION_flags)0, { "--version" } },
180 { 'X', 'X', OPTION_required_FLAG, { "--dynext" } },
181 { '\0', OPT_DESTROY_FLAG, (OPTION_flags)0,
182 { "--leak-test", "--destroy-at-end" } },
183 { '\0', OPT_GC_DEBUG, (OPTION_flags)0, { "--gc-debug" } },
184 { 'a', 'a', (OPTION_flags)0, { "--pasm" } },
185 { 'c', 'c', (OPTION_flags)0, { "--pbc" } },
186 { 'd', 'd', OPTION_optional_FLAG, { "--imcc-debug" } },
187 { '\0', OPT_HELP_DEBUG, (OPTION_flags)0, { "--help-debug" } },
188 { 'h', 'h', (OPTION_flags)0, { "--help" } },
189 { 'o', 'o', OPTION_required_FLAG, { "--output" } },
190 { '\0', OPT_PBC_OUTPUT, (OPTION_flags)0, { "--output-pbc" } },
191 { 'r', 'r', (OPTION_flags)0, { "--run-pbc" } },
192 { '\0', OPT_RUNTIME_PREFIX, (OPTION_flags)0, { "--runtime-prefix" } },
193 { 't', 't', OPTION_optional_FLAG, { "--trace" } },
194 { 'v', 'v', (OPTION_flags)0, { "--verbose" } },
195 { 'w', 'w', (OPTION_flags)0, { "--warnings" } },
196 { 'y', 'y', (OPTION_flags)0, { "--yydebug" } },
197 { 0, 0, (OPTION_flags)0, { NULL } }
202 =item C<static int is_all_hex_digits(const char *s)>
204 Tests all characters in a string are hexadecimal digits.
205 Returns 1 if true, 0 as soon as a non-hex found
207 =cut
211 PARROT_WARN_UNUSED_RESULT
212 PARROT_PURE_FUNCTION
213 static int
214 is_all_hex_digits(ARGIN(const char *s))
216 ASSERT_ARGS(is_all_hex_digits)
217 for (; *s; s++)
218 if (!isxdigit(*s))
219 return 0;
220 return 1;
225 =item C<static void usage(FILE *fp)>
227 Outputs usage error message.
229 =cut
233 static void
234 usage(ARGMOD(FILE *fp))
236 ASSERT_ARGS(usage)
237 fprintf(fp,
238 "parrot -[acEGhprtvVwy.] [-d [FLAGS]] [-D [FLAGS]]"
239 "[-O [level]] [-R runcore] [-o FILE] <file>\n");
244 =item C<static void help_debug(void)>
246 Print out list of debugging flag values.
248 =cut
252 static void
253 help_debug(void)
255 ASSERT_ARGS(help_debug)
256 /* split printf for C89 compliance on string length */
257 printf(
258 "--imcc-debug -d [Flags] ...\n"
259 " 0002 lexer\n"
260 " 0004 parser\n"
261 " 0008 imc\n"
262 " 0010 CFG\n"
263 " 0020 optimization 1\n"
264 " 0040 optimization 2\n"
265 " 0100 AST\n"
266 " 1000 PBC\n"
267 " 2000 PBC constants\n"
268 " 4000 PBC fixups\n"
269 "\n");
270 printf(
271 "--parrot-debug -D [Flags] ...\n"
272 " 0001 memory statistics\n"
273 " 0002 print backtrace on exception\n"
274 " 0004 JIT debugging\n"
275 " 0008 interpreter startup\n"
276 " 0010 thread debugging\n"
277 " 0020 eval/compile\n"
278 " 0040 fill I, N registers with garbage\n"
279 " 0080 show when a context is destroyed\n"
280 "\n"
281 "--trace -t [Flags] ...\n"
282 " 0001 opcodes\n"
283 " 0002 find_method\n"
284 " 0004 function calls\n");
289 =item C<static void help(void)>
291 Print out "help" list of options.
293 =cut
297 static void
298 help(void)
300 ASSERT_ARGS(help)
301 /* split printf for C89 compliance on string length */
302 printf(
303 "parrot [Options] <file>\n"
304 " Options:\n"
305 " -h --help\n"
306 " -V --version\n"
307 " -I --include add path to include search\n"
308 " -L --library add path to library search\n"
309 " -H --hash-seed F00F specify hex value to use as hash seed\n"
310 " -X --dynext add path to dynamic extension search\n"
311 " <Run core options>\n"
312 " -R --runcore slow|bounds|fast|cgoto|cgp\n"
313 " -R --runcore switch|trace|profiling|gcdebug\n"
314 " -t --trace [flags]\n"
315 " <VM options>\n"
316 " -D --parrot-debug[=HEXFLAGS]\n"
317 " --help-debug\n");
318 printf(
319 " -w --warnings\n"
320 " -G --no-gc\n"
321 " --gc-debug\n"
322 " --leak-test|--destroy-at-end\n"
323 " -g --gc ms|inf set GC type\n"
324 " -. --wait Read a keystroke before starting\n"
325 " --runtime-prefix\n"
326 " <Compiler options>\n"
327 " -d --imcc-debug[=HEXFLAGS]\n"
328 " -v --verbose\n"
329 " -E --pre-process-only\n"
330 " -o --output=FILE\n"
331 " --output-pbc\n"
332 " -O --optimize[=LEVEL]\n"
333 " -a --pasm\n"
334 " -c --pbc\n"
335 " -r --run-pbc\n"
336 " -y --yydebug\n"
337 " <Language options>\n"
338 "see docs/running.pod for more\n");
344 =item C<static void Parrot_version(PARROT_INTERP)>
346 Print out parrot version number.
348 =cut
352 static void
353 Parrot_version(PARROT_INTERP)
355 ASSERT_ARGS(Parrot_version)
356 printf("This is Parrot version " PARROT_VERSION);
357 printf(" built for " PARROT_ARCHNAME ".\n");
358 printf("Copyright (C) 2001-2010, Parrot Foundation.\n\
360 This code is distributed under the terms of the Artistic License 2.0.\
362 For more details, see the full text of the license in the LICENSE file\
364 included in the Parrot source tree.\n\n");
366 exit(EXIT_SUCCESS);
371 =item C<static void parseflags_minimal(PARROT_INTERP, int argc, char *argv[])>
373 Parse minimal subset of args required for initializing interpreter.
375 =cut
378 static void
379 parseflags_minimal(PARROT_INTERP, int argc, ARGIN(char *argv[]))
381 ASSERT_ARGS(parseflags_minimal)
383 int pos = 0;
384 const char *arg;
385 while (pos < argc) {
386 arg = argv[pos];
387 if (STREQ(arg, "--gc")) {
388 ++pos;
389 if (pos == argc) {
390 fprintf(stderr,
391 "main: No GC specified."
392 "\n\nhelp: parrot -h\n");
393 exit(EXIT_FAILURE);
395 arg = argv[pos];
396 if (STREQ(arg, "ms"))
397 interp->gc_sys->sys_type = MS;
398 else if (STREQ(arg, "inf"))
399 interp->gc_sys->sys_type = INF;
400 else {
401 fprintf(stderr,
402 "main: Unrecognized GC '%s' specified."
403 "\n\nhelp: parrot -h\n", arg);
404 exit(EXIT_FAILURE);
406 break;
408 else if (STREQ(arg, "--hash-seed")) {
409 ++pos;
410 arg = argv[pos];
411 if (is_all_hex_digits(arg)) {
412 interp->hash_seed = strtoul(arg, NULL, 16);
415 ++pos;
421 =item C<static const char * parseflags(PARROT_INTERP, int *argc, char **argv[],
422 Parrot_Run_core_t *core, Parrot_trace_flags *trace)>
424 Parse Parrot's command line for options and set appropriate flags.
426 =cut
430 PARROT_CAN_RETURN_NULL
431 static const char *
432 parseflags(PARROT_INTERP,
433 ARGIN(int *argc), ARGIN(char **argv[]),
434 ARGIN(Parrot_Run_core_t *core), ARGIN(Parrot_trace_flags *trace))
436 ASSERT_ARGS(parseflags)
437 struct longopt_opt_info opt = LONGOPT_OPT_INFO_INIT;
438 int status;
439 /* g++ complains if we cast char** to const char** directly. However, nobody
440 ever complains if you const to void* first. Sure we lose a certain
441 amount of compiler-enforced type safety, but this is a rare occasion
442 with a very long explanatory comment. */
443 const char ** const _tempargv = (const char **)((void *)*argv);
445 if (*argc == 1) {
446 usage(stderr);
447 exit(EXIT_SUCCESS);
450 imcc_start_handling_flags(interp);
452 while ((status = longopt_get(interp, *argc, _tempargv, options,
453 &opt)) > 0) {
454 switch (opt.opt_id) {
455 case 'R':
456 if (STREQ(opt.opt_arg, "slow") || STREQ(opt.opt_arg, "bounds"))
457 *core = PARROT_SLOW_CORE;
458 else if (STREQ(opt.opt_arg, "fast") || STREQ(opt.opt_arg, "function"))
459 *core = PARROT_FAST_CORE;
460 else if (STREQ(opt.opt_arg, "switch"))
461 *core = PARROT_SWITCH_CORE;
462 else if (STREQ(opt.opt_arg, "cgp"))
463 *core = PARROT_CGP_CORE;
464 else if (STREQ(opt.opt_arg, "cgoto"))
465 *core = PARROT_CGOTO_CORE;
466 else if (STREQ(opt.opt_arg, "jit"))
467 *core = PARROT_FAST_CORE;
468 else if (STREQ(opt.opt_arg, "cgp-jit"))
469 *core = PARROT_CGP_CORE;
470 else if (STREQ(opt.opt_arg, "switch-jit"))
471 *core = PARROT_SWITCH_CORE;
472 else if (STREQ(opt.opt_arg, "exec"))
473 *core = PARROT_EXEC_CORE;
474 else if (STREQ(opt.opt_arg, "trace"))
475 *core = PARROT_SLOW_CORE;
476 else if (STREQ(opt.opt_arg, "profiling"))
477 *core = PARROT_PROFILING_CORE;
478 else if (STREQ(opt.opt_arg, "gcdebug"))
479 *core = PARROT_GC_DEBUG_CORE;
480 else {
481 fprintf(stderr,
482 "main: Unrecognized runcore '%s' specified."
483 "\n\nhelp: parrot -h\n", opt.opt_arg);
484 exit(EXIT_FAILURE);
486 break;
487 case 'g':
488 /* Handled in parseflags_minimal */
489 break;
490 case 't':
491 if (opt.opt_arg && is_all_hex_digits(opt.opt_arg)) {
492 const unsigned long _temp = strtoul(opt.opt_arg, NULL, 16);
493 const Parrot_trace_flags _temp_flag = (Parrot_trace_flags)_temp;
494 *trace = _temp_flag;
496 else
497 *trace = PARROT_TRACE_OPS_FLAG;
498 break;
499 case 'D':
500 if (opt.opt_arg && is_all_hex_digits(opt.opt_arg)) {
501 SET_DEBUG(strtoul(opt.opt_arg, NULL, 16));
503 else
504 SET_DEBUG(PARROT_MEM_STAT_DEBUG_FLAG);
505 break;
507 case '.': /* Give Windows Parrot hackers an opportunity to
508 * attach a debuggger. */
509 fgetc(stdin);
510 break;
511 case 'h':
512 help();
513 exit(EXIT_FAILURE);
514 break;
515 case 'H':
516 /* handled in parseflags_minimal */
517 break;
518 case OPT_HELP_DEBUG:
519 help_debug();
520 exit(EXIT_FAILURE);
521 break;
522 case OPT_RUNTIME_PREFIX:
523 Parrot_io_printf(interp, "%Ss\n",
524 Parrot_get_runtime_path(interp));
525 exit(EXIT_SUCCESS);
526 case 'V':
527 Parrot_version(interp);
528 break;
530 case OPT_GC_DEBUG:
531 #if DISABLE_GC_DEBUG
532 Parrot_warn(interp, PARROT_WARNINGS_ALL_FLAG,
533 "PARROT_GC_DEBUG is set but the binary was compiled "
534 "with DISABLE_GC_DEBUG.");
535 #endif
536 SET_FLAG(PARROT_GC_DEBUG_FLAG);
537 break;
538 case OPT_DESTROY_FLAG:
539 SET_FLAG(PARROT_DESTROY_FLAG);
540 break;
541 case 'I':
542 Parrot_lib_add_path_from_cstring(interp, opt.opt_arg,
543 PARROT_LIB_PATH_INCLUDE);
544 break;
545 case 'L':
546 Parrot_lib_add_path_from_cstring(interp, opt.opt_arg,
547 PARROT_LIB_PATH_LIBRARY);
548 break;
549 case 'X':
550 Parrot_lib_add_path_from_cstring(interp, opt.opt_arg,
551 PARROT_LIB_PATH_DYNEXT);
552 break;
553 default:
554 /* Delegate handling of IMCC flags to IMCC */
555 if (imcc_handle_flag(interp, &opt, core))
556 break;
558 /* PIRC flags handling goes here */
559 fprintf(stderr,
560 "main: Invalid flag '%s' used.\n\nhelp: parrot -h\n",
561 (*argv)[0]);
562 exit(EXIT_FAILURE);
566 if (status == -1) {
567 fprintf(stderr, "%s\n", opt.opt_error);
568 usage(stderr);
569 exit(EXIT_FAILURE);
572 /* reached the end of the option list and consumed all of argv */
573 if (*argc == opt.opt_index) {
574 if (interp->output_file) {
575 fprintf(stderr, "Missing program name or argument for -o\n");
577 else {
578 /* We are not looking at an option, so it must be a program name */
579 fprintf(stderr, "Missing program name\n");
581 usage(stderr);
582 exit(EXIT_FAILURE);
585 *argc -= opt.opt_index;
586 *argv += opt.opt_index;
588 return (*argv)[0];
592 =back
594 =head1 SEE ALSO
596 F<compilers/imcc/main.c>, unfortunately.
598 =cut
603 * Local variables:
604 * c-file-style: "parrot"
605 * End:
606 * vim: expandtab shiftwidth=4: