Repository navigation
gh-116180: check if globals is NULL and set error in run_eval_code_obj() #116637
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 42 commits
9635b76
3e97671
348d895
259034c
85d9f47
cf578bd
bba6927
1b5fe4c
a016a54
173b9ce
86c6e57
7503772
f175046
dcab696
9532797
ee0fd8a
7eca26f
08b5c3a
23b9fe6
acc7eb3
09c71a9
806d21c
907c86d
af9e9fc
56f0d3c
b1d7ab2
f8e29ce
efe064d
8f33e7a
296705a
cd58eb6
c461bd9
7db13d0
eef557c
66646e9
45cab7f
1716ac6
1a9532c
6f0a0a4
2607806
7f4c496
5974757
2b4ba12
aa73f40
f6a8ee9
ccf5871
abeea0a
d579f21
d3938f5
4a18dd2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,103 @@ | ||
| import unittest, os | ||
|
serhiy-storchaka marked this conversation as resolved.
Resolved
|
||
| from collections import UserDict | ||
| from test.support import import_helper | ||
| from test.support.os_helper import unlink, TESTFN, TESTFN_UNDECODABLE | ||
|
|
||
| NULL = None | ||
| _testcapi = import_helper.import_module('_testcapi') | ||
| Py_single_input = _testcapi.Py_single_input | ||
| Py_file_input = _testcapi.Py_file_input | ||
| Py_eval_input = _testcapi.Py_eval_input | ||
|
|
||
|
serhiy-storchaka marked this conversation as resolved.
Resolved
|
||
|
|
||
| class PyRunTest(unittest.TestCase): | ||
| # TODO: Test the following functions: | ||
| # | ||
| # PyRun_SimpleStringFlags | ||
| # PyRun_AnyFileExFlags | ||
| # PyRun_SimpleFileExFlags | ||
| # PyRun_InteractiveOneFlags | ||
| # PyRun_InteractiveOneObject | ||
| # PyRun_InteractiveLoopFlags | ||
| # PyRun_String (may be a macro) | ||
| # PyRun_AnyFile (may be a macro) | ||
| # PyRun_AnyFileEx (may be a macro) | ||
| # PyRun_AnyFileFlags (may be a macro) | ||
| # PyRun_SimpleString (may be a macro) | ||
| # PyRun_SimpleFile (may be a macro) | ||
| # PyRun_SimpleFileEx (may be a macro) | ||
| # PyRun_InteractiveOne (may be a macro) | ||
| # PyRun_InteractiveLoop (may be a macro) | ||
| # PyRun_File (may be a macro) | ||
| # PyRun_FileEx (may be a macro) | ||
| # PyRun_FileFlags (may be a macro) | ||
|
erlend-aasland marked this conversation as resolved.
Resolved
|
||
|
|
||
| def test_pyrun_stringflags(self): | ||
| # Test PyRun_StringFlags(). | ||
| def run(s, *args): | ||
| return _testcapi.run_stringflags(s, Py_file_input, *args) | ||
| source = b'a\n' | ||
|
|
||
| self.assertIsNone(run(b'a\n', dict(a=1))) | ||
| self.assertIsNone(run(b'a\n', dict(a=1), {})) | ||
| self.assertIsNone(run(b'a\n', {}, dict(a=1))) | ||
| self.assertIsNone(run(b'a\n', {}, UserDict(a=1))) | ||
|
|
||
| self.assertRaises(NameError, run, b'a\n', {}) | ||
| self.assertRaises(NameError, run, b'a\n', {}, {}) | ||
| self.assertRaises(TypeError, run, b'a\n', dict(a=1), []) | ||
| self.assertRaises(TypeError, run, b'a\n', dict(a=1), 1) | ||
|
|
||
| self.assertIsNone(run(b'\xc3\xa4\n', {'\xe4': 1})) | ||
| self.assertRaises(SyntaxError, run, b'\xe4\n', {}) | ||
|
|
||
| self.assertRaises(SystemError, run, b'a\n', NULL) | ||
| self.assertRaises(SystemError, run, b'a\n', NULL, {}) | ||
| self.assertRaises(SystemError, run, b'a\n', NULL, dict(a=1)) | ||
| self.assertRaises(SystemError, run, b'a\n', UserDict()) | ||
| self.assertRaises(SystemError, run, b'a\n', UserDict(), {}) | ||
| self.assertRaises(SystemError, run, b'a\n', UserDict(), dict(a=1)) | ||
|
|
||
| # CRASHES run(NULL, {}) | ||
|
|
||
| def test_pyrun_fileexflags(self): | ||
| # Test PyRun_FileExFlags(). | ||
| filename = os.fsencode(TESTFN) | ||
| with open(filename, 'wb') as fp: | ||
| fp.write(b'a\n') | ||
| self.addCleanup(unlink, filename) | ||
| def run(*args): | ||
| return _testcapi.run_fileexflags(filename, Py_file_input, *args) | ||
|
|
||
| self.assertIsNone(run(dict(a=1))) | ||
| self.assertIsNone(run(dict(a=1), {})) | ||
| self.assertIsNone(run({}, dict(a=1))) | ||
| self.assertIsNone(run({}, UserDict(a=1))) | ||
| self.assertIsNone(run(dict(a=1), {}, 1)) # closeit = True | ||
|
|
||
| self.assertRaises(NameError, run, {}) | ||
| self.assertRaises(NameError, run, {}, {}) | ||
| self.assertRaises(TypeError, run, dict(a=1), []) | ||
| self.assertRaises(TypeError, run, dict(a=1), 1) | ||
|
|
||
| self.assertRaises(SystemError, run, NULL) | ||
| self.assertRaises(SystemError, run, NULL, {}) | ||
| self.assertRaises(SystemError, run, NULL, dict(a=1)) | ||
| self.assertRaises(SystemError, run, UserDict()) | ||
| self.assertRaises(SystemError, run, UserDict(), {}) | ||
| self.assertRaises(SystemError, run, UserDict(), dict(a=1)) | ||
|
|
||
| @unittest.skipUnless(TESTFN_UNDECODABLE, 'only works if there are undecodable paths') | ||
| def test_pyrun_fileexflags_with_undecodable_filename(self): | ||
| run = _testcapi.run_fileexflags | ||
| try: | ||
| with open(TESTFN_UNDECODABLE, 'wb') as fp: | ||
| fp.write(b'a\n') | ||
| self.addCleanup(unlink, TESTFN_UNDECODABLE) | ||
| except OSError: | ||
| self.skipTest('undecodable paths are not supported') | ||
| self.assertIsNone(run(TESTFN_UNDECODABLE, Py_file_input, dict(a=1))) | ||
|
|
||
|
|
||
| if __name__ == '__main__': | ||
| unittest.main() | ||
|
erlend-aasland marked this conversation as resolved.
Resolved
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,112 @@ | ||
| #include "parts.h" | ||
| #include "util.h" | ||
|
|
||
| #include <stdio.h> | ||
| #include <errno.h> | ||
|
|
||
|
|
||
| static PyObject * | ||
| run_stringflags(PyObject *mod, PyObject *pos_args) | ||
| { | ||
| const char *str; | ||
| Py_ssize_t size; | ||
| int start; | ||
| PyObject *globals = NULL; | ||
| PyObject *locals = NULL; | ||
| PyCompilerFlags flags = _PyCompilerFlags_INIT; | ||
| PyCompilerFlags *pflags = NULL; | ||
| int cf_flags = 0; | ||
| int cf_feature_version = 0; | ||
|
|
||
| if (!PyArg_ParseTuple(pos_args, "z#iO|Oii", | ||
| &str, &size, &start, &globals, &locals, | ||
| &cf_flags, &cf_feature_version)) { | ||
| return NULL; | ||
| } | ||
|
|
||
| NULLABLE(globals); | ||
| NULLABLE(locals); | ||
| if (cf_flags || cf_feature_version) { | ||
| flags.cf_flags = cf_flags; | ||
| flags.cf_feature_version = cf_feature_version; | ||
| pflags = &flags; | ||
| } | ||
|
|
||
| return PyRun_StringFlags(str, start, globals, locals, pflags); | ||
| } | ||
|
|
||
| static PyObject * | ||
| run_fileexflags(PyObject *mod, PyObject *pos_args) | ||
| { | ||
| PyObject *result = NULL; | ||
| const char *filename = NULL; | ||
| Py_ssize_t filename_size; | ||
| int start; | ||
| PyObject *globals = NULL; | ||
| PyObject *locals = NULL; | ||
| int closeit = 0; | ||
| PyCompilerFlags flags = _PyCompilerFlags_INIT; | ||
| PyCompilerFlags *pflags = NULL; | ||
| int cf_flags = 0; | ||
| int cf_feature_version = 0; | ||
|
|
||
| FILE *fp = NULL; | ||
|
|
||
| if (!PyArg_ParseTuple(pos_args, "z#iO|Oiii", | ||
| &filename, &filename_size, &start, &globals, &locals, | ||
| &closeit, &cf_flags, &cf_feature_version)) { | ||
| return NULL; | ||
| } | ||
|
|
||
| NULLABLE(globals); | ||
| NULLABLE(locals); | ||
| if (cf_flags || cf_feature_version) { | ||
| flags.cf_flags = cf_flags; | ||
| flags.cf_feature_version = cf_feature_version; | ||
| pflags = &flags; | ||
| } | ||
|
|
||
| fp = fopen(filename, "r"); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What if
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Linux will return something like EFAULT with fp = NULL. But NULL can be passed, if you use fp of stdin for example |
||
| if (fp == NULL) { | ||
| PyErr_SetFromErrnoWithFilename(PyExc_OSError, filename); | ||
| return NULL; | ||
| } | ||
|
|
||
| result = PyRun_FileExFlags(fp, filename, start, globals, locals, closeit, pflags); | ||
|
|
||
| #if !defined(__wasi__) | ||
| /* The behavior of fileno() after fclose() is undefined. */ | ||
| if (closeit && result && fileno(fp) >= 0) { | ||
| PyErr_SetString(PyExc_AssertionError, "File was not closed after excution"); | ||
| Py_DECREF(result); | ||
| fclose(fp); | ||
| return NULL; | ||
| } | ||
| #endif | ||
| if (!closeit && fileno(fp) < 0) { | ||
| PyErr_SetString(PyExc_AssertionError, "Bad file descriptor after excution"); | ||
| Py_XDECREF(result); | ||
| return NULL; | ||
| } | ||
|
|
||
| if (!closeit) { | ||
| fclose(fp); /* don't need open file any more*/ | ||
| } | ||
|
|
||
| return result; | ||
| } | ||
|
|
||
| static PyMethodDef test_methods[] = { | ||
| {"run_stringflags", run_stringflags, METH_VARARGS}, | ||
| {"run_fileexflags", run_fileexflags, METH_VARARGS}, | ||
| {NULL}, | ||
| }; | ||
|
|
||
| int | ||
| _PyTestCapi_Init_PyRun(PyObject *mod) | ||
| { | ||
| if (PyModule_AddFunctions(mod, test_methods) < 0) { | ||
| return -1; | ||
| } | ||
| return 0; | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.