Coverage Report

Created: 2025-07-11 06:59

/src/Python-3.8.3/Objects/methodobject.c
Line
Count
Source (jump to first uncovered line)
1
2
/* Method object implementation */
3
4
#include "Python.h"
5
#include "pycore_object.h"
6
#include "pycore_pymem.h"
7
#include "pycore_pystate.h"
8
#include "structmember.h"
9
10
/* Free list for method objects to safe malloc/free overhead
11
 * The m_self element is used to chain the objects.
12
 */
13
static PyCFunctionObject *free_list = NULL;
14
static int numfree = 0;
15
#ifndef PyCFunction_MAXFREELIST
16
8.84k
#define PyCFunction_MAXFREELIST 256
17
#endif
18
19
/* undefine macro trampoline to PyCFunction_NewEx */
20
#undef PyCFunction_New
21
22
/* Forward declarations */
23
static PyObject * cfunction_vectorcall_FASTCALL(
24
    PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames);
25
static PyObject * cfunction_vectorcall_FASTCALL_KEYWORDS(
26
    PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames);
27
static PyObject * cfunction_vectorcall_NOARGS(
28
    PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames);
29
static PyObject * cfunction_vectorcall_O(
30
    PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames);
31
32
33
PyObject *
34
PyCFunction_New(PyMethodDef *ml, PyObject *self)
35
0
{
36
0
    return PyCFunction_NewEx(ml, self, NULL);
37
0
}
38
39
PyObject *
40
PyCFunction_NewEx(PyMethodDef *ml, PyObject *self, PyObject *module)
41
16.8k
{
42
    /* Figure out correct vectorcall function to use */
43
16.8k
    vectorcallfunc vectorcall;
44
16.8k
    switch (ml->ml_flags & (METH_VARARGS | METH_FASTCALL | METH_NOARGS | METH_O | METH_KEYWORDS))
45
16.8k
    {
46
1.70k
        case METH_VARARGS:
47
4.40k
        case METH_VARARGS | METH_KEYWORDS:
48
            /* For METH_VARARGS functions, it's more efficient to use tp_call
49
             * instead of vectorcall. */
50
4.40k
            vectorcall = NULL;
51
4.40k
            break;
52
1.39k
        case METH_FASTCALL:
53
1.39k
            vectorcall = cfunction_vectorcall_FASTCALL;
54
1.39k
            break;
55
3.18k
        case METH_FASTCALL | METH_KEYWORDS:
56
3.18k
            vectorcall = cfunction_vectorcall_FASTCALL_KEYWORDS;
57
3.18k
            break;
58
5.26k
        case METH_NOARGS:
59
5.26k
            vectorcall = cfunction_vectorcall_NOARGS;
60
5.26k
            break;
61
2.58k
        case METH_O:
62
2.58k
            vectorcall = cfunction_vectorcall_O;
63
2.58k
            break;
64
0
        default:
65
0
            PyErr_Format(PyExc_SystemError,
66
0
                         "%s() method: bad call flags", ml->ml_name);
67
0
            return NULL;
68
16.8k
    }
69
70
16.8k
    PyCFunctionObject *op;
71
16.8k
    op = free_list;
72
16.8k
    if (op != NULL) {
73
8.84k
        free_list = (PyCFunctionObject *)(op->m_self);
74
8.84k
        (void)PyObject_INIT(op, &PyCFunction_Type);
75
8.84k
        numfree--;
76
8.84k
    }
77
7.98k
    else {
78
7.98k
        op = PyObject_GC_New(PyCFunctionObject, &PyCFunction_Type);
79
7.98k
        if (op == NULL)
80
0
            return NULL;
81
7.98k
    }
82
16.8k
    op->m_weakreflist = NULL;
83
16.8k
    op->m_ml = ml;
84
16.8k
    Py_XINCREF(self);
85
16.8k
    op->m_self = self;
86
16.8k
    Py_XINCREF(module);
87
16.8k
    op->m_module = module;
88
16.8k
    op->vectorcall = vectorcall;
89
16.8k
    _PyObject_GC_TRACK(op);
90
16.8k
    return (PyObject *)op;
91
16.8k
}
92
93
PyCFunction
94
PyCFunction_GetFunction(PyObject *op)
95
0
{
96
0
    if (!PyCFunction_Check(op)) {
97
0
        PyErr_BadInternalCall();
98
0
        return NULL;
99
0
    }
100
0
    return PyCFunction_GET_FUNCTION(op);
101
0
}
102
103
PyObject *
104
PyCFunction_GetSelf(PyObject *op)
105
0
{
106
0
    if (!PyCFunction_Check(op)) {
107
0
        PyErr_BadInternalCall();
108
0
        return NULL;
109
0
    }
110
0
    return PyCFunction_GET_SELF(op);
111
0
}
112
113
int
114
PyCFunction_GetFlags(PyObject *op)
115
0
{
116
0
    if (!PyCFunction_Check(op)) {
117
0
        PyErr_BadInternalCall();
118
0
        return -1;
119
0
    }
120
0
    return PyCFunction_GET_FLAGS(op);
121
0
}
122
123
/* Methods (the standard built-in methods, that is) */
124
125
static void
126
meth_dealloc(PyCFunctionObject *m)
127
8.84k
{
128
8.84k
    _PyObject_GC_UNTRACK(m);
129
8.84k
    if (m->m_weakreflist != NULL) {
130
0
        PyObject_ClearWeakRefs((PyObject*) m);
131
0
    }
132
8.84k
    Py_XDECREF(m->m_self);
133
8.84k
    Py_XDECREF(m->m_module);
134
8.84k
    if (numfree < PyCFunction_MAXFREELIST) {
135
8.84k
        m->m_self = (PyObject *)free_list;
136
8.84k
        free_list = m;
137
8.84k
        numfree++;
138
8.84k
    }
139
0
    else {
140
0
        PyObject_GC_Del(m);
141
0
    }
142
8.84k
}
143
144
static PyObject *
145
meth_reduce(PyCFunctionObject *m, PyObject *Py_UNUSED(ignored))
146
0
{
147
0
    _Py_IDENTIFIER(getattr);
148
149
0
    if (m->m_self == NULL || PyModule_Check(m->m_self))
150
0
        return PyUnicode_FromString(m->m_ml->ml_name);
151
152
0
    return Py_BuildValue("N(Os)", _PyEval_GetBuiltinId(&PyId_getattr),
153
0
                         m->m_self, m->m_ml->ml_name);
154
0
}
155
156
static PyMethodDef meth_methods[] = {
157
    {"__reduce__", (PyCFunction)meth_reduce, METH_NOARGS, NULL},
158
    {NULL, NULL}
159
};
160
161
static PyObject *
162
meth_get__text_signature__(PyCFunctionObject *m, void *closure)
163
0
{
164
0
    return _PyType_GetTextSignatureFromInternalDoc(m->m_ml->ml_name, m->m_ml->ml_doc);
165
0
}
166
167
static PyObject *
168
meth_get__doc__(PyCFunctionObject *m, void *closure)
169
0
{
170
0
    return _PyType_GetDocFromInternalDoc(m->m_ml->ml_name, m->m_ml->ml_doc);
171
0
}
172
173
static PyObject *
174
meth_get__name__(PyCFunctionObject *m, void *closure)
175
0
{
176
0
    return PyUnicode_FromString(m->m_ml->ml_name);
177
0
}
178
179
static PyObject *
180
meth_get__qualname__(PyCFunctionObject *m, void *closure)
181
0
{
182
    /* If __self__ is a module or NULL, return m.__name__
183
       (e.g. len.__qualname__ == 'len')
184
185
       If __self__ is a type, return m.__self__.__qualname__ + '.' + m.__name__
186
       (e.g. dict.fromkeys.__qualname__ == 'dict.fromkeys')
187
188
       Otherwise return type(m.__self__).__qualname__ + '.' + m.__name__
189
       (e.g. [].append.__qualname__ == 'list.append') */
190
0
    PyObject *type, *type_qualname, *res;
191
0
    _Py_IDENTIFIER(__qualname__);
192
193
0
    if (m->m_self == NULL || PyModule_Check(m->m_self))
194
0
        return PyUnicode_FromString(m->m_ml->ml_name);
195
196
0
    type = PyType_Check(m->m_self) ? m->m_self : (PyObject*)Py_TYPE(m->m_self);
197
198
0
    type_qualname = _PyObject_GetAttrId(type, &PyId___qualname__);
199
0
    if (type_qualname == NULL)
200
0
        return NULL;
201
202
0
    if (!PyUnicode_Check(type_qualname)) {
203
0
        PyErr_SetString(PyExc_TypeError, "<method>.__class__."
204
0
                        "__qualname__ is not a unicode object");
205
0
        Py_XDECREF(type_qualname);
206
0
        return NULL;
207
0
    }
208
209
0
    res = PyUnicode_FromFormat("%S.%s", type_qualname, m->m_ml->ml_name);
210
0
    Py_DECREF(type_qualname);
211
0
    return res;
212
0
}
213
214
static int
215
meth_traverse(PyCFunctionObject *m, visitproc visit, void *arg)
216
16.4k
{
217
16.4k
    Py_VISIT(m->m_self);
218
16.4k
    Py_VISIT(m->m_module);
219
16.4k
    return 0;
220
16.4k
}
221
222
static PyObject *
223
meth_get__self__(PyCFunctionObject *m, void *closure)
224
1
{
225
1
    PyObject *self;
226
227
1
    self = PyCFunction_GET_SELF(m);
228
1
    if (self == NULL)
229
0
        self = Py_None;
230
1
    Py_INCREF(self);
231
1
    return self;
232
1
}
233
234
static PyGetSetDef meth_getsets [] = {
235
    {"__doc__",  (getter)meth_get__doc__,  NULL, NULL},
236
    {"__name__", (getter)meth_get__name__, NULL, NULL},
237
    {"__qualname__", (getter)meth_get__qualname__, NULL, NULL},
238
    {"__self__", (getter)meth_get__self__, NULL, NULL},
239
    {"__text_signature__", (getter)meth_get__text_signature__, NULL, NULL},
240
    {0}
241
};
242
243
#define OFF(x) offsetof(PyCFunctionObject, x)
244
245
static PyMemberDef meth_members[] = {
246
    {"__module__",    T_OBJECT,     OFF(m_module), PY_WRITE_RESTRICTED},
247
    {NULL}
248
};
249
250
static PyObject *
251
meth_repr(PyCFunctionObject *m)
252
0
{
253
0
    if (m->m_self == NULL || PyModule_Check(m->m_self))
254
0
        return PyUnicode_FromFormat("<built-in function %s>",
255
0
                                   m->m_ml->ml_name);
256
0
    return PyUnicode_FromFormat("<built-in method %s of %s object at %p>",
257
0
                               m->m_ml->ml_name,
258
0
                               m->m_self->ob_type->tp_name,
259
0
                               m->m_self);
260
0
}
261
262
static PyObject *
263
meth_richcompare(PyObject *self, PyObject *other, int op)
264
0
{
265
0
    PyCFunctionObject *a, *b;
266
0
    PyObject *res;
267
0
    int eq;
268
269
0
    if ((op != Py_EQ && op != Py_NE) ||
270
0
        !PyCFunction_Check(self) ||
271
0
        !PyCFunction_Check(other))
272
0
    {
273
0
        Py_RETURN_NOTIMPLEMENTED;
274
0
    }
275
0
    a = (PyCFunctionObject *)self;
276
0
    b = (PyCFunctionObject *)other;
277
0
    eq = a->m_self == b->m_self;
278
0
    if (eq)
279
0
        eq = a->m_ml->ml_meth == b->m_ml->ml_meth;
280
0
    if (op == Py_EQ)
281
0
        res = eq ? Py_True : Py_False;
282
0
    else
283
0
        res = eq ? Py_False : Py_True;
284
0
    Py_INCREF(res);
285
0
    return res;
286
0
}
287
288
static Py_hash_t
289
meth_hash(PyCFunctionObject *a)
290
618
{
291
618
    Py_hash_t x, y;
292
618
    x = _Py_HashPointer(a->m_self);
293
618
    y = _Py_HashPointer((void*)(a->m_ml->ml_meth));
294
618
    x ^= y;
295
618
    if (x == -1)
296
0
        x = -2;
297
618
    return x;
298
618
}
299
300
301
PyTypeObject PyCFunction_Type = {
302
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
303
    "builtin_function_or_method",
304
    sizeof(PyCFunctionObject),
305
    0,
306
    (destructor)meth_dealloc,                   /* tp_dealloc */
307
    offsetof(PyCFunctionObject, vectorcall),    /* tp_vectorcall_offset */
308
    0,                                          /* tp_getattr */
309
    0,                                          /* tp_setattr */
310
    0,                                          /* tp_as_async */
311
    (reprfunc)meth_repr,                        /* tp_repr */
312
    0,                                          /* tp_as_number */
313
    0,                                          /* tp_as_sequence */
314
    0,                                          /* tp_as_mapping */
315
    (hashfunc)meth_hash,                        /* tp_hash */
316
    PyCFunction_Call,                           /* tp_call */
317
    0,                                          /* tp_str */
318
    PyObject_GenericGetAttr,                    /* tp_getattro */
319
    0,                                          /* tp_setattro */
320
    0,                                          /* tp_as_buffer */
321
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
322
    _Py_TPFLAGS_HAVE_VECTORCALL,                /* tp_flags */
323
    0,                                          /* tp_doc */
324
    (traverseproc)meth_traverse,                /* tp_traverse */
325
    0,                                          /* tp_clear */
326
    meth_richcompare,                           /* tp_richcompare */
327
    offsetof(PyCFunctionObject, m_weakreflist), /* tp_weaklistoffset */
328
    0,                                          /* tp_iter */
329
    0,                                          /* tp_iternext */
330
    meth_methods,                               /* tp_methods */
331
    meth_members,                               /* tp_members */
332
    meth_getsets,                               /* tp_getset */
333
    0,                                          /* tp_base */
334
    0,                                          /* tp_dict */
335
};
336
337
/* Clear out the free list */
338
339
int
340
PyCFunction_ClearFreeList(void)
341
0
{
342
0
    int freelist_size = numfree;
343
344
0
    while (free_list) {
345
0
        PyCFunctionObject *v = free_list;
346
0
        free_list = (PyCFunctionObject *)(v->m_self);
347
0
        PyObject_GC_Del(v);
348
0
        numfree--;
349
0
    }
350
0
    assert(numfree == 0);
351
0
    return freelist_size;
352
0
}
353
354
void
355
PyCFunction_Fini(void)
356
0
{
357
0
    (void)PyCFunction_ClearFreeList();
358
0
}
359
360
/* Print summary info about the state of the optimized allocator */
361
void
362
_PyCFunction_DebugMallocStats(FILE *out)
363
0
{
364
0
    _PyDebugAllocatorStats(out,
365
0
                           "free PyCFunctionObject",
366
0
                           numfree, sizeof(PyCFunctionObject));
367
0
}
368
369
370
/* Vectorcall functions for each of the PyCFunction calling conventions,
371
 * except for METH_VARARGS (possibly combined with METH_KEYWORDS) which
372
 * doesn't use vectorcall.
373
 *
374
 * First, common helpers
375
 */
