Skip to content

Commit 4b7ea77

Browse files
committed
Fail if an invalid X-option is provided in the command line
1 parent 4e60566 commit 4b7ea77

File tree

4 files changed

+57
-2
lines changed

4 files changed

+57
-2
lines changed

Include/internal/pycore_initconfig.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,9 @@ PyAPI_FUNC(int) _Py_str_to_int(
8282
PyAPI_FUNC(const wchar_t*) _Py_get_xoption(
8383
const PyWideStringList *xoptions,
8484
const wchar_t *name);
85+
PyAPI_FUNC(const wchar_t*) _Py_check_xoptions(
86+
const PyWideStringList *xoptions,
87+
const wchar_t **name);
8588
PyAPI_FUNC(const char*) _Py_GetEnv(
8689
int use_environment,
8790
const char *name);

Lib/test/test_cmd_line.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,17 @@ def get_xoptions(*args):
8383
opts = get_xoptions()
8484
self.assertEqual(opts, {})
8585

86-
opts = get_xoptions('-Xa', '-Xb=c,d=e')
87-
self.assertEqual(opts, {'a': True, 'b': 'c,d=e'})
86+
opts = get_xoptions('-Xno_debug_ranges')
87+
self.assertEqual(opts, {'no_debug_ranges': True})
88+
89+
@unittest.skipIf(interpreter_requires_environment(),
90+
'Cannot run -E tests when PYTHON env vars are required.')
91+
def test_unknown_xoptions(self):
92+
rc, out, err = assert_python_failure('-X', 'blech')
93+
self.assertIn(b'Unknown value for option -X', err)
94+
msg = b'Fatal Python error: Unknown value for option -X'
95+
self.assertEqual(err.splitlines().count(msg), 1)
96+
self.assertEqual(b'', out)
8897

8998
def test_showrefcount(self):
9099
def run_python(*args):

Python/initconfig.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2121,6 +2121,19 @@ _PyConfig_InitImportConfig(PyConfig *config)
21212121
return config_init_import(config, 1);
21222122
}
21232123

2124+
const wchar_t* known_xoptions[] = {
2125+
L"faulthandler",
2126+
L"showrefcount",
2127+
L"tracemalloc",
2128+
L"importtime",
2129+
L"dev",
2130+
L"utf8",
2131+
L"pycache_prefix",
2132+
L"warn_default_encoding",
2133+
L"no_debug_ranges",
2134+
L"frozen_modules",
2135+
NULL,
2136+
};
21242137

21252138
static PyStatus
21262139
config_read(PyConfig *config, int compute_path_config)
@@ -2136,6 +2149,11 @@ config_read(PyConfig *config, int compute_path_config)
21362149
}
21372150

21382151
/* -X options */
2152+
const wchar_t* option = _Py_check_xoptions(&config->xoptions, known_xoptions);
2153+
if (option != NULL) {
2154+
return PyStatus_Error("Unknown value for option -X");
2155+
}
2156+
21392157
if (config_get_xoption(config, L"showrefcount")) {
21402158
config->show_ref_count = 1;
21412159
}

Python/preconfig.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -593,6 +593,31 @@ _Py_get_xoption(const PyWideStringList *xoptions, const wchar_t *name)
593593
return NULL;
594594
}
595595

596+
const wchar_t*
597+
_Py_check_xoptions(const PyWideStringList *xoptions, const wchar_t **names)
598+
{
599+
for (Py_ssize_t i=0; i < xoptions->length; i++) {
600+
const wchar_t *option = xoptions->items[i];
601+
size_t len;
602+
wchar_t *sep = wcschr(option, L'=');
603+
if (sep != NULL) {
604+
len = (sep - option);
605+
}
606+
else {
607+
len = wcslen(option);
608+
}
609+
int found = 0;
610+
for (const wchar_t** name = names; *name != NULL; name++) {
611+
if (wcsncmp(option, *name, len) == 0 && (*name)[len] == L'\0') {
612+
found = 1;
613+
}
614+
}
615+
if (found == 0) {
616+
return option;
617+
}
618+
}
619+
return NULL;
620+
}
596621

597622
static PyStatus
598623
preconfig_init_utf8_mode(PyPreConfig *config, const _PyPreCmdline *cmdline)

0 commit comments

Comments
 (0)