Skip to content

Commit d5dda98

Browse files
authored
pymain_set_sys_argv() now copies argv (#4838)
bpo-29240, bpo-32030: * Rename pymain_set_argv() to pymain_set_sys_argv() * pymain_set_sys_argv() now creates of copy of argv and modify the copy, rather than modifying pymain->argv * Call pymain_set_sys_argv() earlier: before pymain_run_python(), but after pymain_get_importer(). * Add _PySys_SetArgvWithError() to handle errors
1 parent 9814697 commit d5dda98

File tree

3 files changed

+88
-35
lines changed

3 files changed

+88
-35
lines changed

Include/sysmodule.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@ PyAPI_FUNC(int) _PySys_SetObjectId(_Py_Identifier *key, PyObject *);
1616

1717
PyAPI_FUNC(void) PySys_SetArgv(int, wchar_t **);
1818
PyAPI_FUNC(void) PySys_SetArgvEx(int, wchar_t **, int);
19+
#ifdef Py_BUILD_CORE
20+
PyAPI_FUNC(_PyInitError) _PySys_SetArgvWithError(
21+
int argc,
22+
wchar_t **argv,
23+
int updatepath);
24+
#endif
1925
PyAPI_FUNC(void) PySys_SetPath(const wchar_t *);
2026

2127
PyAPI_FUNC(void) PySys_WriteStdout(const char *format, ...)

Modules/main.c

Lines changed: 58 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -434,14 +434,11 @@ typedef struct {
434434

435435
/* .cmdline is initialized to zeros */
436436
#define _PyMain_INIT \
437-
{.status = 0, \
438-
.cf = {.cf_flags = 0}, \
439-
.core_config = _PyCoreConfig_INIT, \
437+
{.core_config = _PyCoreConfig_INIT, \
440438
.config = _PyMainInterpreterConfig_INIT, \
441-
.main_importer_path = NULL, \
442439
.run_code = -1, \
443-
.err = _Py_INIT_OK(), \
444-
.env_warning_options = {0, NULL}}
440+
.err = _Py_INIT_OK()}
441+
/* Note: _PyMain_INIT sets other fields to 0/NULL */
445442

446443

447444
static void
@@ -738,6 +735,9 @@ pymain_parse_cmdline_impl(_PyMain *pymain)
738735
cmdline->filename = pymain->argv[_PyOS_optind];
739736
}
740737

738+
/* -c and -m options are exclusive */
739+
assert(!(cmdline->command != NULL && cmdline->module != NULL));
740+
741741
return 0;
742742
}
743743

@@ -1082,22 +1082,34 @@ pymain_header(_PyMain *pymain)
10821082
}
10831083

10841084

1085-
static void
1086-
pymain_set_argv(_PyMain *pymain)
1085+
static int
1086+
pymain_set_sys_argv(_PyMain *pymain)
10871087
{
10881088
_Py_CommandLineDetails *cmdline = &pymain->cmdline;
10891089

1090-
/* TODO: Move this to _Py_InitializeMainInterpreter */
1091-
if (cmdline->command != NULL) {
1092-
/* Backup _PyOS_optind and force sys.argv[0] = '-c' */
1090+
if (cmdline->command != NULL || cmdline->module != NULL) {
1091+
/* Backup _PyOS_optind */
10931092
_PyOS_optind--;
1094-
pymain->argv[_PyOS_optind] = L"-c";
10951093
}
10961094

1097-
if (cmdline->module != NULL) {
1098-
/* Backup _PyOS_optind and force sys.argv[0] = '-m'*/
1099-
_PyOS_optind--;
1100-
pymain->argv[_PyOS_optind] = L"-m";
1095+
/* Copy argv to be able to modify it (to force -c/-m) */
1096+
int argc2 = pymain->argc - _PyOS_optind;
1097+
size_t size = argc2 * sizeof(pymain->argv[0]);
1098+
wchar_t **argv2 = PyMem_RawMalloc(size);
1099+
if (argv2 == NULL) {
1100+
pymain->err = _Py_INIT_NO_MEMORY();
1101+
return -1;
1102+
}
1103+
memcpy(argv2, &pymain->argv[_PyOS_optind], size);
1104+
1105+
/* TODO: Move this to _Py_InitializeMainInterpreter */
1106+
if (cmdline->command != NULL) {
1107+
/* Force sys.argv[0] = '-c' */
1108+
argv2[0] = L"-c";
1109+
}
1110+
else if (cmdline->module != NULL) {
1111+
/* Force sys.argv[0] = '-m'*/
1112+
argv2[0] = L"-m";
11011113
}
11021114

11031115
int update_path;
@@ -1108,9 +1120,18 @@ pymain_set_argv(_PyMain *pymain)
11081120
/* Use config settings to decide whether or not to update sys.path[0] */
11091121
update_path = (Py_IsolatedFlag == 0);
11101122
}
1111-
PySys_SetArgvEx(pymain->argc - _PyOS_optind,
1112-
pymain->argv + _PyOS_optind,
1113-
update_path);
1123+
1124+
/* Set sys.argv. If '-c' and '-m' options are not used in the command line
1125+
and update_path is non-zero, prepend argv[0] to sys.path. If argv[0] is
1126+
a symlink, use the real path. */
1127+
_PyInitError err = _PySys_SetArgvWithError(argc2, argv2, update_path);
1128+
if (_Py_INIT_FAILED(err)) {
1129+
pymain->err = err;
1130+
return -1;
1131+
}
1132+
1133+
PyMem_RawFree(argv2);
1134+
return 0;
11141135
}
11151136

11161137

@@ -1604,7 +1625,7 @@ pymain_init_utf8_mode(_PyMain *pymain)
16041625
}
16051626
#endif
16061627

