/* * 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 // FLT_MAX #include #include // offsetof() #ifdef HAVE_SYS_WAIT_H # include // W_STOPCODE #endif #ifdef bool # error "The public headers should not include , 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, "", 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 */ 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(¤t_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; }