Coverage Report

Created: 2022-07-08 09:39

/home/mdboom/Work/builds/cpython/Modules/main.c
Line
Count
Source (jump to first uncovered line)
1
/* Python interpreter main program */
2
3
#include "Python.h"
4
#include "pycore_call.h"          // _PyObject_CallNoArgs()
5
#include "pycore_initconfig.h"    // _PyArgv
6
#include "pycore_interp.h"        // _PyInterpreterState.sysdict
7
#include "pycore_pathconfig.h"    // _PyPathConfig_ComputeSysPath0()
8
#include "pycore_pylifecycle.h"   // _Py_PreInitializeFromPyArgv()
9
#include "pycore_pystate.h"       // _PyInterpreterState_GET()
10
11
/* Includes for exit_sigint() */
12
#include <stdio.h>                // perror()
13
#ifdef HAVE_SIGNAL_H
14
#  include <signal.h>             // SIGINT
15
#endif
16
#if defined(HAVE_GETPID) && defined(HAVE_UNISTD_H)
17
#  include <unistd.h>             // getpid()
18
#endif
19
#ifdef MS_WINDOWS
20
#  include <windows.h>            // STATUS_CONTROL_C_EXIT
21
#endif
22
/* End of includes for exit_sigint() */
23
24
#define COPYRIGHT \
25
    "Type \"help\", \"copyright\", \"credits\" or \"license\" " \
26
    "for more information."
