Files
typthon/Modules/_testcapimodule.c
copilot-swe-agent[bot] 0f2e4eb3fd Fix final Py_ patterns - uintptr, arithmetic shift, inc files
- Fixed Py_uintptr_t → Ty_uintptr_t
- Fixed Py_ARITHMETIC_RIGHT_SHIFT → Ty_ARITHMETIC_RIGHT_SHIFT
- Fixed PyTypeObject, PyNumberMethods, PyAsyncMethods in .inc files

Build is nearing completion.

Co-authored-by: johndoe6345789 <224850594+johndoe6345789@users.noreply.github.com>
2025-12-29 18:38:56 +00:00

3484 lines
102 KiB
C

/*
* C Extension module to test Python interpreter C APIs.
*
* The 'test_*' functions exported by this module are run as part of the
* standard Python regression test, via Lib/test/test_capi.py.
*/
// Include parts.h first since it takes care of NDEBUG and Ty_BUILD_CORE macros
// and including Python.h.
//
// Several parts of this module are broken out into files in _testcapi/.
// Include definitions from there.
#include "_testcapi/parts.h"
#include "frameobject.h" // TyFrame_New()
#include "marshal.h" // TyMarshal_WriteLongToFile()
#include <float.h> // FLT_MAX
#include <signal.h>
#include <stddef.h> // offsetof()
#ifdef HAVE_SYS_WAIT_H
# include <sys/wait.h> // W_STOPCODE
#endif
#ifdef bool
# error "The public headers should not include <stdbool.h>, see gh-48924"
#endif
#include "_testcapi/util.h"
// Forward declarations
static struct TyModuleDef _testcapimodule;
// Module state
typedef struct {
TyObject *error; // _testcapi.error object
} testcapistate_t;
static testcapistate_t*
get_testcapi_state(TyObject *module)
{
void *state = TyModule_GetState(module);
assert(state != NULL);
return (testcapistate_t *)state;
}
static TyObject *
get_testerror(TyObject *self) {
testcapistate_t *state = get_testcapi_state(self);
return state->error;
}
static void
simple_object_dealloc(TyObject *self)
{
PyObject_Free(self);
}
/* Raise _testcapi.error with test_name + ": " + msg, and return NULL. */
static TyObject *
raiseTestError(TyObject *self, const char* test_name, const char* msg)
{
TyErr_Format(get_testerror(self), "%s: %s", test_name, msg);
return NULL;
}
/* Test #defines from pyconfig.h (particularly the SIZEOF_* defines).
The ones derived from autoconf on the UNIX-like OSes can be relied
upon (in the absence of sloppy cross-compiling), but the Windows
platforms have these hardcoded. Better safe than sorry.
*/
static TyObject*
sizeof_error(TyObject *self, const char* fatname, const char* typname,
int expected, int got)
{
TyErr_Format(get_testerror(self),
"%s #define == %d but sizeof(%s) == %d",
fatname, expected, typname, got);
return (TyObject*)NULL;
}
static TyObject*
test_config(TyObject *self, TyObject *Py_UNUSED(ignored))
{
#define CHECK_SIZEOF(FATNAME, TYPE) \
do { \
if (FATNAME != sizeof(TYPE)) { \
return sizeof_error(self, #FATNAME, #TYPE, FATNAME, sizeof(TYPE)); \
} \
} while (0)
CHECK_SIZEOF(SIZEOF_SHORT, short);
CHECK_SIZEOF(SIZEOF_INT, int);
CHECK_SIZEOF(SIZEOF_LONG, long);
CHECK_SIZEOF(SIZEOF_VOID_P, void*);
CHECK_SIZEOF(SIZEOF_TIME_T, time_t);
CHECK_SIZEOF(SIZEOF_LONG_LONG, long long);
#undef CHECK_SIZEOF
Py_RETURN_NONE;
}
static TyObject*
test_sizeof_c_types(TyObject *self, TyObject *Py_UNUSED(ignored))
{
#if defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wtype-limits"
#endif
#define CHECK_SIZEOF(TYPE, EXPECTED) \
do { \
if (EXPECTED != sizeof(TYPE)) { \
TyErr_Format(get_testerror(self), \
"sizeof(%s) = %u instead of %u", \
#TYPE, sizeof(TYPE), EXPECTED); \
return (TyObject*)NULL; \
} \
} while (0)
#define IS_SIGNED(TYPE) (((TYPE)-1) < (TYPE)0)
#define CHECK_SIGNNESS(TYPE, SIGNED) \
do { \
if (IS_SIGNED(TYPE) != SIGNED) { \
TyErr_Format(get_testerror(self), \
"%s signness is %i, instead of %i", \
#TYPE, IS_SIGNED(TYPE), SIGNED); \
return (TyObject*)NULL; \
} \
} while (0)
/* integer types */
CHECK_SIZEOF(Ty_UCS1, 1);
CHECK_SIZEOF(Ty_UCS2, 2);
CHECK_SIZEOF(Ty_UCS4, 4);
CHECK_SIGNNESS(Ty_UCS1, 0);
CHECK_SIGNNESS(Ty_UCS2, 0);
CHECK_SIGNNESS(Ty_UCS4, 0);
CHECK_SIZEOF(int32_t, 4);
CHECK_SIGNNESS(int32_t, 1);
CHECK_SIZEOF(uint32_t, 4);
CHECK_SIGNNESS(uint32_t, 0);
CHECK_SIZEOF(int64_t, 8);
CHECK_SIGNNESS(int64_t, 1);
CHECK_SIZEOF(uint64_t, 8);
CHECK_SIGNNESS(uint64_t, 0);
/* pointer/size types */
CHECK_SIZEOF(size_t, sizeof(void *));
CHECK_SIGNNESS(size_t, 0);
CHECK_SIZEOF(Ty_ssize_t, sizeof(void *));
CHECK_SIGNNESS(Ty_ssize_t, 1);
CHECK_SIZEOF(uintptr_t, sizeof(void *));
CHECK_SIGNNESS(uintptr_t, 0);
CHECK_SIZEOF(intptr_t, sizeof(void *));
CHECK_SIGNNESS(intptr_t, 1);
Py_RETURN_NONE;
#undef IS_SIGNED
#undef CHECK_SIGNESS
#undef CHECK_SIZEOF
#if defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))
#pragma GCC diagnostic pop
#endif
}
/* Issue #4701: Check that PyObject_Hash implicitly calls
* TyType_Ready if it hasn't already been called
*/
static TyTypeObject _HashInheritanceTester_Type = {
TyVarObject_HEAD_INIT(NULL, 0)
"hashinheritancetester", /* Name of this type */
sizeof(TyObject), /* Basic object size */
0, /* Item size for varobject */
simple_object_dealloc, /* tp_dealloc */
0, /* tp_vectorcall_offset */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_as_async */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Ty_TPFLAGS_DEFAULT, /* tp_flags */
0, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
TyType_GenericNew, /* tp_new */
};
static TyObject*
pycompilestring(TyObject* self, TyObject *obj) {
if (TyBytes_CheckExact(obj) == 0) {
TyErr_SetString(TyExc_ValueError, "Argument must be a bytes object");
return NULL;
}
const char *the_string = TyBytes_AsString(obj);
if (the_string == NULL) {
return NULL;
}
return Ty_CompileString(the_string, "<string>", Ty_file_input);
}
static TyObject*
test_lazy_hash_inheritance(TyObject* self, TyObject *Py_UNUSED(ignored))
{
TyTypeObject *type;
TyObject *obj;
Ty_hash_t hash;
type = &_HashInheritanceTester_Type;
if (type->tp_dict != NULL)
/* The type has already been initialized. This probably means
-R is being used. */
Py_RETURN_NONE;
obj = PyObject_New(TyObject, type);
if (obj == NULL) {
TyErr_Clear();
TyErr_SetString(
get_testerror(self),
"test_lazy_hash_inheritance: failed to create object");
return NULL;
}
if (type->tp_dict != NULL) {
TyErr_SetString(
get_testerror(self),
"test_lazy_hash_inheritance: type initialised too soon");
Ty_DECREF(obj);
return NULL;
}
hash = PyObject_Hash(obj);
if ((hash == -1) && TyErr_Occurred()) {
TyErr_Clear();
TyErr_SetString(
get_testerror(self),
"test_lazy_hash_inheritance: could not hash object");
Ty_DECREF(obj);
return NULL;
}
if (type->tp_dict == NULL) {
TyErr_SetString(
get_testerror(self),
"test_lazy_hash_inheritance: type not initialised by hash()");
Ty_DECREF(obj);
return NULL;
}
if (type->tp_hash != TyType_Type.tp_hash) {
TyErr_SetString(
get_testerror(self),
"test_lazy_hash_inheritance: unexpected hash function");
Ty_DECREF(obj);
return NULL;
}
Ty_DECREF(obj);
Py_RETURN_NONE;
}
static TyObject *
return_none(void *unused)
{
Py_RETURN_NONE;
}
static TyObject *
raise_error(void *unused)
{
TyErr_SetNone(TyExc_ValueError);
return NULL;
}
static TyObject *
py_buildvalue(TyObject *self, TyObject *args)
{
const char *fmt;
TyObject *objs[10] = {NULL};
if (!TyArg_ParseTuple(args, "s|OOOOOOOOOO", &fmt,
&objs[0], &objs[1], &objs[2], &objs[3], &objs[4],
&objs[5], &objs[6], &objs[7], &objs[8], &objs[9]))
{
return NULL;
}
for(int i = 0; i < 10; i++) {
NULLABLE(objs[i]);
}
return Ty_BuildValue(fmt,
objs[0], objs[1], objs[2], objs[3], objs[4],
objs[5], objs[6], objs[7], objs[8], objs[9]);
}
static TyObject *
py_buildvalue_ints(TyObject *self, TyObject *args)
{
const char *fmt;
unsigned int values[10] = {0};
if (!TyArg_ParseTuple(args, "s|IIIIIIIIII", &fmt,
&values[0], &values[1], &values[2], &values[3], &values[4],
&values[5], &values[6], &values[7], &values[8], &values[9]))
{
return NULL;
}
return Ty_BuildValue(fmt,
values[0], values[1], values[2], values[3], values[4],
values[5], values[6], values[7], values[8], values[9]);
}
static int
test_buildvalue_N_error(TyObject *self, const char *fmt)
{
TyObject *arg, *res;
arg = TyList_New(0);
if (arg == NULL) {
return -1;
}
Ty_INCREF(arg);
res = Ty_BuildValue(fmt, return_none, NULL, arg);
if (res == NULL) {
return -1;
}
Ty_DECREF(res);
if (Ty_REFCNT(arg) != 1) {
TyErr_Format(get_testerror(self), "test_buildvalue_N: "
"arg was not decrefed in successful "
"Ty_BuildValue(\"%s\")", fmt);
return -1;
}
Ty_INCREF(arg);
res = Ty_BuildValue(fmt, raise_error, NULL, arg);
if (res != NULL || !TyErr_Occurred()) {
TyErr_Format(get_testerror(self), "test_buildvalue_N: "
"Ty_BuildValue(\"%s\") didn't complain", fmt);
return -1;
}
TyErr_Clear();
if (Ty_REFCNT(arg) != 1) {
TyErr_Format(get_testerror(self), "test_buildvalue_N: "
"arg was not decrefed in failed "
"Ty_BuildValue(\"%s\")", fmt);
return -1;
}
Ty_DECREF(arg);
return 0;
}
static TyObject *
test_buildvalue_N(TyObject *self, TyObject *Py_UNUSED(ignored))
{
TyObject *arg, *res;
arg = TyList_New(0);
if (arg == NULL) {
return NULL;
}
Ty_INCREF(arg);
res = Ty_BuildValue("N", arg);
if (res == NULL) {
return NULL;
}
if (res != arg) {
return raiseTestError(self, "test_buildvalue_N",
"Ty_BuildValue(\"N\") returned wrong result");
}
if (Ty_REFCNT(arg) != 2) {
return raiseTestError(self, "test_buildvalue_N",
"arg was not decrefed in Ty_BuildValue(\"N\")");
}
Ty_DECREF(res);
Ty_DECREF(arg);
if (test_buildvalue_N_error(self, "O&N") < 0)
return NULL;
if (test_buildvalue_N_error(self, "(O&N)") < 0)
return NULL;
if (test_buildvalue_N_error(self, "[O&N]") < 0)
return NULL;
if (test_buildvalue_N_error(self, "{O&N}") < 0)
return NULL;
if (test_buildvalue_N_error(self, "{()O&(())N}") < 0)
return NULL;
Py_RETURN_NONE;
}
static TyObject *
test_buildvalue_p(TyObject *self, TyObject *Py_UNUSED(ignored))
{
TyObject *res = Ty_BuildValue("p", 3);
if (res == NULL) {
return NULL;
}
if (!Ty_IsTrue(res)) {
Ty_DECREF(res);
return raiseTestError(self, "test_buildvalue_p", "Ty_BuildValue(\"p\", 3) returned wrong result");
}
Ty_DECREF(res);
res = Ty_BuildValue("p", 0);
if (res == NULL) {
return NULL;
}
if (!Ty_IsFalse(res)) {
Ty_DECREF(res);
return raiseTestError(self, "test_buildvalue_p", "Ty_BuildValue(\"p\", 0) returned wrong result");
}
Ty_DECREF(res);
Py_RETURN_NONE;
}
static TyObject *
pyobject_repr_from_null(TyObject *self, TyObject *Py_UNUSED(ignored))
{
return PyObject_Repr(NULL);
}
static TyObject *
pyobject_str_from_null(TyObject *self, TyObject *Py_UNUSED(ignored))
{
return PyObject_Str(NULL);
}
static TyObject *
pyobject_bytes_from_null(TyObject *self, TyObject *Py_UNUSED(ignored))
{
return PyObject_Bytes(NULL);
}
static TyObject *
set_errno(TyObject *self, TyObject *args)
{
int new_errno;
if (!TyArg_ParseTuple(args, "i:set_errno", &new_errno))
return NULL;
errno = new_errno;
Py_RETURN_NONE;
}
/* test_thread_state spawns a thread of its own, and that thread releases
* `thread_done` when it's finished. The driver code has to know when the
* thread finishes, because the thread uses a TyObject (the callable) that
* may go away when the driver finishes. The former lack of this explicit
* synchronization caused rare segfaults, so rare that they were seen only
* on a Mac buildbot (although they were possible on any box).
*/
static TyThread_type_lock thread_done = NULL;
static int
_make_call(void *callable)
{
TyObject *rc;
int success;
TyGILState_STATE s = TyGILState_Ensure();
rc = PyObject_CallNoArgs((TyObject *)callable);
success = (rc != NULL);
Ty_XDECREF(rc);
TyGILState_Release(s);
return success;
}
/* Same thing, but releases `thread_done` when it returns. This variant
* should be called only from threads spawned by test_thread_state().
*/
static void
_make_call_from_thread(void *callable)
{
_make_call(callable);
TyThread_release_lock(thread_done);
}
static TyObject *
test_thread_state(TyObject *self, TyObject *args)
{
TyObject *fn;
int success = 1;
if (!TyArg_ParseTuple(args, "O:test_thread_state", &fn))
return NULL;
if (!PyCallable_Check(fn)) {
TyErr_Format(TyExc_TypeError, "'%s' object is not callable",
Ty_TYPE(fn)->tp_name);
return NULL;
}
thread_done = TyThread_allocate_lock();
if (thread_done == NULL)
return TyErr_NoMemory();
TyThread_acquire_lock(thread_done, 1);
/* Start a new thread with our callback. */
TyThread_start_new_thread(_make_call_from_thread, fn);
/* Make the callback with the thread lock held by this thread */
success &= _make_call(fn);
/* Do it all again, but this time with the thread-lock released */
Ty_BEGIN_ALLOW_THREADS
success &= _make_call(fn);
TyThread_acquire_lock(thread_done, 1); /* wait for thread to finish */
Ty_END_ALLOW_THREADS
/* And once more with and without a thread
XXX - should use a lock and work out exactly what we are trying
to test <wink>
*/
Ty_BEGIN_ALLOW_THREADS
TyThread_start_new_thread(_make_call_from_thread, fn);
success &= _make_call(fn);
TyThread_acquire_lock(thread_done, 1); /* wait for thread to finish */
Ty_END_ALLOW_THREADS
/* Release lock we acquired above. This is required on HP-UX. */
TyThread_release_lock(thread_done);
TyThread_free_lock(thread_done);
if (!success)
return NULL;
Py_RETURN_NONE;
}
static TyObject *
gilstate_ensure_release(TyObject *module, TyObject *Py_UNUSED(ignored))
{
TyGILState_STATE state = TyGILState_Ensure();
TyGILState_Release(state);
Py_RETURN_NONE;
}
#ifndef MS_WINDOWS
static TyThread_type_lock wait_done = NULL;
static void wait_for_lock(void *unused) {
TyThread_acquire_lock(wait_done, 1);
TyThread_release_lock(wait_done);
TyThread_free_lock(wait_done);
wait_done = NULL;
}
// These can be used to test things that care about the existence of another
// thread that the threading module doesn't know about.
static TyObject *
spawn_pthread_waiter(TyObject *self, TyObject *Py_UNUSED(ignored))
{
if (wait_done) {
TyErr_SetString(TyExc_RuntimeError, "thread already running");
return NULL;
}
wait_done = TyThread_allocate_lock();
if (wait_done == NULL)
return TyErr_NoMemory();
TyThread_acquire_lock(wait_done, 1);
TyThread_start_new_thread(wait_for_lock, NULL);
Py_RETURN_NONE;
}
static TyObject *
end_spawned_pthread(TyObject *self, TyObject *Py_UNUSED(ignored))
{
if (!wait_done) {
TyErr_SetString(TyExc_RuntimeError, "call _spawn_pthread_waiter 1st");
return NULL;
}
TyThread_release_lock(wait_done);
Py_RETURN_NONE;
}
#endif // not MS_WINDOWS
/* test Ty_AddPendingCalls using threads */
static int _pending_callback(void *arg)
{
/* we assume the argument is callable object to which we own a reference */
TyObject *callable = (TyObject *)arg;
TyObject *r = PyObject_CallNoArgs(callable);
Ty_DECREF(callable);
Ty_XDECREF(r);
return r != NULL ? 0 : -1;
}
/* The following requests n callbacks to _pending_callback. It can be
* run from any python thread.
*/
static TyObject *
pending_threadfunc(TyObject *self, TyObject *arg, TyObject *kwargs)
{
static char *kwlist[] = {"callback", "num",
"blocking", "ensure_added", NULL};
TyObject *callable;
unsigned int num = 1;
int blocking = 0;
int ensure_added = 0;
if (!TyArg_ParseTupleAndKeywords(arg, kwargs,
"O|I$pp:_pending_threadfunc", kwlist,
&callable, &num, &blocking, &ensure_added))
{
return NULL;
}
/* create the reference for the callbackwhile we hold the lock */
for (unsigned int i = 0; i < num; i++) {
Ty_INCREF(callable);
}
TyThreadState *save_tstate = NULL;
if (!blocking) {
save_tstate = TyEval_SaveThread();
}
unsigned int num_added = 0;
for (; num_added < num; num_added++) {
if (ensure_added) {
int r;
do {
r = Ty_AddPendingCall(&_pending_callback, callable);
} while (r < 0);
}
else {
if (Ty_AddPendingCall(&_pending_callback, callable) < 0) {
break;
}
}
}
if (!blocking) {
TyEval_RestoreThread(save_tstate);
}
for (unsigned int i = num_added; i < num; i++) {
Ty_DECREF(callable); /* unsuccessful add, destroy the extra reference */
}
/* The callable is decref'ed above in each added _pending_callback(). */
return TyLong_FromUnsignedLong((unsigned long)num_added);
}
/* Coverage testing of capsule objects. */
static const char *capsule_name = "capsule name";
static char *capsule_pointer = "capsule pointer";
static char *capsule_context = "capsule context";
static const char *capsule_error = NULL;
static int
capsule_destructor_call_count = 0;
static void
capsule_destructor(TyObject *o) {
capsule_destructor_call_count++;
if (PyCapsule_GetContext(o) != capsule_context) {
capsule_error = "context did not match in destructor!";
} else if (PyCapsule_GetDestructor(o) != capsule_destructor) {
capsule_error = "destructor did not match in destructor! (woah!)";
} else if (PyCapsule_GetName(o) != capsule_name) {
capsule_error = "name did not match in destructor!";
} else if (PyCapsule_GetPointer(o, capsule_name) != capsule_pointer) {
capsule_error = "pointer did not match in destructor!";
}
}
typedef struct {
char *name;
char *module;
char *attribute;
} known_capsule;
static TyObject *
test_capsule(TyObject *self, TyObject *Py_UNUSED(ignored))
{
TyObject *object;
const char *error = NULL;
void *pointer;
void *pointer2;
known_capsule known_capsules[] = {
#define KNOWN_CAPSULE(module, name) { module "." name, module, name }
KNOWN_CAPSULE("_socket", "CAPI"),
KNOWN_CAPSULE("_curses", "_C_API"),
KNOWN_CAPSULE("datetime", "datetime_CAPI"),
{ NULL, NULL },
};
known_capsule *known = &known_capsules[0];
#define FAIL(x) \
do { \
error = (x); \
goto exit; \
} while (0)
#define CHECK_DESTRUCTOR \
do { \
if (capsule_error) { \
FAIL(capsule_error); \
} \
else if (!capsule_destructor_call_count) { \
FAIL("destructor not called!"); \
} \
capsule_destructor_call_count = 0; \
} while (0)
object = PyCapsule_New(capsule_pointer, capsule_name, capsule_destructor);
PyCapsule_SetContext(object, capsule_context);
capsule_destructor(object);
CHECK_DESTRUCTOR;
Ty_DECREF(object);
CHECK_DESTRUCTOR;
object = PyCapsule_New(known, "ignored", NULL);
PyCapsule_SetPointer(object, capsule_pointer);
PyCapsule_SetName(object, capsule_name);
PyCapsule_SetDestructor(object, capsule_destructor);
PyCapsule_SetContext(object, capsule_context);
capsule_destructor(object);
CHECK_DESTRUCTOR;
/* intentionally access using the wrong name */
pointer2 = PyCapsule_GetPointer(object, "the wrong name");
if (!TyErr_Occurred()) {
FAIL("PyCapsule_GetPointer should have failed but did not!");
}
TyErr_Clear();
if (pointer2) {
if (pointer2 == capsule_pointer) {
FAIL("PyCapsule_GetPointer should not have"
" returned the internal pointer!");
} else {
FAIL("PyCapsule_GetPointer should have "
"returned NULL pointer but did not!");
}
}
PyCapsule_SetDestructor(object, NULL);
Ty_DECREF(object);
if (capsule_destructor_call_count) {
FAIL("destructor called when it should not have been!");
}
for (known = &known_capsules[0]; known->module != NULL; known++) {
/* yeah, ordinarily I wouldn't do this either,
but it's fine for this test harness.
*/
static char buffer[256];
#undef FAIL
#define FAIL(x) \
do { \
sprintf(buffer, "%s module: \"%s\" attribute: \"%s\"", \
x, known->module, known->attribute); \
error = buffer; \
goto exit; \
} while (0)
TyObject *module = TyImport_ImportModule(known->module);
if (module) {
pointer = PyCapsule_Import(known->name, 0);
if (!pointer) {
Ty_DECREF(module);
FAIL("PyCapsule_GetPointer returned NULL unexpectedly!");
}
object = PyObject_GetAttrString(module, known->attribute);
if (!object) {
Ty_DECREF(module);
return NULL;
}
pointer2 = PyCapsule_GetPointer(object,
"weebles wobble but they don't fall down");
if (!TyErr_Occurred()) {
Ty_DECREF(object);
Ty_DECREF(module);
FAIL("PyCapsule_GetPointer should have failed but did not!");
}
TyErr_Clear();
if (pointer2) {
Ty_DECREF(module);
Ty_DECREF(object);
if (pointer2 == pointer) {
FAIL("PyCapsule_GetPointer should not have"
" returned its internal pointer!");
} else {
FAIL("PyCapsule_GetPointer should have"
" returned NULL pointer but did not!");
}
}
Ty_DECREF(object);
Ty_DECREF(module);
}
else
TyErr_Clear();
}
exit:
if (error) {
return raiseTestError(self, "test_capsule", error);
}
Py_RETURN_NONE;
#undef FAIL
}
#ifdef HAVE_GETTIMEOFDAY
/* Profiling of integer performance */
static void print_delta(int test, struct timeval *s, struct timeval *e)
{
e->tv_sec -= s->tv_sec;
e->tv_usec -= s->tv_usec;
if (e->tv_usec < 0) {
e->tv_sec -=1;
e->tv_usec += 1000000;
}
printf("Test %d: %d.%06ds\n", test, (int)e->tv_sec, (int)e->tv_usec);
}
static TyObject *
profile_int(TyObject *self, TyObject* args)
{
int i, k;
struct timeval start, stop;
TyObject *single, **multiple, *op1, *result;
/* Test 1: Allocate and immediately deallocate
many small integers */
gettimeofday(&start, NULL);
for(k=0; k < 20000; k++)
for(i=0; i < 1000; i++) {
single = TyLong_FromLong(i);
Ty_DECREF(single);
}
gettimeofday(&stop, NULL);
print_delta(1, &start, &stop);
/* Test 2: Allocate and immediately deallocate
many large integers */
gettimeofday(&start, NULL);
for(k=0; k < 20000; k++)
for(i=0; i < 1000; i++) {
single = TyLong_FromLong(i+1000000);
Ty_DECREF(single);
}
gettimeofday(&stop, NULL);
print_delta(2, &start, &stop);
/* Test 3: Allocate a few integers, then release
them all simultaneously. */
multiple = malloc(sizeof(TyObject*) * 1000);
if (multiple == NULL)
return TyErr_NoMemory();
gettimeofday(&start, NULL);
for(k=0; k < 20000; k++) {
for(i=0; i < 1000; i++) {
multiple[i] = TyLong_FromLong(i+1000000);
}
for(i=0; i < 1000; i++) {
Ty_DECREF(multiple[i]);
}
}
gettimeofday(&stop, NULL);
print_delta(3, &start, &stop);
free(multiple);
/* Test 4: Allocate many integers, then release
them all simultaneously. */
multiple = malloc(sizeof(TyObject*) * 1000000);
if (multiple == NULL)
return TyErr_NoMemory();
gettimeofday(&start, NULL);
for(k=0; k < 20; k++) {
for(i=0; i < 1000000; i++) {
multiple[i] = TyLong_FromLong(i+1000000);
}
for(i=0; i < 1000000; i++) {
Ty_DECREF(multiple[i]);
}
}
gettimeofday(&stop, NULL);
print_delta(4, &start, &stop);
free(multiple);
/* Test 5: Allocate many integers < 32000 */
multiple = malloc(sizeof(TyObject*) * 1000000);
if (multiple == NULL)
return TyErr_NoMemory();
gettimeofday(&start, NULL);
for(k=0; k < 10; k++) {
for(i=0; i < 1000000; i++) {
multiple[i] = TyLong_FromLong(i+1000);
}
for(i=0; i < 1000000; i++) {
Ty_DECREF(multiple[i]);
}
}
gettimeofday(&stop, NULL);
print_delta(5, &start, &stop);
free(multiple);
/* Test 6: Perform small int addition */
op1 = TyLong_FromLong(1);
gettimeofday(&start, NULL);
for(i=0; i < 10000000; i++) {
result = PyNumber_Add(op1, op1);
Ty_DECREF(result);
}
gettimeofday(&stop, NULL);
Ty_DECREF(op1);
print_delta(6, &start, &stop);
/* Test 7: Perform medium int addition */
op1 = TyLong_FromLong(1000);
if (op1 == NULL)
return NULL;
gettimeofday(&start, NULL);
for(i=0; i < 10000000; i++) {
result = PyNumber_Add(op1, op1);
Ty_XDECREF(result);
}
gettimeofday(&stop, NULL);
Ty_DECREF(op1);
print_delta(7, &start, &stop);
Py_RETURN_NONE;
}
#endif
/* Issue 6012 */
static TyObject *str1, *str2;
static int
failing_converter(TyObject *obj, void *arg)
{
/* Clone str1, then let the conversion fail. */
assert(str1);
str2 = Ty_NewRef(str1);
return 0;
}
static TyObject*
argparsing(TyObject *o, TyObject *args)
{
TyObject *res;
str1 = str2 = NULL;
if (!TyArg_ParseTuple(args, "O&O&",
TyUnicode_FSConverter, &str1,
failing_converter, &str2)) {
if (!str2)
/* argument converter not called? */
return NULL;
/* Should be 1 */
res = TyLong_FromSsize_t(Ty_REFCNT(str2));
Ty_DECREF(str2);
TyErr_Clear();
return res;
}
Py_RETURN_NONE;
}
/* To test that the result of TyCode_NewEmpty has the right members. */
static TyObject *
code_newempty(TyObject *self, TyObject *args)
{
const char *filename;
const char *funcname;
int firstlineno;
if (!TyArg_ParseTuple(args, "ssi:code_newempty",
&filename, &funcname, &firstlineno))
return NULL;
return (TyObject *)TyCode_NewEmpty(filename, funcname, firstlineno);
}
static TyObject *
make_memoryview_from_NULL_pointer(TyObject *self, TyObject *Py_UNUSED(ignored))
{
Ty_buffer info;
if (PyBuffer_FillInfo(&info, NULL, NULL, 1, 1, PyBUF_FULL_RO) < 0)
return NULL;
return TyMemoryView_FromBuffer(&info);
}
static TyObject *
buffer_fill_info(TyObject *self, TyObject *args)
{
Ty_buffer info;
const char *data;
Ty_ssize_t size;
int readonly;
int flags;
if (!TyArg_ParseTuple(args, "s#ii:buffer_fill_info",
&data, &size, &readonly, &flags)) {
return NULL;
}
if (PyBuffer_FillInfo(&info, NULL, (void *)data, size, readonly, flags) < 0) {
return NULL;
}
return TyMemoryView_FromBuffer(&info);
}
static TyObject *
test_from_contiguous(TyObject* self, TyObject *Py_UNUSED(ignored))
{
int data[9] = {-1,-1,-1,-1,-1,-1,-1,-1,-1};
int init[5] = {0, 1, 2, 3, 4};
Ty_ssize_t itemsize = sizeof(int);
Ty_ssize_t shape = 5;
Ty_ssize_t strides = 2 * itemsize;
Ty_buffer view = {
data,
NULL,
5 * itemsize,
itemsize,
1,
1,
NULL,
&shape,
&strides,
NULL,
NULL
};
int *ptr;
int i;
PyBuffer_FromContiguous(&view, init, view.len, 'C');
ptr = view.buf;
for (i = 0; i < 5; i++) {
if (ptr[2*i] != i) {
TyErr_SetString(get_testerror(self),
"test_from_contiguous: incorrect result");
return NULL;
}
}
view.buf = &data[8];
view.strides[0] = -2 * itemsize;
PyBuffer_FromContiguous(&view, init, view.len, 'C');
ptr = view.buf;
for (i = 0; i < 5; i++) {
if (*(ptr-2*i) != i) {
TyErr_SetString(get_testerror(self),
"test_from_contiguous: incorrect result");
return NULL;
}
}
Py_RETURN_NONE;
}
#if (defined(__linux__) || defined(__FreeBSD__)) && defined(__GNUC__)
static TyObject *
test_pep3118_obsolete_write_locks(TyObject* self, TyObject *Py_UNUSED(ignored))
{
TyObject *b;
char *dummy[1];
int ret, match;
/* PyBuffer_FillInfo() */
ret = PyBuffer_FillInfo(NULL, NULL, dummy, 1, 0, PyBUF_SIMPLE);
match = TyErr_Occurred() && TyErr_ExceptionMatches(TyExc_BufferError);
TyErr_Clear();
if (ret != -1 || match == 0)
goto error;
/* bytesiobuf_getbuffer() */
TyTypeObject *type = (TyTypeObject *)TyImport_ImportModuleAttrString(
"_io",
"_BytesIOBuffer");
if (type == NULL) {
return NULL;
}
b = type->tp_alloc(type, 0);
Ty_DECREF(type);
if (b == NULL) {
return NULL;
}
ret = PyObject_GetBuffer(b, NULL, PyBUF_SIMPLE);
Ty_DECREF(b);
match = TyErr_Occurred() && TyErr_ExceptionMatches(TyExc_BufferError);
TyErr_Clear();
if (ret != -1 || match == 0)
goto error;
Py_RETURN_NONE;
error:
TyErr_SetString(get_testerror(self),
"test_pep3118_obsolete_write_locks: failure");
return NULL;
}
#endif
/* This tests functions that historically supported write locks. It is
wrong to call getbuffer() with view==NULL and a compliant getbufferproc
is entitled to segfault in that case. */
static TyObject *
getbuffer_with_null_view(TyObject* self, TyObject *obj)
{
if (PyObject_GetBuffer(obj, NULL, PyBUF_SIMPLE) < 0)
return NULL;
Py_RETURN_NONE;
}
/* PyBuffer_SizeFromFormat() */
static TyObject *
test_PyBuffer_SizeFromFormat(TyObject *self, TyObject *args)
{
const char *format;
if (!TyArg_ParseTuple(args, "s:test_PyBuffer_SizeFromFormat",
&format)) {
return NULL;
}
RETURN_SIZE(PyBuffer_SizeFromFormat(format));
}
/* Test that the fatal error from not having a current thread doesn't
cause an infinite loop. Run via Lib/test/test_capi.py */
static TyObject *
crash_no_current_thread(TyObject *self, TyObject *Py_UNUSED(ignored))
{
Ty_BEGIN_ALLOW_THREADS
/* Using TyThreadState_Get() directly allows the test to pass in
!pydebug mode. However, the test only actually tests anything
in pydebug mode, since that's where the infinite loop was in
the first place. */
TyThreadState_Get();
Ty_END_ALLOW_THREADS
return NULL;
}
/* Test that the GILState thread and the "current" thread match. */
static TyObject *
test_current_tstate_matches(TyObject *self, TyObject *Py_UNUSED(ignored))
{
TyThreadState *orig_tstate = TyThreadState_Get();
if (orig_tstate != TyGILState_GetThisThreadState()) {
TyErr_SetString(TyExc_RuntimeError,
"current thread state doesn't match GILState");
return NULL;
}
const char *err = NULL;
TyThreadState_Swap(NULL);
TyThreadState *substate = Ty_NewInterpreter();
if (substate != TyThreadState_Get()) {
err = "subinterpreter thread state not current";
goto finally;
}
if (substate != TyGILState_GetThisThreadState()) {
err = "subinterpreter thread state doesn't match GILState";
goto finally;
}
finally:
Ty_EndInterpreter(substate);
TyThreadState_Swap(orig_tstate);
if (err != NULL) {
TyErr_SetString(TyExc_RuntimeError, err);
return NULL;
}
Py_RETURN_NONE;
}
/* To run some code in a sub-interpreter. */
static TyObject *
run_in_subinterp(TyObject *self, TyObject *args)
{
const char *code;
int r;
TyThreadState *substate, *mainstate;
/* only initialise 'cflags.cf_flags' to test backwards compatibility */
PyCompilerFlags cflags = {0};
if (!TyArg_ParseTuple(args, "s:run_in_subinterp",
&code))
return NULL;
mainstate = TyThreadState_Get();
TyThreadState_Swap(NULL);
substate = Ty_NewInterpreter();
if (substate == NULL) {
/* Since no new thread state was created, there is no exception to
propagate; raise a fresh one after swapping in the old thread
state. */
TyThreadState_Swap(mainstate);
TyErr_SetString(TyExc_RuntimeError, "sub-interpreter creation failed");
return NULL;
}
r = TyRun_SimpleStringFlags(code, &cflags);
Ty_EndInterpreter(substate);
TyThreadState_Swap(mainstate);
return TyLong_FromLong(r);
}
static TyMethodDef ml;
static TyObject *
create_cfunction(TyObject *self, TyObject *args)
{
return PyCFunction_NewEx(&ml, self, NULL);
}
static TyMethodDef ml = {
"create_cfunction",
create_cfunction,
METH_NOARGS,
NULL
};
static TyObject *
test_structseq_newtype_doesnt_leak(TyObject *Py_UNUSED(self),
TyObject *Py_UNUSED(args))
{
TyStructSequence_Desc descr;
TyStructSequence_Field descr_fields[3];
descr_fields[0] = (TyStructSequence_Field){"foo", "foo value"};
descr_fields[1] = (TyStructSequence_Field){NULL, "some hidden value"};
descr_fields[2] = (TyStructSequence_Field){0, NULL};
descr.name = "_testcapi.test_descr";
descr.doc = "This is used to test for memory leaks in NewType";
descr.fields = descr_fields;
descr.n_in_sequence = 1;
TyTypeObject* structseq_type = TyStructSequence_NewType(&descr);
if (structseq_type == NULL) {
return NULL;
}
assert(TyType_Check(structseq_type));
assert(TyType_FastSubclass(structseq_type, Ty_TPFLAGS_TUPLE_SUBCLASS));
Ty_DECREF(structseq_type);
Py_RETURN_NONE;
}
static TyObject *
test_structseq_newtype_null_descr_doc(TyObject *Py_UNUSED(self),
TyObject *Py_UNUSED(args))
{
TyStructSequence_Field descr_fields[1] = {
(TyStructSequence_Field){NULL, NULL}
};
// Test specifically for NULL .doc field.
TyStructSequence_Desc descr = {"_testcapi.test_descr", NULL, &descr_fields[0], 0};
TyTypeObject* structseq_type = TyStructSequence_NewType(&descr);
assert(structseq_type != NULL);
assert(TyType_Check(structseq_type));
assert(TyType_FastSubclass(structseq_type, Ty_TPFLAGS_TUPLE_SUBCLASS));
Ty_DECREF(structseq_type);
Py_RETURN_NONE;
}
typedef struct {
TyThread_type_lock start_event;
TyThread_type_lock exit_event;
TyObject *callback;
} test_c_thread_t;
static void
temporary_c_thread(void *data)
{
test_c_thread_t *test_c_thread = data;
TyGILState_STATE state;
TyObject *res;
TyThread_release_lock(test_c_thread->start_event);
/* Allocate a Python thread state for this thread */
state = TyGILState_Ensure();
res = PyObject_CallNoArgs(test_c_thread->callback);
Ty_CLEAR(test_c_thread->callback);
if (res == NULL) {
TyErr_Print();
}
else {
Ty_DECREF(res);
}
/* Destroy the Python thread state for this thread */
TyGILState_Release(state);
TyThread_release_lock(test_c_thread->exit_event);
}
static test_c_thread_t test_c_thread;
static TyObject *
call_in_temporary_c_thread(TyObject *self, TyObject *args)
{
TyObject *res = NULL;
TyObject *callback = NULL;
long thread;
int wait = 1;
if (!TyArg_ParseTuple(args, "O|i", &callback, &wait))
{
return NULL;
}
test_c_thread.start_event = TyThread_allocate_lock();
test_c_thread.exit_event = TyThread_allocate_lock();
test_c_thread.callback = NULL;
if (!test_c_thread.start_event || !test_c_thread.exit_event) {
TyErr_SetString(TyExc_RuntimeError, "could not allocate lock");
goto exit;
}
test_c_thread.callback = Ty_NewRef(callback);
TyThread_acquire_lock(test_c_thread.start_event, 1);
TyThread_acquire_lock(test_c_thread.exit_event, 1);
thread = TyThread_start_new_thread(temporary_c_thread, &test_c_thread);
if (thread == -1) {
TyErr_SetString(TyExc_RuntimeError, "unable to start the thread");
TyThread_release_lock(test_c_thread.start_event);
TyThread_release_lock(test_c_thread.exit_event);
goto exit;
}
TyThread_acquire_lock(test_c_thread.start_event, 1);
TyThread_release_lock(test_c_thread.start_event);
if (!wait) {
Py_RETURN_NONE;
}
Ty_BEGIN_ALLOW_THREADS
TyThread_acquire_lock(test_c_thread.exit_event, 1);
TyThread_release_lock(test_c_thread.exit_event);
Ty_END_ALLOW_THREADS
res = Ty_NewRef(Ty_None);
exit:
Ty_CLEAR(test_c_thread.callback);
if (test_c_thread.start_event) {
TyThread_free_lock(test_c_thread.start_event);
test_c_thread.start_event = NULL;
}
if (test_c_thread.exit_event) {
TyThread_free_lock(test_c_thread.exit_event);
test_c_thread.exit_event = NULL;
}
return res;
}
static TyObject *
join_temporary_c_thread(TyObject *self, TyObject *Py_UNUSED(ignored))
{
Ty_BEGIN_ALLOW_THREADS
TyThread_acquire_lock(test_c_thread.exit_event, 1);
TyThread_release_lock(test_c_thread.exit_event);
Ty_END_ALLOW_THREADS
Ty_CLEAR(test_c_thread.callback);
TyThread_free_lock(test_c_thread.start_event);
test_c_thread.start_event = NULL;
TyThread_free_lock(test_c_thread.exit_event);
test_c_thread.exit_event = NULL;
Py_RETURN_NONE;
}
/* marshal */
static TyObject*
pymarshal_write_long_to_file(TyObject* self, TyObject *args)
{
long value;
TyObject *filename;
int version;
FILE *fp;
if (!TyArg_ParseTuple(args, "lOi:pymarshal_write_long_to_file",
&value, &filename, &version))
return NULL;
fp = Ty_fopen(filename, "wb");
if (fp == NULL) {
TyErr_SetFromErrno(TyExc_OSError);
return NULL;
}
TyMarshal_WriteLongToFile(value, fp, version);
assert(!TyErr_Occurred());
fclose(fp);
Py_RETURN_NONE;
}
static TyObject*
pymarshal_write_object_to_file(TyObject* self, TyObject *args)
{
TyObject *obj;
TyObject *filename;
int version;
FILE *fp;
if (!TyArg_ParseTuple(args, "OOi:pymarshal_write_object_to_file",
&obj, &filename, &version))
return NULL;
fp = Ty_fopen(filename, "wb");
if (fp == NULL) {
TyErr_SetFromErrno(TyExc_OSError);
return NULL;
}
TyMarshal_WriteObjectToFile(obj, fp, version);
assert(!TyErr_Occurred());
fclose(fp);
Py_RETURN_NONE;
}
static TyObject*
pymarshal_read_short_from_file(TyObject* self, TyObject *args)
{
int value;
long pos;
TyObject *filename;
FILE *fp;
if (!TyArg_ParseTuple(args, "O:pymarshal_read_short_from_file", &filename))
return NULL;
fp = Ty_fopen(filename, "rb");
if (fp == NULL) {
TyErr_SetFromErrno(TyExc_OSError);
return NULL;
}
value = TyMarshal_ReadShortFromFile(fp);
pos = ftell(fp);
fclose(fp);
if (TyErr_Occurred())
return NULL;
return Ty_BuildValue("il", value, pos);
}
static TyObject*
pymarshal_read_long_from_file(TyObject* self, TyObject *args)
{
long value, pos;
TyObject *filename;
FILE *fp;
if (!TyArg_ParseTuple(args, "O:pymarshal_read_long_from_file", &filename))
return NULL;
fp = Ty_fopen(filename, "rb");
if (fp == NULL) {
TyErr_SetFromErrno(TyExc_OSError);
return NULL;
}
value = TyMarshal_ReadLongFromFile(fp);
pos = ftell(fp);
fclose(fp);
if (TyErr_Occurred())
return NULL;
return Ty_BuildValue("ll", value, pos);
}
static TyObject*
pymarshal_read_last_object_from_file(TyObject* self, TyObject *args)
{
TyObject *filename;
if (!TyArg_ParseTuple(args, "O:pymarshal_read_last_object_from_file", &filename))
return NULL;
FILE *fp = Ty_fopen(filename, "rb");
if (fp == NULL) {
TyErr_SetFromErrno(TyExc_OSError);
return NULL;
}
TyObject *obj = TyMarshal_ReadLastObjectFromFile(fp);
long pos = ftell(fp);
fclose(fp);
if (obj == NULL) {
return NULL;
}
return Ty_BuildValue("Nl", obj, pos);
}
static TyObject*
pymarshal_read_object_from_file(TyObject* self, TyObject *args)
{
TyObject *filename;
if (!TyArg_ParseTuple(args, "O:pymarshal_read_object_from_file", &filename))
return NULL;
FILE *fp = Ty_fopen(filename, "rb");
if (fp == NULL) {
TyErr_SetFromErrno(TyExc_OSError);
return NULL;
}
TyObject *obj = TyMarshal_ReadObjectFromFile(fp);
long pos = ftell(fp);
fclose(fp);
if (obj == NULL) {
return NULL;
}
return Ty_BuildValue("Nl", obj, pos);
}
static TyObject*
return_null_without_error(TyObject *self, TyObject *args)
{
/* invalid call: return NULL without setting an error,
* _Ty_CheckFunctionResult() must detect such bug at runtime. */
TyErr_Clear();
return NULL;
}
static TyObject*
return_result_with_error(TyObject *self, TyObject *args)
{
/* invalid call: return a result with an error set,
* _Ty_CheckFunctionResult() must detect such bug at runtime. */
TyErr_SetNone(TyExc_ValueError);
Py_RETURN_NONE;
}
static TyObject *
getitem_with_error(TyObject *self, TyObject *args)
{
TyObject *map, *key;
if (!TyArg_ParseTuple(args, "OO", &map, &key)) {
return NULL;
}
TyErr_SetString(TyExc_ValueError, "bug");
return PyObject_GetItem(map, key);
}
static TyObject *
raise_SIGINT_then_send_None(TyObject *self, TyObject *args)
{
PyGenObject *gen;
if (!TyArg_ParseTuple(args, "O!", &TyGen_Type, &gen))
return NULL;
/* This is used in a test to check what happens if a signal arrives just
as we're in the process of entering a yield from chain (see
bpo-30039).
Needs to be done in C, because:
- we don't have a Python wrapper for raise()
- we need to make sure that the Python-level signal handler doesn't run
*before* we enter the generator frame, which is impossible in Python
because we check for signals before every bytecode operation.
*/
raise(SIGINT);
return PyObject_CallMethod((TyObject *)gen, "send", "O", Ty_None);
}
static TyObject*
stack_pointer(TyObject *self, TyObject *args)
{
int v = 5;
return TyLong_FromVoidPtr(&v);
}
#ifdef W_STOPCODE
static TyObject*
py_w_stopcode(TyObject *self, TyObject *args)
{
int sig, status;
if (!TyArg_ParseTuple(args, "i", &sig)) {
return NULL;
}
status = W_STOPCODE(sig);
return TyLong_FromLong(status);
}
#endif
static TyObject *
test_pythread_tss_key_state(TyObject *self, TyObject *args)
{
Ty_tss_t tss_key = Ty_tss_NEEDS_INIT;
if (TyThread_tss_is_created(&tss_key)) {
return raiseTestError(self, "test_pythread_tss_key_state",
"TSS key not in an uninitialized state at "
"creation time");
}
if (TyThread_tss_create(&tss_key) != 0) {
TyErr_SetString(TyExc_RuntimeError, "TyThread_tss_create failed");
return NULL;
}
if (!TyThread_tss_is_created(&tss_key)) {
return raiseTestError(self, "test_pythread_tss_key_state",
"TyThread_tss_create succeeded, "
"but with TSS key in an uninitialized state");
}
if (TyThread_tss_create(&tss_key) != 0) {
return raiseTestError(self, "test_pythread_tss_key_state",
"TyThread_tss_create unsuccessful with "
"an already initialized key");
}
#define CHECK_TSS_API(expr) \
do { \
(void)(expr); \
if (!TyThread_tss_is_created(&tss_key)) { \
return raiseTestError(self, "test_pythread_tss_key_state", \
"TSS key initialization state was not " \
"preserved after calling " #expr); \
} \
} while (0)
CHECK_TSS_API(TyThread_tss_set(&tss_key, NULL));
CHECK_TSS_API(TyThread_tss_get(&tss_key));
#undef CHECK_TSS_API
TyThread_tss_delete(&tss_key);
if (TyThread_tss_is_created(&tss_key)) {
return raiseTestError(self, "test_pythread_tss_key_state",
"TyThread_tss_delete called, but did not "
"set the key state to uninitialized");
}
Ty_tss_t *ptr_key = TyThread_tss_alloc();
if (ptr_key == NULL) {
TyErr_SetString(TyExc_RuntimeError, "TyThread_tss_alloc failed");
return NULL;
}
if (TyThread_tss_is_created(ptr_key)) {
return raiseTestError(self, "test_pythread_tss_key_state",
"TSS key not in an uninitialized state at "
"allocation time");
}
TyThread_tss_free(ptr_key);
ptr_key = NULL;
Py_RETURN_NONE;
}
/* def bad_get(self, obj, cls):
cls()
return repr(self)
*/
static TyObject*
bad_get(TyObject *module, TyObject *args)
{
TyObject *self, *obj, *cls;
if (!TyArg_ParseTuple(args, "OOO", &self, &obj, &cls)) {
return NULL;
}
TyObject *res = PyObject_CallNoArgs(cls);
if (res == NULL) {
return NULL;
}
Ty_DECREF(res);
return PyObject_Repr(self);
}
/* Functions for testing C calling conventions (METH_*) are named meth_*,
* e.g. "meth_varargs" for METH_VARARGS.
*
* They all return a tuple of their C-level arguments, with None instead
* of NULL and Python tuples instead of C arrays.
*/
static TyObject*
_null_to_none(TyObject* obj)
{
if (obj == NULL) {
Py_RETURN_NONE;
}
return Ty_NewRef(obj);
}
static TyObject*
meth_varargs(TyObject* self, TyObject* args)
{
return Ty_BuildValue("NO", _null_to_none(self), args);
}
static TyObject*
meth_varargs_keywords(TyObject* self, TyObject* args, TyObject* kwargs)
{
return Ty_BuildValue("NON", _null_to_none(self), args, _null_to_none(kwargs));
}
static TyObject*
meth_o(TyObject* self, TyObject* obj)
{
return Ty_BuildValue("NO", _null_to_none(self), obj);
}
static TyObject*
meth_noargs(TyObject* self, TyObject *Py_UNUSED(dummy))
{
return _null_to_none(self);
}
static TyObject*
_fastcall_to_tuple(TyObject* const* args, Ty_ssize_t nargs)
{
TyObject *tuple = TyTuple_New(nargs);
if (tuple == NULL) {
return NULL;
}
for (Ty_ssize_t i=0; i < nargs; i++) {
Ty_INCREF(args[i]);
TyTuple_SET_ITEM(tuple, i, args[i]);
}
return tuple;
}
static TyObject*
meth_fastcall(TyObject* self, TyObject* const* args, Ty_ssize_t nargs)
{
return Ty_BuildValue(
"NN", _null_to_none(self), _fastcall_to_tuple(args, nargs)
);
}
static TyObject*
meth_fastcall_keywords(TyObject* self, TyObject* const* args,
Ty_ssize_t nargs, TyObject* kwargs)
{
TyObject *pyargs = _fastcall_to_tuple(args, nargs);
if (pyargs == NULL) {
return NULL;
}
assert(args != NULL || nargs == 0);
TyObject* const* args_offset = args == NULL ? NULL : args + nargs;
TyObject *pykwargs = PyObject_Vectorcall((TyObject*)&TyDict_Type,
args_offset, 0, kwargs);
return Ty_BuildValue("NNN", _null_to_none(self), pyargs, pykwargs);
}
static TyObject*
test_pycfunction_call(TyObject *module, TyObject *args)
{
// Function removed in the Python 3.13 API but was kept in the stable ABI.
extern TyObject* PyCFunction_Call(TyObject *callable, TyObject *args, TyObject *kwargs);
TyObject *func, *pos_args, *kwargs = NULL;
if (!TyArg_ParseTuple(args, "OO!|O!", &func, &TyTuple_Type, &pos_args, &TyDict_Type, &kwargs)) {
return NULL;
}
return PyCFunction_Call(func, pos_args, kwargs);
}
static TyObject*
pynumber_tobase(TyObject *module, TyObject *args)
{
TyObject *obj;
int base;
if (!TyArg_ParseTuple(args, "Oi:pynumber_tobase",
&obj, &base)) {
return NULL;
}
return PyNumber_ToBase(obj, base);
}
/* We only use 2 in test_capi/test_misc.py. */
#define NUM_BASIC_STATIC_TYPES 2
static TyTypeObject BasicStaticTypes[NUM_BASIC_STATIC_TYPES] = {
#define INIT_BASIC_STATIC_TYPE \
{ \
TyVarObject_HEAD_INIT(NULL, 0) \
.tp_name = "BasicStaticType", \
.tp_basicsize = sizeof(TyObject), \
}
INIT_BASIC_STATIC_TYPE,
INIT_BASIC_STATIC_TYPE,
#undef INIT_BASIC_STATIC_TYPE
};
static int num_basic_static_types_used = 0;
static TyObject *
get_basic_static_type(TyObject *self, TyObject *args)
{
TyObject *base = NULL;
if (!TyArg_ParseTuple(args, "|O", &base)) {
return NULL;
}
assert(base == NULL || TyType_Check(base));
if(num_basic_static_types_used >= NUM_BASIC_STATIC_TYPES) {
TyErr_SetString(TyExc_RuntimeError, "no more available basic static types");
return NULL;
}
TyTypeObject *cls = &BasicStaticTypes[num_basic_static_types_used++];
if (base != NULL) {
cls->tp_bases = TyTuple_Pack(1, base);
if (cls->tp_bases == NULL) {
return NULL;
}
cls->tp_base = (TyTypeObject *)Ty_NewRef(base);
}
if (TyType_Ready(cls) < 0) {
Ty_DECREF(cls->tp_bases);
Ty_DECREF(cls->tp_base);
return NULL;
}
return (TyObject *)cls;
}
// Test TyThreadState C API
static TyObject *
test_tstate_capi(TyObject *self, TyObject *Py_UNUSED(args))
{
// TyThreadState_Get()
TyThreadState *tstate = TyThreadState_Get();
assert(tstate != NULL);
// TyThreadState_GET()
TyThreadState *tstate2 = TyThreadState_Get();
assert(tstate2 == tstate);
// TyThreadState_GetUnchecked()
TyThreadState *tstate3 = TyThreadState_GetUnchecked();
assert(tstate3 == tstate);
// TyThreadState_EnterTracing(), TyThreadState_LeaveTracing()
TyThreadState_EnterTracing(tstate);
TyThreadState_LeaveTracing(tstate);
// TyThreadState_GetDict(): no tstate argument
TyObject *dict = TyThreadState_GetDict();
// TyThreadState_GetDict() API can return NULL if TyDict_New() fails,
// but it should not occur in practice.
assert(dict != NULL);
assert(TyDict_Check(dict));
// dict is a borrowed reference
// TyThreadState_GetInterpreter()
TyInterpreterState *interp = TyThreadState_GetInterpreter(tstate);
assert(interp != NULL);
// TyThreadState_GetFrame()
PyFrameObject*frame = TyThreadState_GetFrame(tstate);
assert(frame != NULL);
assert(TyFrame_Check(frame));
Ty_DECREF(frame);
// TyThreadState_GetID()
uint64_t id = TyThreadState_GetID(tstate);
assert(id >= 1);
Py_RETURN_NONE;
}
static TyObject *
gen_get_code(TyObject *self, TyObject *gen)
{
if (!TyGen_Check(gen)) {
TyErr_SetString(TyExc_TypeError, "argument must be a generator object");
return NULL;
}
return (TyObject *)TyGen_GetCode((PyGenObject *)gen);
}
static TyObject *
eval_eval_code_ex(TyObject *mod, TyObject *pos_args)
{
TyObject *result = NULL;
TyObject *code;
TyObject *globals;
TyObject *locals = NULL;
TyObject *args = NULL;
TyObject *kwargs = NULL;
TyObject *defaults = NULL;
TyObject *kw_defaults = NULL;
TyObject *closure = NULL;
TyObject **c_kwargs = NULL;
if (!TyArg_ParseTuple(pos_args,
"OO|OO!O!O!OO:eval_code_ex",
&code,
&globals,
&locals,
&TyTuple_Type, &args,
&TyDict_Type, &kwargs,
&TyTuple_Type, &defaults,
&kw_defaults,
&closure))
{
goto exit;
}
NULLABLE(code);
NULLABLE(globals);
NULLABLE(locals);
NULLABLE(kw_defaults);
NULLABLE(closure);
TyObject **c_args = NULL;
Ty_ssize_t c_args_len = 0;
if (args) {
c_args = &TyTuple_GET_ITEM(args, 0);
c_args_len = TyTuple_Size(args);
}
Ty_ssize_t c_kwargs_len = 0;
if (kwargs) {
c_kwargs_len = TyDict_Size(kwargs);
if (c_kwargs_len > 0) {
c_kwargs = TyMem_NEW(TyObject*, 2 * c_kwargs_len);
if (!c_kwargs) {
TyErr_NoMemory();
goto exit;
}
Ty_ssize_t i = 0;
Ty_ssize_t pos = 0;
while (TyDict_Next(kwargs, &pos, &c_kwargs[i], &c_kwargs[i + 1])) {
i += 2;
}
c_kwargs_len = i / 2;
/* XXX This is broken if the caller deletes dict items! */
}
}
TyObject **c_defaults = NULL;
Ty_ssize_t c_defaults_len = 0;
if (defaults) {
c_defaults = &TyTuple_GET_ITEM(defaults, 0);
c_defaults_len = TyTuple_Size(defaults);
}
result = TyEval_EvalCodeEx(
code,
globals,
locals,
c_args,
(int)c_args_len,
c_kwargs,
(int)c_kwargs_len,
c_defaults,
(int)c_defaults_len,
kw_defaults,
closure
);
exit:
if (c_kwargs) {
TyMem_DEL(c_kwargs);
}
return result;
}
static TyObject *
get_feature_macros(TyObject *self, TyObject *Py_UNUSED(args))
{
TyObject *result = TyDict_New();
if (!result) {
return NULL;
}
int res;
#include "_testcapi_feature_macros.inc"
return result;
}
static TyObject *
test_code_api(TyObject *self, TyObject *Py_UNUSED(args))
{
PyCodeObject *co = TyCode_NewEmpty("_testcapi", "dummy", 1);
if (co == NULL) {
return NULL;
}
/* co_code */
{
TyObject *co_code = TyCode_GetCode(co);
if (co_code == NULL) {
goto fail;
}
assert(TyBytes_CheckExact(co_code));
if (PyObject_Length(co_code) == 0) {
TyErr_SetString(TyExc_ValueError, "empty co_code");
Ty_DECREF(co_code);
goto fail;
}
Ty_DECREF(co_code);
}
/* co_varnames */
{
TyObject *co_varnames = TyCode_GetVarnames(co);
if (co_varnames == NULL) {
goto fail;
}
if (!TyTuple_CheckExact(co_varnames)) {
TyErr_SetString(TyExc_TypeError, "co_varnames not tuple");
Ty_DECREF(co_varnames);
goto fail;
}
if (TyTuple_GET_SIZE(co_varnames) != 0) {
TyErr_SetString(TyExc_ValueError, "non-empty co_varnames");
Ty_DECREF(co_varnames);
goto fail;
}
Ty_DECREF(co_varnames);
}
/* co_cellvars */
{
TyObject *co_cellvars = TyCode_GetCellvars(co);
if (co_cellvars == NULL) {
goto fail;
}
if (!TyTuple_CheckExact(co_cellvars)) {
TyErr_SetString(TyExc_TypeError, "co_cellvars not tuple");
Ty_DECREF(co_cellvars);
goto fail;
}
if (TyTuple_GET_SIZE(co_cellvars) != 0) {
TyErr_SetString(TyExc_ValueError, "non-empty co_cellvars");
Ty_DECREF(co_cellvars);
goto fail;
}
Ty_DECREF(co_cellvars);
}
/* co_freevars */
{
TyObject *co_freevars = TyCode_GetFreevars(co);
if (co_freevars == NULL) {
goto fail;
}
if (!TyTuple_CheckExact(co_freevars)) {
TyErr_SetString(TyExc_TypeError, "co_freevars not tuple");
Ty_DECREF(co_freevars);
goto fail;
}
if (TyTuple_GET_SIZE(co_freevars) != 0) {
TyErr_SetString(TyExc_ValueError, "non-empty co_freevars");
Ty_DECREF(co_freevars);
goto fail;
}
Ty_DECREF(co_freevars);
}
Ty_DECREF(co);
Py_RETURN_NONE;
fail:
Ty_DECREF(co);
return NULL;
}
static int
record_func(TyObject *obj, PyFrameObject *f, int what, TyObject *arg)
{
assert(TyList_Check(obj));
TyObject *what_obj = NULL;
TyObject *line_obj = NULL;
TyObject *tuple = NULL;
int res = -1;
what_obj = TyLong_FromLong(what);
if (what_obj == NULL) {
goto error;
}
int line = TyFrame_GetLineNumber(f);
line_obj = TyLong_FromLong(line);
if (line_obj == NULL) {
goto error;
}
tuple = TyTuple_Pack(3, what_obj, line_obj, arg);
if (tuple == NULL) {
goto error;
}
TyTuple_SET_ITEM(tuple, 0, what_obj);
if (TyList_Append(obj, tuple)) {
goto error;
}
res = 0;
error:
Ty_XDECREF(what_obj);
Ty_XDECREF(line_obj);
Ty_XDECREF(tuple);
return res;
}
static TyObject *
settrace_to_record(TyObject *self, TyObject *list)
{
if (!TyList_Check(list)) {
TyErr_SetString(TyExc_TypeError, "argument must be a list");
return NULL;
}
TyEval_SetTrace(record_func, list);
Py_RETURN_NONE;
}
static int
error_func(TyObject *obj, PyFrameObject *f, int what, TyObject *arg)
{
assert(TyList_Check(obj));
/* Only raise if list is empty, otherwise append None
* This ensures that we only raise once */
if (TyList_GET_SIZE(obj)) {
return 0;
}
if (TyList_Append(obj, Ty_None)) {
return -1;
}
TyErr_SetString(TyExc_Exception, "an exception");
return -1;
}
static TyObject *
settrace_to_error(TyObject *self, TyObject *list)
{
if (!TyList_Check(list)) {
TyErr_SetString(TyExc_TypeError, "argument must be a list");
return NULL;
}
TyEval_SetTrace(error_func, list);
Py_RETURN_NONE;
}
static TyObject *
test_macros(TyObject *self, TyObject *Py_UNUSED(args))
{
struct MyStruct {
int x;
};
wchar_t array[3];
// static_assert(), Ty_BUILD_ASSERT()
static_assert(1 == 1, "bug");
Ty_BUILD_ASSERT(1 == 1);
// Ty_MIN(), Ty_MAX(), Ty_ABS()
assert(Ty_MIN(5, 11) == 5);
assert(Ty_MAX(5, 11) == 11);
assert(Ty_ABS(-5) == 5);
// Ty_STRINGIFY()
assert(strcmp(Ty_STRINGIFY(123), "123") == 0);
// Ty_MEMBER_SIZE(), Ty_ARRAY_LENGTH()
assert(Ty_MEMBER_SIZE(struct MyStruct, x) == sizeof(int));
assert(Ty_ARRAY_LENGTH(array) == 3);
// Ty_CHARMASK()
int c = 0xab00 | 7;
assert(Ty_CHARMASK(c) == 7);
// _Ty_IS_TYPE_SIGNED()
assert(_Ty_IS_TYPE_SIGNED(int));
assert(!_Ty_IS_TYPE_SIGNED(unsigned int));
Py_RETURN_NONE;
}
static TyObject *
test_weakref_capi(TyObject *Py_UNUSED(module), TyObject *Py_UNUSED(args))
{
// Ignore PyWeakref_GetObject() deprecation, we test it on purpose
_Ty_COMP_DIAG_PUSH
_Ty_COMP_DIAG_IGNORE_DEPR_DECLS
// Create a new heap type, create an instance of this type, and delete the
// type. This object supports weak references.
TyObject *new_type = PyObject_CallFunction((TyObject*)&TyType_Type,
"s(){}", "TypeName");
if (new_type == NULL) {
return NULL;
}
TyObject *obj = PyObject_CallNoArgs(new_type);
Ty_DECREF(new_type);
if (obj == NULL) {
return NULL;
}
Ty_ssize_t refcnt = Ty_REFCNT(obj);
// test PyWeakref_NewRef(), reference is alive
TyObject *weakref = PyWeakref_NewRef(obj, NULL);
if (weakref == NULL) {
Ty_DECREF(obj);
return NULL;
}
// test PyWeakref_Check(), valid weakref object
assert(PyWeakref_Check(weakref));
assert(PyWeakref_CheckRefExact(weakref));
assert(PyWeakref_CheckRefExact(weakref));
assert(Ty_REFCNT(obj) == refcnt);
// test PyWeakref_GetRef(), reference is alive
TyObject *ref = UNINITIALIZED_PTR;
assert(PyWeakref_GetRef(weakref, &ref) == 1);
assert(ref == obj);
assert(!PyWeakref_IsDead(weakref));
assert(Ty_REFCNT(obj) == (refcnt + 1));
Ty_DECREF(ref);
// test PyWeakref_GetObject(), reference is alive
ref = PyWeakref_GetObject(weakref); // borrowed ref
assert(ref == obj);
// test PyWeakref_GET_OBJECT(), reference is alive
ref = PyWeakref_GET_OBJECT(weakref); // borrowed ref
assert(ref == obj);
// delete the referenced object: clear the weakref
assert(Ty_REFCNT(obj) == 1);
Ty_DECREF(obj);
assert(PyWeakref_IsDead(weakref));
// test PyWeakref_GET_OBJECT(), reference is dead
assert(PyWeakref_GET_OBJECT(weakref) == Ty_None);
// test PyWeakref_GetRef(), reference is dead
ref = UNINITIALIZED_PTR;
assert(PyWeakref_GetRef(weakref, &ref) == 0);
assert(ref == NULL);
// test PyWeakref_Check(), not a weakref object
TyObject *invalid_weakref = Ty_None;
assert(!PyWeakref_Check(invalid_weakref));
assert(!PyWeakref_CheckRefExact(invalid_weakref));
assert(!PyWeakref_CheckRefExact(invalid_weakref));
// test PyWeakref_GetRef(), invalid type
assert(!TyErr_Occurred());
ref = UNINITIALIZED_PTR;
assert(PyWeakref_GetRef(invalid_weakref, &ref) == -1);
assert(TyErr_ExceptionMatches(TyExc_TypeError));
TyErr_Clear();
assert(ref == NULL);
// test PyWeakRef_IsDead(), invalid type
assert(!TyErr_Occurred());
assert(PyWeakref_IsDead(invalid_weakref) == -1);
assert(TyErr_ExceptionMatches(TyExc_TypeError));
TyErr_Clear();
// test PyWeakref_GetObject(), invalid type
assert(PyWeakref_GetObject(invalid_weakref) == NULL);
assert(TyErr_ExceptionMatches(TyExc_SystemError));
TyErr_Clear();
// test PyWeakref_GetRef(NULL)
ref = UNINITIALIZED_PTR;
assert(PyWeakref_GetRef(NULL, &ref) == -1);
assert(TyErr_ExceptionMatches(TyExc_SystemError));
assert(ref == NULL);
TyErr_Clear();
// test PyWeakref_IsDead(NULL)
assert(PyWeakref_IsDead(NULL) == -1);
assert(TyErr_ExceptionMatches(TyExc_SystemError));
TyErr_Clear();
// test PyWeakref_GetObject(NULL)
assert(PyWeakref_GetObject(NULL) == NULL);
assert(TyErr_ExceptionMatches(TyExc_SystemError));
TyErr_Clear();
Ty_DECREF(weakref);
Py_RETURN_NONE;
_Ty_COMP_DIAG_POP
}
struct simpletracer_data {
int create_count;
int destroy_count;
void* addresses[10];
};
static int _simpletracer(TyObject *obj, PyRefTracerEvent event, void* data) {
struct simpletracer_data* the_data = (struct simpletracer_data*)data;
assert(the_data->create_count + the_data->destroy_count < (int)Ty_ARRAY_LENGTH(the_data->addresses));
the_data->addresses[the_data->create_count + the_data->destroy_count] = obj;
if (event == PyRefTracer_CREATE) {
the_data->create_count++;
} else {
the_data->destroy_count++;
}
return 0;
}
static TyObject *
test_reftracer(TyObject *ob, TyObject *Py_UNUSED(ignored))
{
// Save the current tracer and data to restore it later
void* current_data;
PyRefTracer current_tracer = PyRefTracer_GetTracer(&current_data);
struct simpletracer_data tracer_data = {0};
void* the_data = &tracer_data;
// Install a simple tracer function
if (PyRefTracer_SetTracer(_simpletracer, the_data) != 0) {
goto failed;
}
// Check that the tracer was correctly installed
void* data;
if (PyRefTracer_GetTracer(&data) != _simpletracer || data != the_data) {
TyErr_SetString(TyExc_AssertionError, "The reftracer not correctly installed");
(void)PyRefTracer_SetTracer(NULL, NULL);
goto failed;
}
// Create a bunch of objects
TyObject* obj = TyList_New(0);
if (obj == NULL) {
goto failed;
}
TyObject* obj2 = TyDict_New();
if (obj2 == NULL) {
Ty_DECREF(obj);
goto failed;
}
// Kill all objects
Ty_DECREF(obj);
Ty_DECREF(obj2);
// Remove the tracer
(void)PyRefTracer_SetTracer(NULL, NULL);
// Check that the tracer was removed
if (PyRefTracer_GetTracer(&data) != NULL || data != NULL) {
TyErr_SetString(TyExc_ValueError, "The reftracer was not correctly removed");
goto failed;
}
if (tracer_data.create_count != 2 ||
tracer_data.addresses[0] != obj ||
tracer_data.addresses[1] != obj2) {
TyErr_SetString(TyExc_ValueError, "The object creation was not correctly traced");
goto failed;
}
if (tracer_data.destroy_count != 2 ||
tracer_data.addresses[2] != obj ||
tracer_data.addresses[3] != obj2) {
TyErr_SetString(TyExc_ValueError, "The object destruction was not correctly traced");
goto failed;
}
PyRefTracer_SetTracer(current_tracer, current_data);
Py_RETURN_NONE;
failed:
PyRefTracer_SetTracer(current_tracer, current_data);
return NULL;
}
static TyObject *
function_set_warning(TyObject *Py_UNUSED(module), TyObject *Py_UNUSED(args))
{
if (TyErr_WarnEx(TyExc_RuntimeWarning, "Testing TyErr_WarnEx", 2)) {
return NULL;
}
Py_RETURN_NONE;
}
static TyObject *
test_critical_sections(TyObject *module, TyObject *Py_UNUSED(args))
{
Ty_BEGIN_CRITICAL_SECTION(module);
Ty_END_CRITICAL_SECTION();
Ty_BEGIN_CRITICAL_SECTION2(module, module);
Ty_END_CRITICAL_SECTION2();
Py_RETURN_NONE;
}
// Used by `finalize_thread_hang`.
#if defined(_POSIX_THREADS) && !defined(__wasi__)
static void finalize_thread_hang_cleanup_callback(void *Py_UNUSED(arg)) {
// Should not reach here.
Ty_FatalError("pthread thread termination was triggered unexpectedly");
}
#endif
// Tests that finalization does not trigger pthread cleanup.
//
// Must be called with a single nullary callable function that should block
// (with GIL released) until finalization is in progress.
static TyObject *
finalize_thread_hang(TyObject *self, TyObject *callback)
{
// WASI builds some pthread stuff but doesn't have these APIs today?
#if defined(_POSIX_THREADS) && !defined(__wasi__)
pthread_cleanup_push(finalize_thread_hang_cleanup_callback, NULL);
#endif
PyObject_CallNoArgs(callback);
// Should not reach here.
Ty_FatalError("thread unexpectedly did not hang");
#if defined(_POSIX_THREADS) && !defined(__wasi__)
pthread_cleanup_pop(0);
#endif
Py_RETURN_NONE;
}
struct atexit_data {
int called;
TyThreadState *tstate;
TyInterpreterState *interp;
};
static void
atexit_callback(void *data)
{
struct atexit_data *at_data = (struct atexit_data *)data;
// Ensure that the callback is from the same interpreter
assert(TyThreadState_Get() == at_data->tstate);
assert(TyInterpreterState_Get() == at_data->interp);
++at_data->called;
}
static TyObject *
test_atexit(TyObject *self, TyObject *Py_UNUSED(args))
{
TyThreadState *oldts = TyThreadState_Swap(NULL);
TyThreadState *tstate = Ty_NewInterpreter();
struct atexit_data data = {0};
data.tstate = TyThreadState_Get();
data.interp = TyInterpreterState_Get();
int amount = 10;
for (int i = 0; i < amount; ++i)
{
int res = PyUnstable_AtExit(tstate->interp, atexit_callback, (void *)&data);
if (res < 0) {
Ty_EndInterpreter(tstate);
TyThreadState_Swap(oldts);
TyErr_SetString(TyExc_RuntimeError, "atexit callback failed");
return NULL;
}
}
Ty_EndInterpreter(tstate);
TyThreadState_Swap(oldts);
if (data.called != amount) {
TyErr_SetString(TyExc_RuntimeError, "atexit callback not called");
return NULL;
}
Py_RETURN_NONE;
}
static TyObject*
code_offset_to_line(TyObject* self, TyObject* const* args, Ty_ssize_t nargsf)
{
Ty_ssize_t nargs = _PyVectorcall_NARGS(nargsf);
if (nargs != 2) {
TyErr_SetString(TyExc_TypeError, "code_offset_to_line takes 2 arguments");
return NULL;
}
int offset;
if (TyLong_AsInt32(args[1], &offset) < 0) {
return NULL;
}
PyCodeObject *code = (PyCodeObject *)args[0];
if (!TyCode_Check(code)) {
TyErr_SetString(TyExc_TypeError, "first arg must be a code object");
return NULL;
}
return TyLong_FromInt32(TyCode_Addr2Line(code, offset));
}
static int
_reftrace_printer(TyObject *obj, PyRefTracerEvent event, void *counter_data)
{
if (event == PyRefTracer_CREATE) {
printf("CREATE %s\n", Ty_TYPE(obj)->tp_name);
}
else { // PyRefTracer_DESTROY
printf("DESTROY %s\n", Ty_TYPE(obj)->tp_name);
}
return 0;
}
// A simple reftrace printer for very simple tests
static TyObject *
toggle_reftrace_printer(TyObject *ob, TyObject *arg)
{
if (arg == Ty_True) {
PyRefTracer_SetTracer(_reftrace_printer, NULL);
}
else {
PyRefTracer_SetTracer(NULL, NULL);
}
Py_RETURN_NONE;
}
static TyMethodDef TestMethods[] = {
{"set_errno", set_errno, METH_VARARGS},
{"test_config", test_config, METH_NOARGS},
{"test_sizeof_c_types", test_sizeof_c_types, METH_NOARGS},
{"test_lazy_hash_inheritance", test_lazy_hash_inheritance,METH_NOARGS},
{"test_structseq_newtype_doesnt_leak",
test_structseq_newtype_doesnt_leak, METH_NOARGS},
{"test_structseq_newtype_null_descr_doc",
test_structseq_newtype_null_descr_doc, METH_NOARGS},
{"pyobject_repr_from_null", pyobject_repr_from_null, METH_NOARGS},
{"pyobject_str_from_null", pyobject_str_from_null, METH_NOARGS},
{"pyobject_bytes_from_null", pyobject_bytes_from_null, METH_NOARGS},
{"test_capsule", test_capsule, METH_NOARGS},
{"test_from_contiguous", test_from_contiguous, METH_NOARGS},
#if (defined(__linux__) || defined(__FreeBSD__)) && defined(__GNUC__)
{"test_pep3118_obsolete_write_locks", test_pep3118_obsolete_write_locks, METH_NOARGS},
#endif
{"getbuffer_with_null_view", getbuffer_with_null_view, METH_O},
{"PyBuffer_SizeFromFormat", test_PyBuffer_SizeFromFormat, METH_VARARGS},
{"py_buildvalue", py_buildvalue, METH_VARARGS},
{"py_buildvalue_ints", py_buildvalue_ints, METH_VARARGS},
{"test_buildvalue_N", test_buildvalue_N, METH_NOARGS},
{"test_buildvalue_p", test_buildvalue_p, METH_NOARGS},
{"test_reftracer", test_reftracer, METH_NOARGS},
{"_test_thread_state", test_thread_state, METH_VARARGS},
{"gilstate_ensure_release", gilstate_ensure_release, METH_NOARGS},
#ifndef MS_WINDOWS
{"_spawn_pthread_waiter", spawn_pthread_waiter, METH_NOARGS},
{"_end_spawned_pthread", end_spawned_pthread, METH_NOARGS},
#endif
{"_pending_threadfunc", _PyCFunction_CAST(pending_threadfunc),
METH_VARARGS|METH_KEYWORDS},
#ifdef HAVE_GETTIMEOFDAY
{"profile_int", profile_int, METH_NOARGS},
#endif
{"argparsing", argparsing, METH_VARARGS},
{"code_newempty", code_newempty, METH_VARARGS},
{"eval_code_ex", eval_eval_code_ex, METH_VARARGS},
{"make_memoryview_from_NULL_pointer", make_memoryview_from_NULL_pointer,
METH_NOARGS},
{"buffer_fill_info", buffer_fill_info, METH_VARARGS},
{"crash_no_current_thread", crash_no_current_thread, METH_NOARGS},
{"test_current_tstate_matches", test_current_tstate_matches, METH_NOARGS},
{"run_in_subinterp", run_in_subinterp, METH_VARARGS},
{"create_cfunction", create_cfunction, METH_NOARGS},
{"call_in_temporary_c_thread", call_in_temporary_c_thread, METH_VARARGS,
TyDoc_STR("set_error_class(error_class) -> None")},
{"join_temporary_c_thread", join_temporary_c_thread, METH_NOARGS},
{"pymarshal_write_long_to_file",
pymarshal_write_long_to_file, METH_VARARGS},
{"pymarshal_write_object_to_file",
pymarshal_write_object_to_file, METH_VARARGS},
{"pymarshal_read_short_from_file",
pymarshal_read_short_from_file, METH_VARARGS},
{"pymarshal_read_long_from_file",
pymarshal_read_long_from_file, METH_VARARGS},
{"pymarshal_read_last_object_from_file",
pymarshal_read_last_object_from_file, METH_VARARGS},
{"pymarshal_read_object_from_file",
pymarshal_read_object_from_file, METH_VARARGS},
{"return_null_without_error", return_null_without_error, METH_NOARGS},
{"return_result_with_error", return_result_with_error, METH_NOARGS},
{"getitem_with_error", getitem_with_error, METH_VARARGS},
{"Ty_CompileString", pycompilestring, METH_O},
{"raise_SIGINT_then_send_None", raise_SIGINT_then_send_None, METH_VARARGS},
{"stack_pointer", stack_pointer, METH_NOARGS},
#ifdef W_STOPCODE
{"W_STOPCODE", py_w_stopcode, METH_VARARGS},
#endif
{"test_pythread_tss_key_state", test_pythread_tss_key_state, METH_VARARGS},
{"bad_get", bad_get, METH_VARARGS},
{"meth_varargs", meth_varargs, METH_VARARGS},
{"meth_varargs_keywords", _PyCFunction_CAST(meth_varargs_keywords), METH_VARARGS|METH_KEYWORDS},
{"meth_o", meth_o, METH_O},
{"meth_noargs", meth_noargs, METH_NOARGS},
{"meth_fastcall", _PyCFunction_CAST(meth_fastcall), METH_FASTCALL},
{"meth_fastcall_keywords", _PyCFunction_CAST(meth_fastcall_keywords), METH_FASTCALL|METH_KEYWORDS},
{"pycfunction_call", test_pycfunction_call, METH_VARARGS},
{"pynumber_tobase", pynumber_tobase, METH_VARARGS},
{"get_basic_static_type", get_basic_static_type, METH_VARARGS, NULL},
{"test_tstate_capi", test_tstate_capi, METH_NOARGS, NULL},
{"gen_get_code", gen_get_code, METH_O, NULL},
{"get_feature_macros", get_feature_macros, METH_NOARGS, NULL},
{"test_code_api", test_code_api, METH_NOARGS, NULL},
{"settrace_to_error", settrace_to_error, METH_O, NULL},
{"settrace_to_record", settrace_to_record, METH_O, NULL},
{"test_macros", test_macros, METH_NOARGS, NULL},
{"test_weakref_capi", test_weakref_capi, METH_NOARGS},
{"function_set_warning", function_set_warning, METH_NOARGS},
{"test_critical_sections", test_critical_sections, METH_NOARGS},
{"finalize_thread_hang", finalize_thread_hang, METH_O, NULL},
{"test_atexit", test_atexit, METH_NOARGS},
{"code_offset_to_line", _PyCFunction_CAST(code_offset_to_line), METH_FASTCALL},
{"toggle_reftrace_printer", toggle_reftrace_printer, METH_O},
{NULL, NULL} /* sentinel */
};
typedef struct {
PyObject_HEAD
} matmulObject;
static TyObject *
matmulType_matmul(TyObject *self, TyObject *other)
{
return Ty_BuildValue("(sOO)", "matmul", self, other);
}
static TyObject *
matmulType_imatmul(TyObject *self, TyObject *other)
{
return Ty_BuildValue("(sOO)", "imatmul", self, other);
}
static void
matmulType_dealloc(TyObject *self)
{
Ty_TYPE(self)->tp_free(self);
}
static TyNumberMethods matmulType_as_number = {
0, /* nb_add */
0, /* nb_subtract */
0, /* nb_multiply */
0, /* nb_remainde r*/
0, /* nb_divmod */
0, /* nb_power */
0, /* nb_negative */
0, /* tp_positive */
0, /* tp_absolute */
0, /* tp_bool */
0, /* nb_invert */
0, /* nb_lshift */
0, /* nb_rshift */
0, /* nb_and */
0, /* nb_xor */
0, /* nb_or */
0, /* nb_int */
0, /* nb_reserved */
0, /* nb_float */
0, /* nb_inplace_add */
0, /* nb_inplace_subtract */
0, /* nb_inplace_multiply */
0, /* nb_inplace_remainder */
0, /* nb_inplace_power */
0, /* nb_inplace_lshift */
0, /* nb_inplace_rshift */
0, /* nb_inplace_and */
0, /* nb_inplace_xor */
0, /* nb_inplace_or */
0, /* nb_floor_divide */
0, /* nb_true_divide */
0, /* nb_inplace_floor_divide */
0, /* nb_inplace_true_divide */
0, /* nb_index */
matmulType_matmul, /* nb_matrix_multiply */
matmulType_imatmul /* nb_matrix_inplace_multiply */
};
static TyTypeObject matmulType = {
TyVarObject_HEAD_INIT(NULL, 0)
"matmulType",
sizeof(matmulObject), /* tp_basicsize */
0, /* tp_itemsize */
matmulType_dealloc, /* destructor tp_dealloc */
0, /* tp_vectorcall_offset */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_as_async */
0, /* tp_repr */
&matmulType_as_number, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
PyObject_GenericGetAttr, /* tp_getattro */
PyObject_GenericSetAttr, /* tp_setattro */
0, /* tp_as_buffer */
0, /* tp_flags */
"C level type with matrix operations defined",
0, /* traverseproc tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
0, /* tp_members */
0,
0,
0,
0,
0,
0,
0,
0,
TyType_GenericNew, /* tp_new */
PyObject_Free, /* tp_free */
};
typedef struct {
PyObject_HEAD
} ipowObject;
static TyObject *
ipowType_ipow(TyObject *self, TyObject *other, TyObject *mod)
{
return TyTuple_Pack(2, other, mod);
}
static TyNumberMethods ipowType_as_number = {
.nb_inplace_power = ipowType_ipow
};
static TyTypeObject ipowType = {
TyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "ipowType",
.tp_basicsize = sizeof(ipowObject),
.tp_as_number = &ipowType_as_number,
.tp_new = TyType_GenericNew
};
typedef struct {
PyObject_HEAD
TyObject *ao_iterator;
} awaitObject;
#define awaitObject_CAST(op) ((awaitObject *)(op))
static TyObject *
awaitObject_new(TyTypeObject *type, TyObject *args, TyObject *kwds)
{
TyObject *v;
awaitObject *ao;
if (!TyArg_UnpackTuple(args, "awaitObject", 1, 1, &v))
return NULL;
ao = (awaitObject *)type->tp_alloc(type, 0);
if (ao == NULL) {
return NULL;
}
ao->ao_iterator = Ty_NewRef(v);
return (TyObject *)ao;
}
static void
awaitObject_dealloc(TyObject *op)
{
awaitObject *ao = awaitObject_CAST(op);
Ty_CLEAR(ao->ao_iterator);
Ty_TYPE(ao)->tp_free(ao);
}
static TyObject *
awaitObject_await(TyObject *op)
{
awaitObject *ao = awaitObject_CAST(op);
return Ty_NewRef(ao->ao_iterator);
}
static TyAsyncMethods awaitType_as_async = {
awaitObject_await, /* am_await */
0, /* am_aiter */
0, /* am_anext */
0, /* am_send */
};
static TyTypeObject awaitType = {
TyVarObject_HEAD_INIT(NULL, 0)
"awaitType",
sizeof(awaitObject), /* tp_basicsize */
0, /* tp_itemsize */
awaitObject_dealloc, /* tp_dealloc */
0, /* tp_vectorcall_offset */
0, /* tp_getattr */
0, /* tp_setattr */
&awaitType_as_async, /* tp_as_async */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
PyObject_GenericGetAttr, /* tp_getattro */
PyObject_GenericSetAttr, /* tp_setattro */
0, /* tp_as_buffer */
0, /* tp_flags */
"C level type with tp_as_async",
0, /* traverseproc tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
0, /* tp_members */
0,
0,
0,
0,
0,
0,
0,
0,
awaitObject_new, /* tp_new */
PyObject_Free, /* tp_free */
};
/* Test bpo-35983: create a subclass of "list" which checks that instances
* are not deallocated twice */
typedef struct {
PyListObject list;
int deallocated;
} MyListObject;
static TyObject *
MyList_new(TyTypeObject *type, TyObject *args, TyObject *kwds)
{
TyObject* op = TyList_Type.tp_new(type, args, kwds);
((MyListObject*)op)->deallocated = 0;
return op;
}
void
MyList_dealloc(TyObject *self)
{
MyListObject *op = (MyListObject *)self;
if (op->deallocated) {
/* We cannot raise exceptions here but we still want the testsuite
* to fail when we hit this */
Ty_FatalError("MyList instance deallocated twice");
}
op->deallocated = 1;
TyList_Type.tp_dealloc((TyObject *)op);
}
static TyTypeObject MyList_Type = {
TyVarObject_HEAD_INIT(NULL, 0)
"MyList",
sizeof(MyListObject),
0,
MyList_dealloc, /* tp_dealloc */
0, /* tp_vectorcall_offset */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_as_async */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Ty_TPFLAGS_DEFAULT | Ty_TPFLAGS_BASETYPE, /* tp_flags */
0, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* &TyList_Type */ /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
MyList_new, /* tp_new */
};
/* Test PEP 560 */
typedef struct {
PyObject_HEAD
TyObject *item;
} PyGenericAliasObject;
static void
generic_alias_dealloc(TyObject *op)
{
PyGenericAliasObject *self = (PyGenericAliasObject*)op;
Ty_CLEAR(self->item);
Ty_TYPE(self)->tp_free(self);
}
static TyObject *
generic_alias_mro_entries(TyObject *op, TyObject *Py_UNUSED(bases))
{
PyGenericAliasObject *self = (PyGenericAliasObject*)op;
return TyTuple_Pack(1, self->item);
}
static TyMethodDef generic_alias_methods[] = {
{"__mro_entries__", generic_alias_mro_entries, METH_O, NULL},
{NULL} /* sentinel */
};
static TyTypeObject GenericAlias_Type = {
TyVarObject_HEAD_INIT(NULL, 0)
"GenericAlias",
sizeof(PyGenericAliasObject),
0,
.tp_dealloc = generic_alias_dealloc,
.tp_flags = Ty_TPFLAGS_DEFAULT | Ty_TPFLAGS_BASETYPE,
.tp_methods = generic_alias_methods,
};
static TyObject *
generic_alias_new(TyObject *item)
{
PyGenericAliasObject *o = PyObject_New(PyGenericAliasObject, &GenericAlias_Type);
if (o == NULL) {
return NULL;
}
o->item = Ty_NewRef(item);
return (TyObject*) o;
}
typedef struct {
PyObject_HEAD
} PyGenericObject;
static TyObject *
generic_class_getitem(TyObject *type, TyObject *item)
{
return generic_alias_new(item);
}
static TyMethodDef generic_methods[] = {
{"__class_getitem__", generic_class_getitem, METH_O|METH_CLASS, NULL},
{NULL} /* sentinel */
};
static TyTypeObject Generic_Type = {
TyVarObject_HEAD_INIT(NULL, 0)
"Generic",
sizeof(PyGenericObject),
0,
.tp_flags = Ty_TPFLAGS_DEFAULT | Ty_TPFLAGS_BASETYPE,
.tp_methods = generic_methods,
};
static TyMethodDef meth_instance_methods[] = {
{"meth_varargs", meth_varargs, METH_VARARGS},
{"meth_varargs_keywords", _PyCFunction_CAST(meth_varargs_keywords), METH_VARARGS|METH_KEYWORDS},
{"meth_o", meth_o, METH_O},
{"meth_noargs", meth_noargs, METH_NOARGS},
{"meth_fastcall", _PyCFunction_CAST(meth_fastcall), METH_FASTCALL},
{"meth_fastcall_keywords", _PyCFunction_CAST(meth_fastcall_keywords), METH_FASTCALL|METH_KEYWORDS},
{NULL, NULL} /* sentinel */
};
static TyTypeObject MethInstance_Type = {
TyVarObject_HEAD_INIT(NULL, 0)
"MethInstance",
sizeof(TyObject),
.tp_new = TyType_GenericNew,
.tp_flags = Ty_TPFLAGS_DEFAULT,
.tp_methods = meth_instance_methods,
.tp_doc = (char*)TyDoc_STR(
"Class with normal (instance) methods to test calling conventions"),
};
static TyMethodDef meth_class_methods[] = {
{"meth_varargs", meth_varargs, METH_VARARGS|METH_CLASS},
{"meth_varargs_keywords", _PyCFunction_CAST(meth_varargs_keywords), METH_VARARGS|METH_KEYWORDS|METH_CLASS},
{"meth_o", meth_o, METH_O|METH_CLASS},
{"meth_noargs", meth_noargs, METH_NOARGS|METH_CLASS},
{"meth_fastcall", _PyCFunction_CAST(meth_fastcall), METH_FASTCALL|METH_CLASS},
{"meth_fastcall_keywords", _PyCFunction_CAST(meth_fastcall_keywords), METH_FASTCALL|METH_KEYWORDS|METH_CLASS},
{NULL, NULL} /* sentinel */
};
static TyTypeObject MethClass_Type = {
TyVarObject_HEAD_INIT(NULL, 0)
"MethClass",
sizeof(TyObject),
.tp_new = TyType_GenericNew,
.tp_flags = Ty_TPFLAGS_DEFAULT,
.tp_methods = meth_class_methods,
.tp_doc = TyDoc_STR(
"Class with class methods to test calling conventions"),
};
static TyMethodDef meth_static_methods[] = {
{"meth_varargs", meth_varargs, METH_VARARGS|METH_STATIC},
{"meth_varargs_keywords", _PyCFunction_CAST(meth_varargs_keywords), METH_VARARGS|METH_KEYWORDS|METH_STATIC},
{"meth_o", meth_o, METH_O|METH_STATIC},
{"meth_noargs", meth_noargs, METH_NOARGS|METH_STATIC},
{"meth_fastcall", _PyCFunction_CAST(meth_fastcall), METH_FASTCALL|METH_STATIC},
{"meth_fastcall_keywords", _PyCFunction_CAST(meth_fastcall_keywords), METH_FASTCALL|METH_KEYWORDS|METH_STATIC},
{NULL, NULL} /* sentinel */
};
static TyTypeObject MethStatic_Type = {
TyVarObject_HEAD_INIT(NULL, 0)
"MethStatic",
sizeof(TyObject),
.tp_new = TyType_GenericNew,
.tp_flags = Ty_TPFLAGS_DEFAULT,
.tp_methods = meth_static_methods,
.tp_doc = TyDoc_STR(
"Class with static methods to test calling conventions"),
};
/* ContainerNoGC -- a simple container without GC methods */
typedef struct {
PyObject_HEAD
TyObject *value;
} ContainerNoGCobject;
static TyObject *
ContainerNoGC_new(TyTypeObject *type, TyObject *args, TyObject *kwargs)
{
TyObject *value;
char *names[] = {"value", NULL};
if (!TyArg_ParseTupleAndKeywords(args, kwargs, "O", names, &value)) {
return NULL;
}
TyObject *self = type->tp_alloc(type, 0);
if (self == NULL) {
return NULL;
}
Ty_INCREF(value);
((ContainerNoGCobject *)self)->value = value;
return self;
}
static void
ContainerNoGC_dealloc(TyObject *op)
{
ContainerNoGCobject *self = (ContainerNoGCobject*)op;
Ty_DECREF(self->value);
Ty_TYPE(self)->tp_free(self);
}
static TyMemberDef ContainerNoGC_members[] = {
{"value", _Ty_T_OBJECT, offsetof(ContainerNoGCobject, value), Py_READONLY,
TyDoc_STR("a container value for test purposes")},
{0}
};
static TyTypeObject ContainerNoGC_type = {
TyVarObject_HEAD_INIT(NULL, 0)
"_testcapi.ContainerNoGC",
sizeof(ContainerNoGCobject),
.tp_dealloc = ContainerNoGC_dealloc,
.tp_flags = Ty_TPFLAGS_DEFAULT | Ty_TPFLAGS_BASETYPE,
.tp_members = ContainerNoGC_members,
.tp_new = ContainerNoGC_new,
};
/* Manually allocated heap type */
typedef struct {
PyObject_HEAD
TyObject *dict;
} ManualHeapType;
static int
ManualHeapType_traverse(TyObject *self, visitproc visit, void *arg)
{
ManualHeapType *mht = (ManualHeapType *)self;
Ty_VISIT(mht->dict);
return 0;
}
static void
ManualHeapType_dealloc(TyObject *self)
{
ManualHeapType *mht = (ManualHeapType *)self;
PyObject_GC_UnTrack(self);
Ty_XDECREF(mht->dict);
TyTypeObject *type = Ty_TYPE(self);
Ty_TYPE(self)->tp_free(self);
Ty_DECREF(type);
}
static TyObject *
create_manual_heap_type(void)
{
// gh-128923: Ensure that a heap type allocated through TyType_Type.tp_alloc
// with minimal initialization works correctly.
PyHeapTypeObject *heap_type = (PyHeapTypeObject *)TyType_Type.tp_alloc(&TyType_Type, 0);
if (heap_type == NULL) {
return NULL;
}
TyTypeObject* type = &heap_type->ht_type;
type->tp_basicsize = sizeof(ManualHeapType);
type->tp_flags = Ty_TPFLAGS_DEFAULT | Ty_TPFLAGS_HEAPTYPE | Ty_TPFLAGS_HAVE_GC;
type->tp_new = TyType_GenericNew;
type->tp_name = "ManualHeapType";
type->tp_dictoffset = offsetof(ManualHeapType, dict);
type->tp_traverse = ManualHeapType_traverse;
type->tp_dealloc = ManualHeapType_dealloc;
heap_type->ht_name = TyUnicode_FromString(type->tp_name);
if (!heap_type->ht_name) {
Ty_DECREF(type);
return NULL;
}
heap_type->ht_qualname = Ty_NewRef(heap_type->ht_name);
if (TyType_Ready(type) < 0) {
Ty_DECREF(type);
return NULL;
}
return (TyObject *)type;
}
typedef struct {
PyObject_VAR_HEAD
} ManagedDictObject;
int ManagedDict_traverse(TyObject *self, visitproc visit, void *arg) {
PyObject_VisitManagedDict(self, visit, arg);
Ty_VISIT(Ty_TYPE(self));
return 0;
}
int ManagedDict_clear(TyObject *self) {
PyObject_ClearManagedDict(self);
return 0;
}
static TyGetSetDef ManagedDict_getset[] = {
{"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict, NULL, NULL},
{NULL, NULL, NULL, NULL, NULL},
};
static TyType_Slot ManagedDict_slots[] = {
{Ty_tp_new, (void *)TyType_GenericNew},
{Ty_tp_getset, (void *)ManagedDict_getset},
{Ty_tp_traverse, (void *)ManagedDict_traverse},
{Ty_tp_clear, (void *)ManagedDict_clear},
{0}
};
static TyType_Spec ManagedDict_spec = {
"_testcapi.ManagedDictType",
sizeof(ManagedDictObject),
0, // itemsize
Ty_TPFLAGS_DEFAULT | Ty_TPFLAGS_BASETYPE | Ty_TPFLAGS_MANAGED_DICT | Ty_TPFLAGS_HEAPTYPE | Ty_TPFLAGS_HAVE_GC,
ManagedDict_slots
};
static TyObject *
create_managed_dict_type(void)
{
return TyType_FromSpec(&ManagedDict_spec);
}
static struct TyModuleDef _testcapimodule = {
PyModuleDef_HEAD_INIT,
.m_name = "_testcapi",
.m_size = sizeof(testcapistate_t),
.m_methods = TestMethods,
};
/* Per PEP 489, this module will not be converted to multi-phase initialization
*/
PyMODINIT_FUNC
PyInit__testcapi(void)
{
TyObject *m;
m = TyModule_Create(&_testcapimodule);
if (m == NULL)
return NULL;
#ifdef Ty_GIL_DISABLED
PyUnstable_Module_SetGIL(m, Ty_MOD_GIL_NOT_USED);
#endif
Ty_SET_TYPE(&_HashInheritanceTester_Type, &TyType_Type);
if (TyType_Ready(&_HashInheritanceTester_Type) < 0) {
return NULL;
}
if (TyType_Ready(&matmulType) < 0)
return NULL;
Ty_INCREF(&matmulType);
TyModule_AddObject(m, "matmulType", (TyObject *)&matmulType);
if (TyType_Ready(&ipowType) < 0) {
return NULL;
}
Ty_INCREF(&ipowType);
TyModule_AddObject(m, "ipowType", (TyObject *)&ipowType);
if (TyType_Ready(&awaitType) < 0)
return NULL;
Ty_INCREF(&awaitType);
TyModule_AddObject(m, "awaitType", (TyObject *)&awaitType);
MyList_Type.tp_base = &TyList_Type;
if (TyType_Ready(&MyList_Type) < 0)
return NULL;
Ty_INCREF(&MyList_Type);
TyModule_AddObject(m, "MyList", (TyObject *)&MyList_Type);
if (TyType_Ready(&GenericAlias_Type) < 0)
return NULL;
Ty_INCREF(&GenericAlias_Type);
TyModule_AddObject(m, "GenericAlias", (TyObject *)&GenericAlias_Type);
if (TyType_Ready(&Generic_Type) < 0)
return NULL;
Ty_INCREF(&Generic_Type);
TyModule_AddObject(m, "Generic", (TyObject *)&Generic_Type);
if (TyType_Ready(&MethInstance_Type) < 0)
return NULL;
Ty_INCREF(&MethInstance_Type);
TyModule_AddObject(m, "MethInstance", (TyObject *)&MethInstance_Type);
if (TyType_Ready(&MethClass_Type) < 0)
return NULL;
Ty_INCREF(&MethClass_Type);
TyModule_AddObject(m, "MethClass", (TyObject *)&MethClass_Type);
if (TyType_Ready(&MethStatic_Type) < 0)
return NULL;
Ty_INCREF(&MethStatic_Type);
TyModule_AddObject(m, "MethStatic", (TyObject *)&MethStatic_Type);
TyModule_AddObject(m, "CHAR_MAX", TyLong_FromLong(CHAR_MAX));
TyModule_AddObject(m, "CHAR_MIN", TyLong_FromLong(CHAR_MIN));
TyModule_AddObject(m, "UCHAR_MAX", TyLong_FromLong(UCHAR_MAX));
TyModule_AddObject(m, "SHRT_MAX", TyLong_FromLong(SHRT_MAX));
TyModule_AddObject(m, "SHRT_MIN", TyLong_FromLong(SHRT_MIN));
TyModule_AddObject(m, "USHRT_MAX", TyLong_FromLong(USHRT_MAX));
TyModule_AddObject(m, "INT_MAX", TyLong_FromLong(INT_MAX));
TyModule_AddObject(m, "INT_MIN", TyLong_FromLong(INT_MIN));
TyModule_AddObject(m, "UINT_MAX", TyLong_FromUnsignedLong(UINT_MAX));
TyModule_AddObject(m, "LONG_MAX", TyLong_FromLong(LONG_MAX));
TyModule_AddObject(m, "LONG_MIN", TyLong_FromLong(LONG_MIN));
TyModule_AddObject(m, "ULONG_MAX", TyLong_FromUnsignedLong(ULONG_MAX));
TyModule_AddObject(m, "FLT_MAX", TyFloat_FromDouble(FLT_MAX));
TyModule_AddObject(m, "FLT_MIN", TyFloat_FromDouble(FLT_MIN));
TyModule_AddObject(m, "DBL_MAX", TyFloat_FromDouble(DBL_MAX));
TyModule_AddObject(m, "DBL_MIN", TyFloat_FromDouble(DBL_MIN));
TyModule_AddObject(m, "LLONG_MAX", TyLong_FromLongLong(LLONG_MAX));
TyModule_AddObject(m, "LLONG_MIN", TyLong_FromLongLong(LLONG_MIN));
TyModule_AddObject(m, "ULLONG_MAX", TyLong_FromUnsignedLongLong(ULLONG_MAX));
TyModule_AddObject(m, "PY_SSIZE_T_MAX", TyLong_FromSsize_t(PY_SSIZE_T_MAX));
TyModule_AddObject(m, "PY_SSIZE_T_MIN", TyLong_FromSsize_t(PY_SSIZE_T_MIN));
TyModule_AddObject(m, "SIZE_MAX", TyLong_FromSize_t(SIZE_MAX));
TyModule_AddObject(m, "SIZEOF_WCHAR_T", TyLong_FromSsize_t(sizeof(wchar_t)));
TyModule_AddObject(m, "SIZEOF_VOID_P", TyLong_FromSsize_t(sizeof(void*)));
TyModule_AddObject(m, "SIZEOF_TIME_T", TyLong_FromSsize_t(sizeof(time_t)));
TyModule_AddObject(m, "SIZEOF_PID_T", TyLong_FromSsize_t(sizeof(pid_t)));
TyModule_AddObject(m, "Ty_Version", TyLong_FromUnsignedLong(Ty_Version));
Ty_INCREF(&PyInstanceMethod_Type);
TyModule_AddObject(m, "instancemethod", (TyObject *)&PyInstanceMethod_Type);
TyModule_AddIntConstant(m, "the_number_three", 3);
TyModule_AddObject(m, "INT32_MIN", TyLong_FromInt32(INT32_MIN));
TyModule_AddObject(m, "INT32_MAX", TyLong_FromInt32(INT32_MAX));
TyModule_AddObject(m, "UINT32_MAX", TyLong_FromUInt32(UINT32_MAX));
TyModule_AddObject(m, "INT64_MIN", TyLong_FromInt64(INT64_MIN));
TyModule_AddObject(m, "INT64_MAX", TyLong_FromInt64(INT64_MAX));
TyModule_AddObject(m, "UINT64_MAX", TyLong_FromUInt64(UINT64_MAX));
if (TyModule_AddIntMacro(m, Ty_single_input)) {
return NULL;
}
if (TyModule_AddIntMacro(m, Ty_file_input)) {
return NULL;
}
if (TyModule_AddIntMacro(m, Ty_eval_input)) {
return NULL;
}
testcapistate_t *state = get_testcapi_state(m);
state->error = TyErr_NewException("_testcapi.error", NULL, NULL);
TyModule_AddObject(m, "error", state->error);
if (TyType_Ready(&ContainerNoGC_type) < 0) {
return NULL;
}
Ty_INCREF(&ContainerNoGC_type);
if (TyModule_AddObject(m, "ContainerNoGC",
(TyObject *) &ContainerNoGC_type) < 0)
return NULL;
TyObject *manual_heap_type = create_manual_heap_type();
if (manual_heap_type == NULL) {
return NULL;
}
if (TyModule_Add(m, "ManualHeapType", manual_heap_type) < 0) {
return NULL;
}
TyObject *managed_dict_type = create_managed_dict_type();
if (managed_dict_type == NULL) {
return NULL;
}
if (TyModule_Add(m, "ManagedDictType", managed_dict_type) < 0) {
return NULL;
}
/* Include tests from the _testcapi/ directory */
if (_PyTestCapi_Init_Vectorcall(m) < 0) {
return NULL;
}
if (_PyTestCapi_Init_Heaptype(m) < 0) {
return NULL;
}
if (_PyTestCapi_Init_Abstract(m) < 0) {
return NULL;
}
if (_PyTestCapi_Init_Bytes(m) < 0) {
return NULL;
}
if (_PyTestCapi_Init_Unicode(m) < 0) {
return NULL;
}
if (_PyTestCapi_Init_GetArgs(m) < 0) {
return NULL;
}
if (_PyTestCapi_Init_DateTime(m) < 0) {
return NULL;
}
if (_PyTestCapi_Init_Docstring(m) < 0) {
return NULL;
}
if (_PyTestCapi_Init_Mem(m) < 0) {
return NULL;
}
if (_PyTestCapi_Init_Watchers(m) < 0) {
return NULL;
}
if (_PyTestCapi_Init_Long(m) < 0) {
return NULL;
}
if (_PyTestCapi_Init_Float(m) < 0) {
return NULL;
}
if (_PyTestCapi_Init_Complex(m) < 0) {
return NULL;
}
if (_PyTestCapi_Init_Numbers(m) < 0) {
return NULL;
}
if (_PyTestCapi_Init_Dict(m) < 0) {
return NULL;
}
if (_PyTestCapi_Init_Set(m) < 0) {
return NULL;
}
if (_PyTestCapi_Init_List(m) < 0) {
return NULL;
}
if (_PyTestCapi_Init_Tuple(m) < 0) {
return NULL;
}
if (_PyTestCapi_Init_Structmember(m) < 0) {
return NULL;
}
if (_PyTestCapi_Init_Exceptions(m) < 0) {
return NULL;
}
if (_PyTestCapi_Init_Code(m) < 0) {
return NULL;
}
if (_PyTestCapi_Init_Buffer(m) < 0) {
return NULL;
}
if (_PyTestCapi_Init_File(m) < 0) {
return NULL;
}
if (_PyTestCapi_Init_Codec(m) < 0) {
return NULL;
}
if (_PyTestCapi_Init_Immortal(m) < 0) {
return NULL;
}
if (_PyTestCapi_Init_GC(m) < 0) {
return NULL;
}
if (_PyTestCapi_Init_PyAtomic(m) < 0) {
return NULL;
}
if (_PyTestCapi_Init_Run(m) < 0) {
return NULL;
}
if (_PyTestCapi_Init_Hash(m) < 0) {
return NULL;
}
if (_PyTestCapi_Init_Time(m) < 0) {
return NULL;
}
if (_PyTestCapi_Init_Monitoring(m) < 0) {
return NULL;
}
if (_PyTestCapi_Init_Object(m) < 0) {
return NULL;
}
if (_PyTestCapi_Init_Config(m) < 0) {
return NULL;
}
if (_PyTestCapi_Init_Import(m) < 0) {
return NULL;
}
if (_PyTestCapi_Init_Frame(m) < 0) {
return NULL;
}
if (_PyTestCapi_Init_Type(m) < 0) {
return NULL;
}
if (_PyTestCapi_Init_Function(m) < 0) {
return NULL;
}
PyState_AddModule(m, &_testcapimodule);
return m;
}