Skip to content

Commit

Permalink
[3.11] gh-107735: Add C API tests for PySys_GetObject() and PySys_Set…
Browse files Browse the repository at this point in the history
…Object() (GH-107736) (GH-107741)

(cherry picked from commit bea5f93)
  • Loading branch information
serhiy-storchaka authored Aug 7, 2023
1 parent 81c8f7d commit 22b39d1
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 0 deletions.
43 changes: 43 additions & 0 deletions Lib/test/test_capi/test_misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

from collections import OrderedDict
import _thread
import contextlib
import importlib.machinery
import importlib.util
import os
Expand Down Expand Up @@ -40,6 +41,8 @@
Py_DEBUG = hasattr(sys, 'gettotalrefcount')


NULL = None

def decode_stderr(err):
return err.decode('utf-8', 'replace').replace('\r', '')

Expand Down Expand Up @@ -910,6 +913,46 @@ def some():
with self.assertRaises(SystemError):
_testcapi.function_get_module(None) # not a function

def test_sys_getobject(self):
getobject = _testcapi.sys_getobject

self.assertIs(getobject(b'stdout'), sys.stdout)
with support.swap_attr(sys, '\U0001f40d', 42):
self.assertEqual(getobject('\U0001f40d'.encode()), 42)

self.assertIs(getobject(b'nonexisting'), AttributeError)
self.assertIs(getobject(b'\xff'), AttributeError)
# CRASHES getobject(NULL)

def test_sys_setobject(self):
setobject = _testcapi.sys_setobject

value = ['value']
value2 = ['value2']
try:
self.assertEqual(setobject(b'newattr', value), 0)
self.assertIs(sys.newattr, value)
self.assertEqual(setobject(b'newattr', value2), 0)
self.assertIs(sys.newattr, value2)
self.assertEqual(setobject(b'newattr', NULL), 0)
self.assertFalse(hasattr(sys, 'newattr'))
self.assertEqual(setobject(b'newattr', NULL), 0)
finally:
with contextlib.suppress(AttributeError):
del sys.newattr
try:
self.assertEqual(setobject('\U0001f40d'.encode(), value), 0)
self.assertIs(getattr(sys, '\U0001f40d'), value)
self.assertEqual(setobject('\U0001f40d'.encode(), NULL), 0)
self.assertFalse(hasattr(sys, '\U0001f40d'))
finally:
with contextlib.suppress(AttributeError):
delattr(sys, '\U0001f40d')

with self.assertRaises(UnicodeDecodeError):
setobject(b'\xff', value)
# CRASHES setobject(NULL, value)


class TestPendingCalls(unittest.TestCase):

Expand Down
41 changes: 41 additions & 0 deletions Modules/_testcapimodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,16 @@
# error "The public headers should not include <stdbool.h>, see bpo-46748"
#endif

#define NULLABLE(x) do { if (x == Py_None) x = NULL; } while (0);

#define RETURN_INT(value) do { \
int _ret = (value); \
if (_ret == -1) { \
return NULL; \
} \
return PyLong_FromLong(_ret); \
} while (0)

// Forward declarations
static struct PyModuleDef _testcapimodule;
static PyType_Spec HeapTypeNameType_Spec;
Expand Down Expand Up @@ -6449,6 +6459,35 @@ static PyObject *getargs_s_hash_int(PyObject *, PyObject *, PyObject*);
static PyObject *getargs_s_hash_int2(PyObject *, PyObject *, PyObject*);
static PyObject *gh_99240_clear_args(PyObject *, PyObject *);

static PyObject *
sys_getobject(PyObject *Py_UNUSED(module), PyObject *arg)
{
const char *name;
Py_ssize_t size;
if (!PyArg_Parse(arg, "z#", &name, &size)) {
return NULL;
}
PyObject *result = PySys_GetObject(name);
if (result == NULL) {
result = PyExc_AttributeError;
}
return Py_NewRef(result);
}

static PyObject *
sys_setobject(PyObject *Py_UNUSED(module), PyObject *args)
{
const char *name;
Py_ssize_t size;
PyObject *value;
if (!PyArg_ParseTuple(args, "z#O", &name, &size, &value)) {
return NULL;
}
NULLABLE(value);
RETURN_INT(PySys_SetObject(name, value));
}


static PyMethodDef TestMethods[] = {
{"exc_set_object", exc_set_object, METH_VARARGS},
{"raise_exception", raise_exception, METH_VARARGS},
Expand Down Expand Up @@ -6761,6 +6800,8 @@ static PyMethodDef TestMethods[] = {
{"function_get_code", function_get_code, METH_O, NULL},
{"function_get_globals", function_get_globals, METH_O, NULL},
{"function_get_module", function_get_module, METH_O, NULL},
{"sys_getobject", sys_getobject, METH_O},
{"sys_setobject", sys_setobject, METH_VARARGS},
{NULL, NULL} /* sentinel */
};

Expand Down

0 comments on commit 22b39d1

Please sign in to comment.