376
static const char *
377
get_name(PyObject *func)
378
0
{
379
0
    assert(PyCFunction_Check(func));
380
0
    PyMethodDef *method = ((PyCFunctionObject *)func)->m_ml;
381
0
    return method->ml_name;
382
0
}
383
384
typedef void (*funcptr)(void);
385
386
static inline int
387
cfunction_check_kwargs(PyObject *func, PyObject *kwnames)
388
25.8k
{
389
25.8k
    assert(!PyErr_Occurred());
390
25.8k
    assert(PyCFunction_Check(func));
391
25.8k
    if (kwnames && PyTuple_GET_SIZE(kwnames)) {
392
0
        PyErr_Format(PyExc_TypeError,
393
0
                     "%.200s() takes no keyword arguments", get_name(func));
394
0
        return -1;
395
0
    }
396
25.8k
    return 0;
397
25.8k
}
398
399
static inline funcptr
400
cfunction_enter_call(PyObject *func)
401
32.3k
{
402
32.3k
    if (Py_EnterRecursiveCall(" while calling a Python object")) {
403
0
        return NULL;
404
0
    }
405
32.3k
    return (funcptr)PyCFunction_GET_FUNCTION(func);
406
32.3k
}
407
408
/* Now the actual vectorcall functions */
409
static PyObject *
410
cfunction_vectorcall_FASTCALL(
411
    PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
412
10.7k
{
413
10.7k
    if (cfunction_check_kwargs(func, kwnames)) {
414
0
        return NULL;
415
0
    }
416
10.7k
    Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
417
10.7k
    _PyCFunctionFast meth = (_PyCFunctionFast)
418
10.7k
                            cfunction_enter_call(func);
419
10.7k
    if (meth == NULL) {
420
0
        return NULL;
421
0
    }
422
10.7k
    PyObject *result = meth(PyCFunction_GET_SELF(func), args, nargs);
423
10.7k
    Py_LeaveRecursiveCall();
424
10.7k
    return result;
425
10.7k
}
426
427
static PyObject *
428
cfunction_vectorcall_FASTCALL_KEYWORDS(
429
    PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
430
6.52k
{
431
6.52k
    Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
432
6.52k
    _PyCFunctionFastWithKeywords meth = (_PyCFunctionFastWithKeywords)
433
6.52k
                                        cfunction_enter_call(func);
434
6.52k
    if (meth == NULL) {
435
0
        return NULL;
436
0
    }
437
6.52k
    PyObject *result = meth(PyCFunction_GET_SELF(func), args, nargs, kwnames);
438
6.52k
    Py_LeaveRecursiveCall();
439
6.52k
    return result;
440
6.52k
}
441
442
static PyObject *
443
cfunction_vectorcall_NOARGS(
444
    PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
445
9.33k
{
446
9.33k
    if (cfunction_check_kwargs(func, kwnames)) {
447
0
        return NULL;
448
0
    }
449
9.33k
    Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
450
9.33k
    if (nargs != 0) {
451
0
        PyErr_Format(PyExc_TypeError,
452
0
            "%.200s() takes no arguments (%zd given)", get_name(func), nargs);
453
0
        return NULL;
454
0
    }
455
9.33k
    PyCFunction meth = (PyCFunction)cfunction_enter_call(func);
456
9.33k
    if (meth == NULL) {
457
0
        return NULL;
458
0
    }
459
9.33k
    PyObject *result = meth(PyCFunction_GET_SELF(func), NULL);
460
9.33k
    Py_LeaveRecursiveCall();
461
9.33k
    return result;
462
9.33k
}
463
464
static PyObject *
465
cfunction_vectorcall_O(
466
    PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
467
5.75k
{
468
5.75k
    if (cfunction_check_kwargs(func, kwnames)) {
469
0
        return NULL;
470
0
    }
471
5.75k
    Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
472
5.75k
    if (nargs != 1) {
473
0
        PyErr_Format(PyExc_TypeError,
474
0
            "%.200s() takes exactly one argument (%zd given)",
475
0
            get_name(func), nargs);
476
0
        return NULL;
477
0
    }
478
5.75k
    PyCFunction meth = (PyCFunction)cfunction_enter_call(func);
479
5.75k
    if (meth == NULL) {
480
0
        return NULL;
481
0
    }
482
5.75k
    PyObject *result = meth(PyCFunction_GET_SELF(func), args[0]);
483
5.75k
    Py_LeaveRecursiveCall();
484
5.75k
    return result;
485
5.75k
}