Skip to content

Commit af1d64d

Browse files
authored
bpo-42260: Main init modify sys.flags in-place (GH-23150)
When Py_Initialize() is called twice, the second call now updates more sys attributes for the configuration, rather than only sys.argv. * Rename _PySys_InitMain() to _PySys_UpdateConfig(). * _PySys_UpdateConfig() now modifies sys.flags in-place, instead of creating a new flags object. * Remove old commented sys.flags flags (unbuffered and skip_first). * Add private _PySys_GetObject() function. * When Py_Initialize(), Py_InitializeFromConfig() and
1 parent 58ca33b commit af1d64d

File tree

4 files changed

+89
-74
lines changed

4 files changed

+89
-74
lines changed

Include/internal/pycore_pylifecycle.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ extern PyStatus _PySys_Create(
4444
PyObject **sysmod_p);
4545
extern PyStatus _PySys_ReadPreinitWarnOptions(PyWideStringList *options);
4646
extern PyStatus _PySys_ReadPreinitXOptions(PyConfig *config);
47-
extern int _PySys_InitMain(PyThreadState *tstate);
47+
extern int _PySys_UpdateConfig(PyThreadState *tstate);
4848
extern PyStatus _PyExc_Init(PyThreadState *tstate);
4949
extern PyStatus _PyErr_Init(void);
5050
extern PyStatus _PyBuiltins_AddExceptions(PyObject * bltinmod);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
When :c:func:`Py_Initialize` is called twice, the second call now updates
2+
more :mod:`sys` attributes for the configuration, rather than only
3+
:data:`sys.argv`. Patch by Victor Stinner.

Python/pylifecycle.c

+18-27
Original file line numberDiff line numberDiff line change
@@ -949,19 +949,10 @@ pyinit_core(_PyRuntimeState *runtime,
949949
configuration. Example of bpo-34008: Py_Main() called after
950950
Py_Initialize(). */
951951
static PyStatus
952-
_Py_ReconfigureMainInterpreter(PyThreadState *tstate)
952+
pyinit_main_reconfigure(PyThreadState *tstate)
953953
{
954-
const PyConfig *config = _PyInterpreterState_GetConfig(tstate->interp);
955-
956-
PyObject *argv = _PyWideStringList_AsList(&config->argv);
957-
if (argv == NULL) {
958-
return _PyStatus_NO_MEMORY(); \
959-
}
960-
961-
int res = PyDict_SetItemString(tstate->interp->sysdict, "argv", argv);
962-
Py_DECREF(argv);
963-
if (res < 0) {
964-
return _PyStatus_ERR("fail to set sys.argv");
954+
if (_PySys_UpdateConfig(tstate) < 0) {
955+
return _PyStatus_ERR("fail to update sys for the new conf");
965956
}
966957
return _PyStatus_OK();
967958
}
@@ -995,7 +986,7 @@ init_interp_main(PyThreadState *tstate)
995986
}
996987
}
997988

998-
if (_PySys_InitMain(tstate) < 0) {
989+
if (_PySys_UpdateConfig(tstate) < 0) {
999990
return _PyStatus_ERR("can't finish initializing sys");
1000991
}
1001992

@@ -1100,7 +1091,7 @@ pyinit_main(PyThreadState *tstate)
11001091
}
11011092

11021093
if (interp->runtime->initialized) {
1103-
return _Py_ReconfigureMainInterpreter(tstate);
1094+
return pyinit_main_reconfigure(tstate);
11041095
}
11051096

11061097
PyStatus status = init_interp_main(tstate);
@@ -1111,19 +1102,6 @@ pyinit_main(PyThreadState *tstate)
11111102
}
11121103

11131104

1114-
PyStatus
1115-
_Py_InitializeMain(void)
1116-
{
1117-
PyStatus status = _PyRuntime_Initialize();
1118-
if (_PyStatus_EXCEPTION(status)) {
1119-
return status;
1120-
}
1121-
_PyRuntimeState *runtime = &_PyRuntime;
1122-
PyThreadState *tstate = _PyRuntimeState_GetThreadState(runtime);
1123-
return pyinit_main(tstate);
1124-
}
1125-
1126-
11271105
PyStatus
11281106
Py_InitializeFromConfig(const PyConfig *config)
11291107
{
@@ -1191,6 +1169,19 @@ Py_Initialize(void)
11911169
}
11921170

11931171

