Skip to content

Commit 023f806

Browse files
authored
Fix and improve Objects/lazyimportobject.c (#31)
* re-order imports * simplify static type definition * fix undefined behaviors * reject keyword arguments for `lazy_import`
1 parent a0a28c2 commit 023f806

File tree

1 file changed

+53
-66
lines changed

1 file changed

+53
-66
lines changed

Objects/lazyimportobject.c

Lines changed: 53 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
/* Lazy object implementation */
22

33
#include "Python.h"
4-
#include "pycore_import.h"
5-
#include "pycore_lazyimportobject.h"
6-
#include "pycore_frame.h"
74
#include "pycore_ceval.h"
5+
#include "pycore_frame.h"
6+
#include "pycore_import.h"
87
#include "pycore_interpframe.h"
8+
#include "pycore_lazyimportobject.h"
9+
#include "pycore_modsupport.h"
10+
11+
#define PyLazyImportObject_CAST(op) ((PyLazyImportObject *)(op))
912

1013
PyObject *
1114
_PyLazyImport_New(PyObject *builtins, PyObject *from, PyObject *attr)
@@ -46,8 +49,9 @@ _PyLazyImport_New(PyObject *builtins, PyObject *from, PyObject *attr)
4649
}
4750

4851
static int
49-
lazy_import_traverse(PyLazyImportObject *m, visitproc visit, void *arg)
52+
lazy_import_traverse(PyObject *op, visitproc visit, void *arg)
5053
{
54+
PyLazyImportObject *m = PyLazyImportObject_CAST(op);
5155
Py_VISIT(m->lz_builtins);
5256
Py_VISIT(m->lz_from);
5357
Py_VISIT(m->lz_attr);
@@ -56,8 +60,9 @@ lazy_import_traverse(PyLazyImportObject *m, visitproc visit, void *arg)
5660
}
5761

5862
static int
59-
lazy_import_clear(PyLazyImportObject *m)
63+
lazy_import_clear(PyObject *op)
6064
{
65+
PyLazyImportObject *m = PyLazyImportObject_CAST(op);
6166
Py_CLEAR(m->lz_builtins);
6267
Py_CLEAR(m->lz_from);
6368
Py_CLEAR(m->lz_attr);
@@ -66,11 +71,11 @@ lazy_import_clear(PyLazyImportObject *m)
6671
}
6772

6873
static void
69-
lazy_import_dealloc(PyLazyImportObject *m)
74+
lazy_import_dealloc(PyObject *op)
7075
{
71-
_PyObject_GC_UNTRACK(m);
72-
lazy_import_clear(m);
73-
Py_TYPE(m)->tp_free((PyObject *)m);
76+
_PyObject_GC_UNTRACK(op);
77+
(void)lazy_import_clear(op);
78+
Py_TYPE(op)->tp_free(op);
7479
}
7580

7681
static PyObject *
@@ -79,60 +84,69 @@ lazy_import_name(PyLazyImportObject *m)
7984
if (m->lz_attr != NULL) {
8085
if (PyUnicode_Check(m->lz_attr)) {
8186
return PyUnicode_FromFormat("%U.%U", m->lz_from, m->lz_attr);
82-
} else {
87+
}
88+
else {
8389
return PyUnicode_FromFormat("%U...", m->lz_from);
8490
}
8591
}
86-
Py_INCREF(m->lz_from);
87-
return m->lz_from;
92+
return Py_NewRef(m->lz_from);
8893
}
8994

9095
static PyObject *
91-
lazy_import_repr(PyLazyImportObject *m)
96+
lazy_import_repr(PyObject *op)
9297
{
98+
PyLazyImportObject *m = PyLazyImportObject_CAST(op);
9399
PyObject *name = lazy_import_name(m);
94100
if (name == NULL) {
95101
return NULL;
96102
}
97-
PyObject *res = PyUnicode_FromFormat("<lazy_import '%U'>", name);
103+
PyObject *res = PyUnicode_FromFormat("<%T '%U'>", op, name);
98104
Py_DECREF(name);
99105
return res;
100106
}
101107