1607-
wchar_t *xopt = pymain_get_xoption(pymain, L"utf8");
1628+
const wchar_t *xopt = pymain_get_xoption(pymain, L"utf8");
16081629
if (xopt) {
16091630
wchar_t *sep = wcschr(xopt, L'=');
16101631
if (sep) {
@@ -1626,7 +1647,7 @@ pymain_init_utf8_mode(_PyMain *pymain)
16261647
return 0;
16271648
}
16281649

1629-
char *opt = pymain_get_env_var("PYTHONUTF8");
1650+
const char *opt = pymain_get_env_var("PYTHONUTF8");
16301651
if (opt) {
16311652
if (strcmp(opt, "1") == 0) {
16321653
core_config->utf8_mode = 1;
@@ -1788,6 +1809,22 @@ pymain_init_python(_PyMain *pymain)
17881809
if (pymain_init_main_interpreter(pymain)) {
17891810
return -1;
17901811
}
1812+
1813+
if (pymain->cmdline.filename != NULL) {
1814+
/* If filename is a package (ex: directory or ZIP file) which contains
1815+
__main__.py, main_importer_path is set to filename and will be
1816+
prepended to sys.path by pymain_run_main_from_importer(). Otherwise,
1817+
main_importer_path is set to NULL. */
1818+
pymain->main_importer_path = pymain_get_importer(pymain->cmdline.filename);
1819+
}
1820+
1821+
/* FIXME: put argv into _PyMainInterpreterConfig.
1822+
Currently, PySys_SetArgvEx() can still modify sys.path and so must be
1823+
called after _Py_InitializeMainInterpreter() which calls
1824+
_PyPathConfig_Init(). */
1825+
if (pymain_set_sys_argv(pymain) < 0) {
1826+
return -1;
1827+
}
17911828
return 0;
17921829
}
17931830

@@ -1800,12 +1837,6 @@ pymain_run_python(_PyMain *pymain)
18001837
pymain_header(pymain);
18011838
pymain_import_readline(pymain);
18021839

1803-
if (cmdline->filename != NULL) {
1804-
pymain->main_importer_path = pymain_get_importer(cmdline->filename);
1805-
}
1806-
1807-
pymain_set_argv(pymain);
1808-
18091840
if (cmdline->command) {
18101841
pymain->status = pymain_run_command(cmdline->command, &pymain->cf);
18111842
}
@@ -1868,7 +1899,6 @@ pymain_impl(_PyMain *pymain)
18681899
other special meaning */
18691900
pymain->status = 120;
18701901
}
1871-
18721902
return 0;
18731903
}
18741904

Python/sysmodule.c

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2446,17 +2446,34 @@ sys_update_path(int argc, wchar_t **argv)
24462446
Py_DECREF(a);
24472447
}
24482448

2449-
void
2450-
PySys_SetArgvEx(int argc, wchar_t **argv, int updatepath)
2449+
_PyInitError
2450+
_PySys_SetArgvWithError(int argc, wchar_t **argv, int updatepath)
24512451
{
24522452
PyObject *av = makeargvobject(argc, argv);
2453-
if (av == NULL)
2454-
Py_FatalError("no mem for sys.argv");
2455-
if (PySys_SetObject("argv", av) != 0)
2456-
Py_FatalError("can't assign sys.argv");
2453+
if (av == NULL) {
2454+
return _Py_INIT_NO_MEMORY();
2455+
}
2456+
if (PySys_SetObject("argv", av) != 0) {
2457+
Py_DECREF(av);
2458+
return _Py_INIT_ERR("can't assign sys.argv");
2459+
}
24572460
Py_DECREF(av);
2458-
if (updatepath)
2461+
2462+
if (updatepath) {
2463+
/* If argv[0] is not '-c' nor '-m', prepend argv[0] to sys.path.
2464+
If argv[0] is a symlink, use the real path. */
24592465
sys_update_path(argc, argv);
2466+
}
2467+
return _Py_INIT_OK();
2468+
}
2469+
2470+
void
2471+
PySys_SetArgvEx(int argc, wchar_t **argv, int updatepath)
2472+
{
2473+
_PyInitError err = _PySys_SetArgvWithError(argc, argv, updatepath);
2474+
if (_Py_INIT_FAILED(err)) {
2475+
_Py_FatalInitError(err);
2476+
}
24602477
}
24612478

24622479
void

0 commit comments

Comments
 (0)