1172+
PyStatus
1173+
_Py_InitializeMain(void)
1174+
{
1175+
PyStatus status = _PyRuntime_Initialize();
1176+
if (_PyStatus_EXCEPTION(status)) {
1177+
return status;
1178+
}
1179+
_PyRuntimeState *runtime = &_PyRuntime;
1180+
PyThreadState *tstate = _PyRuntimeState_GetThreadState(runtime);
1181+
return pyinit_main(tstate);
1182+
}
1183+
1184+
11941185
static void
11951186
finalize_modules_delete_special(PyThreadState *tstate, int verbose)
11961187
{

Python/sysmodule.c

+67-46
Original file line numberDiff line numberDiff line change
@@ -84,17 +84,24 @@ _PySys_GetObjectId(_Py_Identifier *key)
8484
return sys_get_object_id(tstate, key);
8585
}
8686

87+
static PyObject *
88+
_PySys_GetObject(PyThreadState *tstate, const char *name)
89+
{
90+
PyObject *sysdict = tstate->interp->sysdict;
91+
if (sysdict == NULL) {
92+
return NULL;
93+
}
94+
return _PyDict_GetItemStringWithError(sysdict, name);
95+
}
96+
8797
PyObject *
8898
PySys_GetObject(const char *name)
8999
{
90100
PyThreadState *tstate = _PyThreadState_GET();
91-
PyObject *sd = tstate->interp->sysdict;
92-
if (sd == NULL) {
93-
return NULL;
94-
}
101+
95102
PyObject *exc_type, *exc_value, *exc_tb;
96103
_PyErr_Fetch(tstate, &exc_type, &exc_value, &exc_tb);
97-
PyObject *value = _PyDict_GetItemStringWithError(sd, name);
104+
PyObject *value = _PySys_GetObject(tstate, name);
98105
/* XXX Suppress a new exception if it was raised and restore
99106
* the old one. */
100107
_PyErr_Restore(tstate, exc_type, exc_value, exc_tb);
@@ -2464,8 +2471,6 @@ static PyStructSequence_Field flags_fields[] = {
24642471
{"no_site", "-S"},
24652472
{"ignore_environment", "-E"},
24662473
{"verbose", "-v"},
2467-
/* {"unbuffered", "-u"}, */
2468-
/* {"skip_first", "-x"}, */
24692474
{"bytes_warning", "-b"},
24702475
{"quiet", "-q"},
24712476
{"hash_randomization", "-R"},
@@ -2482,21 +2487,27 @@ static PyStructSequence_Desc flags_desc = {
24822487
15
24832488
};
24842489

2485-
static PyObject*
2486-
make_flags(PyThreadState *tstate)
2490+
static int
2491+
set_flags_from_config(PyObject *flags, PyThreadState *tstate)
24872492
{
24882493
PyInterpreterState *interp = tstate->interp;
24892494
const PyPreConfig *preconfig = &interp->runtime->preconfig;
24902495
const PyConfig *config = _PyInterpreterState_GetConfig(interp);
24912496

2492-
PyObject *seq = PyStructSequence_New(&FlagsType);
2493-
if (seq == NULL) {
2494-
return NULL;
2495-
}
2496-
2497-
int pos = 0;
2498-
#define SetFlag(flag) \
2499-
PyStructSequence_SET_ITEM(seq, pos++, PyLong_FromLong(flag))
2497+
// _PySys_UpdateConfig() modifies sys.flags in-place:
2498+
// Py_XDECREF() is needed in this case.
2499+
Py_ssize_t pos = 0;
2500+
#define SetFlagObj(expr) \
2501+
do { \
2502+
PyObject *value = (expr); \
2503+
if (value == NULL) { \
2504+
return -1; \
2505+
} \
2506+
Py_XDECREF(PyStructSequence_GET_ITEM(flags, pos)); \
2507+
PyStructSequence_SET_ITEM(flags, pos, value); \
2508+
pos++; \
2509+
} while (0)
2510+
#define SetFlag(expr) SetFlagObj(PyLong_FromLong(expr))
25002511

25012512
SetFlag(config->parser_debug);
25022513
SetFlag(config->inspect);
@@ -2507,23 +2518,34 @@ make_flags(PyThreadState *tstate)
25072518
SetFlag(!config->site_import);
25082519
SetFlag(!config->use_environment);
25092520
SetFlag(config->verbose);
2510-
/* SetFlag(saw_unbuffered_flag); */
2511-
/* SetFlag(skipfirstline); */
25122521
SetFlag(config->bytes_warning);
25132522
SetFlag(config->quiet);
25142523
SetFlag(config->use_hash_seed == 0 || config->hash_seed != 0);
25152524
SetFlag(config->isolated);
2516-
PyStructSequence_SET_ITEM(seq, pos++, PyBool_FromLong(config->dev_mode));
2525+
SetFlagObj(PyBool_FromLong(config->dev_mode));
25172526
SetFlag(preconfig->utf8_mode);
2527+
#undef SetFlagObj
25182528
#undef SetFlag
2529+
return 0;
2530+
}
25192531

2520-
if (_PyErr_Occurred(tstate)) {
2521-
Py_DECREF(seq);
2532+
2533+
static PyObject*
2534+
make_flags(PyThreadState *tstate)
2535+
{
2536+
PyObject *flags = PyStructSequence_New(&FlagsType);
2537+
if (flags == NULL) {
25222538
return NULL;
25232539
}
2524-
return seq;
2540+
2541+
if (set_flags_from_config(flags, tstate) < 0) {
2542+
Py_DECREF(flags);
2543+
return NULL;
2544+
}
2545+
return flags;
25252546
}
25262547

2548+
25272549
PyDoc_STRVAR(version_info__doc__,
25282550
"sys.version_info\n\
25292551
\n\
@@ -2767,14 +2789,23 @@ _PySys_InitCore(PyThreadState *tstate, PyObject *sysdict)
27672789
/* implementation */
27682790
SET_SYS("implementation", make_impl_info(version_info));
27692791

2770-
/* flags */
2792+
// sys.flags: updated in-place later by _PySys_UpdateConfig()
27712793
if (FlagsType.tp_name == 0) {
27722794
if (PyStructSequence_InitType2(&FlagsType, &flags_desc) < 0) {
27732795
goto type_init_failed;
27742796
}
27752797
}
2776-
/* Set flags to their default values (updated by _PySys_InitMain()) */
27772798
SET_SYS("flags", make_flags(tstate));
2799+
/* prevent user from creating new instances */
2800+
FlagsType.tp_init = NULL;
2801+
FlagsType.tp_new = NULL;
2802+
res = PyDict_DelItemString(FlagsType.tp_dict, "__new__");
2803+
if (res < 0) {
2804+
if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) {
2805+
goto err_occurred;
2806+
}
2807+
_PyErr_Clear(tstate);
2808+
}
27782809

27792810
#if defined(MS_WINDOWS)
27802811
/* getwindowsversion */
@@ -2876,8 +2907,10 @@ sys_create_xoptions_dict(const PyConfig *config)
28762907
}
28772908

28782909

2910+
// Update sys attributes for a new PyConfig configuration.
2911+
// This function also adds attributes that _PySys_InitCore() didn't add.
28792912
int
2880-
_PySys_InitMain(PyThreadState *tstate)
2913+
_PySys_UpdateConfig(PyThreadState *tstate)
28812914
{
28822915
PyObject *sysdict = tstate->interp->sysdict;
28832916
const PyConfig *config = _PyInterpreterState_GetConfig(tstate->interp);
@@ -2914,28 +2947,16 @@ _PySys_InitMain(PyThreadState *tstate)
29142947
#undef COPY_LIST
29152948
#undef SET_SYS_FROM_WSTR
29162949

2917-
2918-
/* Set flags to their final values */
2919-
SET_SYS("flags", make_flags(tstate));
2920-
/* prevent user from creating new instances */
2921-
FlagsType.tp_init = NULL;
2922-
FlagsType.tp_new = NULL;
2923-
res = PyDict_DelItemString(FlagsType.tp_dict, "__new__");
2924-
if (res < 0) {
2925-
if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) {
2926-
return res;
2927-
}
2928-
_PyErr_Clear(tstate);
2950+
// sys.flags
2951+
PyObject *flags = _PySys_GetObject(tstate, "flags"); // borrowed ref
2952+
if (flags == NULL) {
2953+
return -1;
29292954
}
2930-
2931-
SET_SYS("dont_write_bytecode", PyBool_FromLong(!config->write_bytecode));
2932-
2933-
if (get_warnoptions(tstate) == NULL) {
2955+
if (set_flags_from_config(flags, tstate) < 0) {
29342956
return -1;
29352957
}
29362958

2937-
if (get_xoptions(tstate) == NULL)
2938-
return -1;
2959+
SET_SYS("dont_write_bytecode", PyBool_FromLong(!config->write_bytecode));
29392960

29402961
if (_PyErr_Occurred(tstate)) {
29412962
goto err_occurred;
@@ -2977,8 +2998,8 @@ _PySys_SetPreliminaryStderr(PyObject *sysdict)
29772998
}
29782999

29793000

2980-
/* Create sys module without all attributes: _PySys_InitMain() should be called
2981-
later to add remaining attributes. */
3001+
/* Create sys module without all attributes.
3002+
_PySys_UpdateConfig() should be called later to add remaining attributes. */
29823003
PyStatus
29833004
_PySys_Create(PyThreadState *tstate, PyObject **sysmod_p)
29843005
{

0 commit comments

Comments
 (0)