102108
static PyObject *
103109
lazy_import_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
104110
{
105-
if (PyTuple_GET_SIZE(args) != 2 && PyTuple_GET_SIZE(args) != 3) {
106-
PyErr_SetString(PyExc_ValueError, "lazy_import expected 2-3 arguments");
111+
PyTypeObject *base_tp = &PyLazyImport_Type;
112+
if (
113+
(type == base_tp || type->tp_init == base_tp->tp_init)
114+
&& !_PyArg_NoKeywords("lazy_import", kwds)
115+
) {
107116
return NULL;
108117
}
109118

110-
PyObject *builtins = PyTuple_GET_ITEM(args, 0);
111-
PyObject *from = PyTuple_GET_ITEM(args, 1);
112-
PyObject *attr = NULL;
113-
if (PyTuple_GET_SIZE(args) == 3) {
114-
attr = PyTuple_GET_ITEM(args, 2);
119+
Py_ssize_t nargs = PyTuple_GET_SIZE(args);
120+
if (!_PyArg_CheckPositional("lazy_import", nargs, 2, 3)) {
121+
return NULL;
115122
}
116123

124+
PyObject *builtins = PyTuple_GET_ITEM(args, 0);
125+
PyObject *from = PyTuple_GET_ITEM(args, 1);
126+
PyObject *attr = nargs == 3 ? PyTuple_GET_ITEM(args, 2) : NULL;
117127
return _PyLazyImport_New(builtins, from, attr);
118128
}
119129

120130
PyObject *
121-
_PyLazyImport_GetName(PyObject *lazy_import)
131+
_PyLazyImport_GetName(PyObject *op)
122132
{
133+
PyLazyImportObject *lazy_import = PyLazyImportObject_CAST(op);
123134
assert(PyLazyImport_CheckExact(lazy_import));
124-
return lazy_import_name((PyLazyImportObject *)lazy_import);
135+
return lazy_import_name(lazy_import);
125136
}
126137

127138
static PyObject *
128-
lazy_resolve(PyObject *self, PyObject *args)
139+
lazy_import_resolve(PyObject *self, PyObject *args)
129140
{
130141
return _PyImport_LoadLazyImportTstate(PyThreadState_GET(), self);
131142
}
132143

133-
static PyMethodDef lazy_methods[] = {
134-
{"resolve", lazy_resolve, METH_NOARGS, PyDoc_STR("resolves the lazy import and returns the actual object")},
135-
{0}
144+
static PyMethodDef lazy_import_methods[] = {
145+
{
146+
"resolve", lazy_import_resolve, METH_NOARGS,
147+
PyDoc_STR("resolves the lazy import and returns the actual object")
148+
},
149+
{NULL, NULL}
136150
};
137151

138152

@@ -147,43 +161,16 @@ PyDoc_STRVAR(lazy_import_doc,
147161

148162
PyTypeObject PyLazyImport_Type = {
149163
PyVarObject_HEAD_INIT(&PyType_Type, 0)
150-
"lazy_import", /* tp_name */
151-
sizeof(PyLazyImportObject), /* tp_basicsize */
152-
0, /* tp_itemsize */
153-
(destructor)lazy_import_dealloc, /* tp_dealloc */
154-
0, /* tp_print */
155-
0, /* tp_getattr */
156-
0, /* tp_setattr */
157-
0, /* tp_reserved */
158-
(reprfunc)lazy_import_repr, /* tp_repr */
159-
0, /* tp_as_number */
160-
0, /* tp_as_sequence */
161-
0, /* tp_as_mapping */
162-
0, /* tp_hash */
163-
0, /* tp_call */
164-
0, /* tp_str */
165-
0, /* tp_getattro */
166-
0, /* tp_setattro */
167-
0, /* tp_as_buffer */
168-
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
169-
Py_TPFLAGS_BASETYPE, /* tp_flags */
170-
lazy_import_doc, /* tp_doc */
171-
(traverseproc)lazy_import_traverse, /* tp_traverse */
172-
(inquiry)lazy_import_clear, /* tp_clear */
173-
0, /* tp_richcompare */
174-
0, /* tp_weaklistoffset */
175-
0, /* tp_iter */
176-
0, /* tp_iternext */
177-
lazy_methods, /* tp_methods */
178-
0, /* tp_members */
179-
0, /* tp_getset */
180-
0, /* tp_base */
181-
0, /* tp_dict */
182-
0, /* tp_descr_get */
183-
0, /* tp_descr_set */
184-
0, /* tp_dictoffset */
185-
0, /* tp_init */
186-
PyType_GenericAlloc, /* tp_alloc */
187-
lazy_import_new, /* tp_new */
188-
PyObject_GC_Del, /* tp_free */
164+
.tp_name = "lazy_import",
165+
.tp_basicsize = sizeof(PyLazyImportObject),
166+
.tp_dealloc = lazy_import_dealloc,
167+
.tp_repr = lazy_import_repr,
168+
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE,
169+
.tp_doc = lazy_import_doc,
170+
.tp_traverse = lazy_import_traverse,
171+
.tp_clear = lazy_import_clear,
172+
.tp_methods = lazy_import_methods,
173+
.tp_alloc = PyType_GenericAlloc,
174+
.tp_new = lazy_import_new,
175+
.tp_free = PyObject_GC_Del,
189176
};

0 commit comments

Comments
 (0)