27
28
#ifdef __cplusplus
29
extern "C" {
30
#endif
31
32
/* --- pymain_init() ---------------------------------------------- */
33
34
static PyStatus
35
pymain_init(const _PyArgv *args)
36
{
37
    PyStatus status;
38
39
    status = _PyRuntime_Initialize();
40
    if (_PyStatus_EXCEPTION(status)) {
41
        return status;
42
    }
43
44
    PyPreConfig preconfig;
45
    PyPreConfig_InitPythonConfig(&preconfig);
46
47
    status = _Py_PreInitializeFromPyArgv(&preconfig, args);
48
    if (_PyStatus_EXCEPTION(status)) {
49
        return status;
50
    }
51
52
    PyConfig config;
53
    PyConfig_InitPythonConfig(&config);
54
55
    /* pass NULL as the config: config is read from command line arguments,
56
       environment variables, configuration files */
57
    if (args->use_bytes_argv) {
  Branch (57:9): [True: 11, False: 3]
58
        status = PyConfig_SetBytesArgv(&config, args->argc, args->bytes_argv);
59
    }
60
    else {
61
        status = PyConfig_SetArgv(&config, args->argc, args->wchar_argv);
62
    }
63
    if (_PyStatus_EXCEPTION(status)) {
64
        goto done;
65
    }
66
67
    status = Py_InitializeFromConfig(&config);
68
    if (_PyStatus_EXCEPTION(status)) {
69
        goto done;
70
    }
71
    status = _PyStatus_OK();
72
73
done:
74
    PyConfig_Clear(&config);
75
    return status;
76
}
77
78
79
/* --- pymain_run_python() ---------------------------------------- */
80
81
/* Non-zero if filename, command (-c) or module (-m) is set
82
   on the command line */
83
static inline int config_run_code(const PyConfig *config)
84
{
85
    return (config->run_command != NULL
  Branch (85:13): [True: 44, False: 7]
86
            || 
config->run_filename != NULL7
  Branch (86:16): [True: 2, False: 5]
87
            || 
config->run_module != NULL5
);
  Branch (87:16): [True: 2, False: 3]
88
}
89
90
91
/* Return non-zero if stdin is a TTY or if -i command line option is used */
92
static int
93
stdin_is_interactive(const PyConfig *config)
94
{
95
    return (isatty(fileno(stdin)) || 
config->interactive0
);
  Branch (95:13): [True: 3, False: 0]
  Branch (95:38): [True: 0, False: 0]
96
}
97
98
99
/* Display the current Python exception and return an exitcode */
100
static int
101
pymain_err_print(int *exitcode_p)
102
{
103
    int exitcode;
104
    if (_Py_HandleSystemExit(&exitcode)) {
  Branch (104:9): [True: 1, False: 3]
105
        *exitcode_p = exitcode;
106
        return 1;
107
    }
108
109
    PyErr_Print();
110
    return 0;
111
}
112
113
114
static int
115
pymain_exit_err_print(void)
116
{
117
    int exitcode = 1;
118
    pymain_err_print(&exitcode);
119
    return exitcode;
120
}
121
122
123
/* Write an exitcode into *exitcode and return 1 if we have to exit Python.
124
   Return 0 otherwise. */
125
static int
126
pymain_get_importer(const wchar_t *filename, PyObject **importer_p, int *exitcode)
127
{
128
    PyObject *sys_path0 = NULL, *importer;
129
130
    sys_path0 = PyUnicode_FromWideChar(filename, wcslen(filename));
131
    if (sys_path0 == NULL) {
  Branch (131:9): [True: 0, False: 1]
132
        goto error;
133
    }
134
135
    importer = PyImport_GetImporter(sys_path0);
136
    if (importer == NULL) {
  Branch (136:9): [True: 0, False: 1]
137
        goto error;
138
    }
139
140
    if (importer == Py_None) {
  Branch (140:9): [True: 1, False: 0]
141
        Py_DECREF(sys_path0);
142
        Py_DECREF(importer);
143
        return 0;
144
    }
145
146
    Py_DECREF(importer);
147
    *importer_p = sys_path0;
148
    return 0;
149
150
error:
151
    Py_XDECREF(sys_path0);
152
153
    PySys_WriteStderr("Failed checking if argv[0] is an import path entry\n");
154
    return pymain_err_print(exitcode);
155
}
156
157
158
static int
159
pymain_sys_path_add_path0(PyInterpreterState *interp, PyObject *path0)
160
{
161
    PyObject *sys_path;
162
    PyObject *sysdict = interp->sysdict;
163
    if (sysdict != NULL) {
  Branch (163:9): [True: 25, False: 0]
164
        sys_path = PyDict_GetItemWithError(sysdict, &_Py_ID(path));
165
        if (sys_path == NULL && 
PyErr_Occurred()0
) {
  Branch (165:13): [True: 0, False: 25]
  Branch (165:33): [True: 0, False: 0]
166
            return -1;
167
        }
168
    }
169
    else {
170
        sys_path = NULL;
171
    }
172
    if (sys_path == NULL) {
  Branch (172:9): [True: 0, False: 25]
173
        PyErr_SetString(PyExc_RuntimeError, "unable to get sys.path");
174
        return -1;
175
    }
176
177
    if (PyList_Insert(sys_path, 0, path0)) {
  Branch (177:9): [True: 0, False: 25]
178
        return -1;
179
    }
180
    return 0;
181
}
182
183
184
static void
185
pymain_header(const PyConfig *config)
186
{
187
    if (config->quiet) {
  Branch (187:9): [True: 3, False: 26]
188
        return;
189
    }
190
191
    if (!config->verbose && (config_run_code(config) || 
!stdin_is_interactive(config)0
)) {
  Branch (191:9): [True: 26, False: 0]
  Branch (191:30): [True: 26, False: 0]
  Branch (191:57): [True: 0, False: 0]
192
        return;
193
    }
194
195
    fprintf(stderr, "Python %s on %s\n", Py_GetVersion(), Py_GetPlatform());
196
    if (config->site_import) {
  Branch (196:9): [True: 0, False: 0]
197
        fprintf(stderr, "%s\n", COPYRIGHT);
198
    }
199
}
200
201
202
static void
203
pymain_import_readline(const PyConfig *config)
204
{
205
    if (config->isolated) {
  Branch (205:9): [True: 4, False: 25]
206
        return;
207
    }
208
    if (!config->inspect && config_run_code(config)) {
  Branch (208:9): [True: 25, False: 0]
  Branch (208:29): [True: 22, False: 3]
209
        return;
210
    }
211
    if (!isatty(fileno(stdin))) {
  Branch (211:9): [True: 0, False: 3]
212
        return;
213
    }
214
215
    PyObject *mod = PyImport_ImportModule("readline");
216
    if (mod == NULL) {
  Branch (216:9): [True: 0, False: 3]
217
        PyErr_Clear();
218
    }
219
    else {
220
        Py_DECREF(mod);
221
    }
222
    mod = PyImport_ImportModule("rlcompleter");
223
    if (mod == NULL) {
  Branch (223:9): [True: 0, False: 3]
224
        PyErr_Clear();
225
    }
226
    else {
227
        Py_DECREF(mod);
228
    }
229
}
230
231
232
static int
233
pymain_run_command(wchar_t *command)
234
{
235
    PyObject *unicode, *bytes;
236
    int ret;
237
238
    unicode = PyUnicode_FromWideChar(command, -1);
239
    if (unicode == NULL) {
  Branch (239:9): [True: 0, False: 24]
240
        goto error;
241
    }
242
243
    if (PySys_Audit("cpython.run_command", "O", unicode) < 0) {
  Branch (243:9): [True: 1, False: 23]
244
        return pymain_exit_err_print();
245
    }
246
247
    bytes = PyUnicode_AsUTF8String(unicode);
248
    Py_DECREF(unicode);
249
    if (bytes == NULL) {
  Branch (249:9): [True: 0, False: 23]
250
        goto error;
251
    }
252
253
    PyCompilerFlags cf = _PyCompilerFlags_INIT;
254
    cf.cf_flags |= PyCF_IGNORE_COOKIE;
255
    ret = PyRun_SimpleStringFlags(PyBytes_AsString(bytes), &cf);
256
    Py_DECREF(bytes);
257
    return (ret != 0);
258
259
error:
260
    PySys_WriteStderr("Unable to decode the command from the command line:\n");
261
    return pymain_exit_err_print();
262
}
263
264
265
static int
266
pymain_run_module(const wchar_t *modname, int set_argv0)
267
{
268
    PyObject *module, *runpy, *runmodule, *runargs, *result;
269
    if (PySys_Audit("cpython.run_module", "u", modname) < 0) {
  Branch (269:9): [True: 0, False: 1]
270
        return pymain_exit_err_print();
271
    }
272
    runpy = PyImport_ImportModule("runpy");
273
    if (runpy == NULL) {
  Branch (273:9): [True: 0, False: 1]
274
        fprintf(stderr, "Could not import runpy module\n");
275
        return pymain_exit_err_print();
276
    }
277
    runmodule = PyObject_GetAttrString(runpy, "_run_module_as_main");
278
    if (runmodule == NULL) {
  Branch (278:9): [True: 0, False: 1]
279
        fprintf(stderr, "Could not access runpy._run_module_as_main\n");
280
        Py_DECREF(runpy);
281
        return pymain_exit_err_print();
282
    }
283
    module = PyUnicode_FromWideChar(modname, wcslen(modname));
284
    if (module == NULL) {
  Branch (284:9): [True: 0, False: 1]
285
        fprintf(stderr, "Could not convert module name to unicode\n");
286
        Py_DECREF(runpy);
287
        Py_DECREF(runmodule);
288
        return pymain_exit_err_print();
289
    }
290
    runargs = PyTuple_Pack(2, module, set_argv0 ? Py_True : Py_False);
  Branch (290:39): [True: 1, False: 0]
291
    if (runargs == NULL) {
  Branch (291:9): [True: 0, False: 1]
292
        fprintf(stderr,
293
            "Could not create arguments for runpy._run_module_as_main\n");
294
        Py_DECREF(runpy);
295
        Py_DECREF(runmodule);
296
        Py_DECREF(module);
297
        return pymain_exit_err_print();
298
    }
299
    _Py_UnhandledKeyboardInterrupt = 0;
300
    result = PyObject_Call(runmodule, runargs, NULL);
301
    if (!result && PyErr_Occurred() == PyExc_KeyboardInterrupt) {
  Branch (301:9): [True: 1, False: 0]
  Branch (301:20): [True: 0, False: 1]
302
        _Py_UnhandledKeyboardInterrupt = 1;
303
    }
304
    Py_DECREF(runpy);
305
    Py_DECREF(runmodule);
306
    Py_DECREF(module);
307
    Py_DECREF(runargs);
308
    if (result == NULL) {
  Branch (308:9): [True: 1, False: 0]
309
        return pymain_exit_err_print();
310
    }
311
    Py_DECREF(result);
312
    return 0;
313
}
314
315
316
static int
317
pymain_run_file_obj(PyObject *program_name, PyObject *filename,
318
                    int skip_source_first_line)
319
{
320
    if (PySys_Audit("cpython.run_file", "O", filename) < 0) {
  Branch (320:9): [True: 1, False: 0]
321
        return pymain_exit_err_print();
322
    }
323
324
    FILE *fp = _Py_fopen_obj(filename, "rb");
325
    if (fp == NULL) {
  Branch (325:9): [True: 0, False: 0]
326
        // Ignore the OSError
327
        PyErr_Clear();
328
        PySys_FormatStderr("%S: can't open file %R: [Errno %d] %s\n",
329
                           program_name, filename, errno, strerror(errno));
330
        return 2;
331
    }
332
333
    if (skip_source_first_line) {
  Branch (333:9): [True: 0, False: 0]
334
        int ch;
335
        /* Push back first newline so line numbers remain the same */
336
        while ((ch = getc(fp)) != EOF) {
  Branch (336:16): [True: 0, False: 0]
337
            if (ch == '\n') {
  Branch (337:17): [True: 0, False: 0]
338
                (void)ungetc(ch, fp);
339
                break;
340
            }
341
        }
342
    }
343
344
    struct _Py_stat_struct sb;
345
    if (_Py_fstat_noraise(fileno(fp), &sb) == 0 && S_ISDIR(sb.st_mode)) {
  Branch (345:9): [True: 0, False: 0]
346
        PySys_FormatStderr("%S: %R is a directory, cannot continue\n",
347
                           program_name, filename);
348
        fclose(fp);
349
        return 1;
350
    }
351
352
    // Call pending calls like signal handlers (SIGINT)
353
    if (Py_MakePendingCalls() == -1) {
  Branch (353:9): [True: 0, False: 0]
354
        fclose(fp);
355
        return pymain_exit_err_print();
356
    }
357
358
    /* PyRun_AnyFileExFlags(closeit=1) calls fclose(fp) before running code */
359
    PyCompilerFlags cf = _PyCompilerFlags_INIT;
360
    int run = _PyRun_AnyFileObject(fp, filename, 1, &cf);
361
    return (run != 0);
362
}
363
364
static int
365
pymain_run_file(const PyConfig *config)
366
{
367
    PyObject *filename = PyUnicode_FromWideChar(config->run_filename, -1);
368
    if (filename == NULL) {
  Branch (368:9): [True: 0, False: 1]
369
        PyErr_Print();
370
        return -1;
371
    }
372
    PyObject *program_name = PyUnicode_FromWideChar(config->program_name, -1);
373
    if (program_name == NULL) {
  Branch (373:9): [True: 0, False: 1]
374
        Py_DECREF(filename);
375
        PyErr_Print();
376
        return -1;
377
    }
378
379
    int res = pymain_run_file_obj(program_name, filename,
380
                                  config->skip_source_first_line);
381
    Py_DECREF(filename);
382
    Py_DECREF(program_name);
383
    return res;
384
}
385
386
387
static int
388
pymain_run_startup(PyConfig *config, int *exitcode)
389
{
390
    int ret;
391
    if (!config->use_environment) {
  Branch (391:9): [True: 0, False: 3]
392
        return 0;
393
    }
394
    PyObject *startup = NULL;
395
#ifdef MS_WINDOWS
396
    const wchar_t *env = _wgetenv(L"PYTHONSTARTUP");
397
    if (env == NULL || env[0] == L'\0') {
398
        return 0;
399
    }
400
    startup = PyUnicode_FromWideChar(env, wcslen(env));
401
    if (startup == NULL) {
402
        goto error;
403
    }
404
#else
405
    const char *env = _Py_GetEnv(config->use_environment, "PYTHONSTARTUP");
406
    if (env == NULL) {
  Branch (406:9): [True: 1, False: 2]
407
        return 0;
408
    }
409
    startup = PyUnicode_DecodeFSDefault(env);
410
    if (startup == NULL) {
  Branch (410:9): [True: 0, False: 2]
411
        goto error;
412
    }
413
#endif
414
    if (PySys_Audit("cpython.run_startup", "O", startup) < 0) {
  Branch (414:9): [True: 0, False: 2]
415
        goto error;
416
    }
417
418
    FILE *fp = _Py_fopen_obj(startup, "r");
419
    if (fp == NULL) {
  Branch (419:9): [True: 0, False: 2]
420
        int save_errno = errno;
421
        PyErr_Clear();
422
        PySys_WriteStderr("Could not open PYTHONSTARTUP\n");
423
424
        errno = save_errno;
425
        PyErr_SetFromErrnoWithFilenameObjects(PyExc_OSError, startup, NULL);
426
        goto error;
427
    }
428
429
    PyCompilerFlags cf = _PyCompilerFlags_INIT;
430
    (void) _PyRun_SimpleFileObject(fp, startup, 0, &cf);
431
    PyErr_Clear();
432
    fclose(fp);
433
    ret = 0;
434
435
done:
436
    Py_XDECREF(startup);
437
    return ret;
438
439
error:
440
    ret = pymain_err_print(exitcode);
441
    goto done;
442
}
443
444
445
/* Write an exitcode into *exitcode and return 1 if we have to exit Python.
446
   Return 0 otherwise. */
447
static int
448
pymain_run_interactive_hook(int *exitcode)
449
{
450
    PyObject *sys, *hook, *result;
451
    sys = PyImport_ImportModule("sys");
452
    if (sys == NULL) {
  Branch (452:9): [True: 0, False: 2]
453
        goto error;
454
    }
455
456
    hook = PyObject_GetAttrString(sys, "__interactivehook__");
457
    Py_DECREF(sys);
458
    if (hook == NULL) {
  Branch (458:9): [True: 0, False: 2]
459
        PyErr_Clear();
460
        return 0;
461
    }
462
463
    if (PySys_Audit("cpython.run_interactivehook", "O", hook) < 0) {
  Branch (463:9): [True: 0, False: 2]
464
        goto error;
465
    }
466
467
    result = _PyObject_CallNoArgs(hook);
468
    Py_DECREF(hook);
469
    if (result == NULL) {
  Branch (469:9): [True: 0, False: 2]
470
        goto error;
471
    }
472
    Py_DECREF(result);
473
474
    return 0;
475
476
error:
477
    PySys_WriteStderr("Failed calling sys.__interactivehook__\n");
478
    return pymain_err_print(exitcode);
479
}
480
481
482
static void
483
pymain_set_inspect(PyConfig *config, int inspect)
484
{
485
    config->inspect = inspect;
486
_Py_COMP_DIAG_PUSH
487
_Py_COMP_DIAG_IGNORE_DEPR_DECLS
488
    Py_InspectFlag = inspect;
489
_Py_COMP_DIAG_POP
490
}
491
492
493
static int
494
pymain_run_stdin(PyConfig *config)
495
{
496
    if (stdin_is_interactive(config)) {
  Branch (496:9): [True: 3, False: 0]
497
        // do exit on SystemExit
498
        pymain_set_inspect(config, 0);
499
500
        int exitcode;
501
        if (pymain_run_startup(config, &exitcode)) {
  Branch (501:13): [True: 0, False: 3]
502
            return exitcode;
503
        }
504
505
        if (pymain_run_interactive_hook(&exitcode)) {
  Branch (505:13): [True: 0, False: 3]
506
            return exitcode;
507
        }
508
    }
509
510
    /* call pending calls like signal handlers (SIGINT) */
511
    if (Py_MakePendingCalls() == -1) {
  Branch (511:9): [True: 0, False: 3]
512
        return pymain_exit_err_print();
513
    }
514
515
    if (PySys_Audit("cpython.run_stdin", NULL) < 0) {
  Branch (515:9): [True: 1, False: 2]
516
        return pymain_exit_err_print();
517
    }
518
519
    PyCompilerFlags cf = _PyCompilerFlags_INIT;
520
    int run = PyRun_AnyFileExFlags(stdin, "<stdin>", 0, &cf);
521
    return (run != 0);
522
}
523
524
525
static void
526
pymain_repl(PyConfig *config, int *exitcode)
527
{
528
    /* Check this environment variable at the end, to give programs the
529
       opportunity to set it from Python. */
530
    if (!config->inspect && _Py_GetEnv(config->use_environment, "PYTHONINSPECT")) {
  Branch (530:9): [True: 21, False: 0]
  Branch (530:29): [True: 0, False: 21]
531
        pymain_set_inspect(config, 1);
532
    }
533
534
    if (!(config->inspect && 
stdin_is_interactive(config)0
&&
config_run_code(config)0
)) {
  Branch (534:11): [True: 0, False: 21]
  Branch (534:30): [True: 0, False: 0]
  Branch (534:62): [True: 0, False: 0]
535
        return;
536
    }
537
538
    pymain_set_inspect(config, 0);
539
    if (pymain_run_interactive_hook(exitcode)) {
  Branch (539:9): [True: 0, False: 0]
540
        return;
541
    }
542
543
    PyCompilerFlags cf = _PyCompilerFlags_INIT;
544
    int res = PyRun_AnyFileFlags(stdin, "<stdin>", &cf);
545
    *exitcode = (res != 0);
546
}
547
548
549
static void
550
pymain_run_python(int *exitcode)
551
{
552
    PyObject *main_importer_path = NULL;
553
    PyInterpreterState *interp = _PyInterpreterState_GET();
554
    /* pymain_run_stdin() modify the config */
555
    PyConfig *config = (PyConfig*)_PyInterpreterState_GetConfig(interp);
556
557
    /* ensure path config is written into global variables */
558
    if (_PyStatus_EXCEPTION(_PyPathConfig_UpdateGlobal(config))) {
559
        goto error;
560
    }
561
562
    if (config->run_filename != NULL) {
  Branch (562:9): [True: 1, False: 28]
563
        /* If filename is a package (ex: directory or ZIP file) which contains
564
           __main__.py, main_importer_path is set to filename and will be
565
           prepended to sys.path.
566
567
           Otherwise, main_importer_path is left unchanged. */
568
        if (pymain_get_importer(config->run_filename, &main_importer_path,
  Branch (568:13): [True: 0, False: 1]
569
                                exitcode)) {
570
            return;
571
        }
572
    }
573
574
    // import readline and rlcompleter before script dir is added to sys.path
575
    pymain_import_readline(config);
576
577
    if (main_importer_path != NULL) {
  Branch (577:9): [True: 0, False: 29]
578
        if (pymain_sys_path_add_path0(interp, main_importer_path) < 0) {
  Branch (578:13): [True: 0, False: 0]
579
            goto error;
580
        }
581
    }
582
    else if (!config->safe_path) {
  Branch (582:14): [True: 25, False: 4]
583
        PyObject *path0 = NULL;
584
        int res = _PyPathConfig_ComputeSysPath0(&config->argv, &path0);
585
        if (res < 0) {
  Branch (585:13): [True: 0, False: 25]
586
            goto error;
587
        }
588
589
        if (res > 0) {
  Branch (589:13): [True: 25, False: 0]
590
            if (pymain_sys_path_add_path0(interp, path0) < 0) {
  Branch (590:17): [True: 0, False: 25]
591
                Py_DECREF(path0);
592
                goto error;
593
            }
594
            Py_DECREF(path0);
595
        }
596
    }
597
598
    pymain_header(config);
599
600
    if (config->run_command) {
  Branch (600:9): [True: 24, False: 5]
601
        *exitcode = pymain_run_command(config->run_command);
602
    }
603
    else if (config->run_module) {
  Branch (603:14): [True: 1, False: 4]
604
        *exitcode = pymain_run_module(config->run_module, 1);
605
    }
606
    else if (main_importer_path != NULL) {
  Branch (606:14): [True: 0, False: 4]
607
        *exitcode = pymain_run_module(L"__main__", 0);
608
    }
609
    else if (config->run_filename != NULL) {
  Branch (609:14): [True: 1, False: 3]
610
        *exitcode = pymain_run_file(config);
611
    }
612
    else {
613
        *exitcode = pymain_run_stdin(config);
614
    }
615
616
    pymain_repl(config, exitcode);
617
    goto done;
618
619
error:
620
    *exitcode = pymain_exit_err_print();
621
622
done:
623
    Py_XDECREF(main_importer_path);
624
}
625
626
627
/* --- pymain_main() ---------------------------------------------- */
628
629
static void
630
pymain_free(void)
631
{
632
    _PyImport_Fini2();
633
634
    /* Free global variables which cannot be freed in Py_Finalize():
635
       configuration options set before Py_Initialize() which should
636
       remain valid after Py_Finalize(), since
637
       Py_Initialize()-Py_Finalize() can be called multiple times. */
638
    _PyPathConfig_ClearGlobal();
639
    _Py_ClearStandardStreamEncoding();
640
    _Py_ClearArgcArgv();
641
    _PyRuntime_Finalize();
642
}
643
644
645
static int
646
exit_sigint(void)
647
{
648
    /* bpo-1054041: We need to exit via the
649
     * SIG_DFL handler for SIGINT if KeyboardInterrupt went unhandled.
650
     * If we don't, a calling process such as a shell may not know
651
     * about the user's ^C.  https://www.cons.org/cracauer/sigint.html */
652
#if defined(HAVE_GETPID) && !defined(MS_WINDOWS)
653
    if (PyOS_setsig(SIGINT, SIG_DFL) == SIG_ERR) {
  Branch (653:9): [True: 0, False: 0]
654
        perror("signal");  /* Impossible in normal environments. */
655
    } else {
656
        kill(getpid(), SIGINT);
657
    }
658
    /* If setting SIG_DFL failed, or kill failed to terminate us,
659
     * there isn't much else we can do aside from an error code. */
660
#endif  /* HAVE_GETPID && !MS_WINDOWS */
661
#ifdef MS_WINDOWS
662
    /* cmd.exe detects this, prints ^C, and offers to terminate. */
663
    /* https://msdn.microsoft.com/en-us/library/cc704588.aspx */
664
    return STATUS_CONTROL_C_EXIT;
665
#else
666
    return SIGINT + 128;
667
#endif  /* !MS_WINDOWS */
668
}
669
670
671
static void _Py_NO_RETURN
672
pymain_exit_error(PyStatus status)
673
{
674
    if (_PyStatus_IS_EXIT(status)) {
675
        /* If it's an error rather than a regular exit, leave Python runtime
676
           alive: Py_ExitStatusException() uses the current exception and use
677
           sys.stdout in this case. */
678
        pymain_free();
679
    }
680
    Py_ExitStatusException(status);
681
}
682
683
684
int
685
Py_RunMain(void)
686
{
687
    int exitcode = 0;
688
689
    pymain_run_python(&exitcode);
690
691
    if (Py_FinalizeEx() < 0) {
  Branch (691:9): [True: 0, False: 29]
692
        /* Value unlikely to be confused with a non-error exit status or
693
           other special meaning */
694
        exitcode = 120;
695
    }
696
697
    pymain_free();
698
699
    if (_Py_UnhandledKeyboardInterrupt) {
  Branch (699:9): [True: 0, False: 29]
700
        exitcode = exit_sigint();
701
    }
702
703
    return exitcode;
704
}
705
706
707
static int
708
pymain_main(_PyArgv *args)
709
{
710
    PyStatus status = pymain_init(args);
711
    if (_PyStatus_IS_EXIT(status)) {
712
        pymain_free();
713
        return status.exitcode;
714
    }
715
    if (_PyStatus_EXCEPTION(status)) {
716
        pymain_exit_error(status);
717
    }
718
719
    return Py_RunMain();
720
}
721
722
723
int
724
Py_Main(int argc, wchar_t **argv)
725
{
726
    _PyArgv args = {
727
        .argc = argc,
728
        .use_bytes_argv = 0,
729
        .bytes_argv = NULL,
730
        .wchar_argv = argv};
731
    return pymain_main(&args);
732
}
733
734
735
int
736
Py_BytesMain(int argc, char **argv)
737
{
738
    _PyArgv args = {
739
        .argc = argc,
740
        .use_bytes_argv = 1,
741
        .bytes_argv = argv,
742
        .wchar_argv = NULL};
743
    return pymain_main(&args);
744
}
745
746
#ifdef __cplusplus
747
}
748
#endif