blob: ab6c5965d1661be00ee55e5d1aa80f9beeb763a3 [file] [log] [blame]
Victor Stinner23bace22019-04-18 11:37:26 +02001/*
2 * C Extension module to test Python internal C APIs (Include/internal).
3 */
4
5#if !defined(Py_BUILD_CORE_BUILTIN) && !defined(Py_BUILD_CORE_MODULE)
6# error "Py_BUILD_CORE_BUILTIN or Py_BUILD_CORE_MODULE must be defined"
7#endif
8
Hai Shi5dd21f52020-04-21 00:49:13 +08009/* Always enable assertions */
10#undef NDEBUG
11
Victor Stinner23bace22019-04-18 11:37:26 +020012#define PY_SSIZE_T_CLEAN
13
14#include "Python.h"
Victor Stinner52a327c2020-12-23 03:41:08 +010015#include "pycore_atomic_funcs.h" // _Py_atomic_int_get()
Victor Stinnerc6b292c2020-06-08 16:30:33 +020016#include "pycore_bitutils.h" // _Py_bswap32()
Victor Stinner01355982020-04-13 11:38:42 +020017#include "pycore_gc.h" // PyGC_Head
Victor Stinnerf3cb8142020-11-05 18:12:33 +010018#include "pycore_hashtable.h" // _Py_hashtable_new()
19#include "pycore_initconfig.h" // _Py_GetConfigsAsDict()
20#include "pycore_interp.h" // _PyInterpreterState_GetConfigCopy()
Victor Stinner23bace22019-04-18 11:37:26 +020021
22
23static PyObject *
24get_configs(PyObject *self, PyObject *Py_UNUSED(args))
25{
Victor Stinner8f427482020-07-08 00:20:37 +020026 return _Py_GetConfigsAsDict();
Victor Stinner23bace22019-04-18 11:37:26 +020027}
28
29
Victor Stinner3f2f4fe2020-03-13 13:07:31 +010030static PyObject*
Victor Stinner1ae035b2020-04-17 17:47:20 +020031get_recursion_depth(PyObject *self, PyObject *Py_UNUSED(args))
Victor Stinner3f2f4fe2020-03-13 13:07:31 +010032{
33 PyThreadState *tstate = PyThreadState_Get();
34
35 /* subtract one to ignore the frame of the get_recursion_depth() call */
36 return PyLong_FromLong(tstate->recursion_depth - 1);
37}
38
39
Victor Stinner1ae035b2020-04-17 17:47:20 +020040static PyObject*
41test_bswap(PyObject *self, PyObject *Py_UNUSED(args))
42{
43 uint16_t u16 = _Py_bswap16(UINT16_C(0x3412));
44 if (u16 != UINT16_C(0x1234)) {
45 PyErr_Format(PyExc_AssertionError,
46 "_Py_bswap16(0x3412) returns %u", u16);
47 return NULL;
48 }
49
50 uint32_t u32 = _Py_bswap32(UINT32_C(0x78563412));
51 if (u32 != UINT32_C(0x12345678)) {
52 PyErr_Format(PyExc_AssertionError,
53 "_Py_bswap32(0x78563412) returns %lu", u32);
54 return NULL;
55 }
56
57 uint64_t u64 = _Py_bswap64(UINT64_C(0xEFCDAB9078563412));
58 if (u64 != UINT64_C(0x1234567890ABCDEF)) {
59 PyErr_Format(PyExc_AssertionError,
60 "_Py_bswap64(0xEFCDAB9078563412) returns %llu", u64);
61 return NULL;
62 }
63
64 Py_RETURN_NONE;
65}
66
67
Victor Stinnerc6b292c2020-06-08 16:30:33 +020068static int
69check_popcount(uint32_t x, int expected)
70{
71 // Use volatile to prevent the compiler to optimize out the whole test
72 volatile uint32_t u = x;
73 int bits = _Py_popcount32(u);
74 if (bits != expected) {
75 PyErr_Format(PyExc_AssertionError,
76 "_Py_popcount32(%lu) returns %i, expected %i",
77 (unsigned long)x, bits, expected);
78 return -1;
79 }
80 return 0;
81}
82
83
84static PyObject*
85test_popcount(PyObject *self, PyObject *Py_UNUSED(args))
86{
87#define CHECK(X, RESULT) \
88 do { \
89 if (check_popcount(X, RESULT) < 0) { \
90 return NULL; \
91 } \
92 } while (0)
93
94 CHECK(0, 0);
95 CHECK(1, 1);
96 CHECK(0x08080808, 4);
97 CHECK(0x10101010, 4);
98 CHECK(0x10204080, 4);
99 CHECK(0xDEADCAFE, 22);
100 CHECK(0xFFFFFFFF, 32);
101 Py_RETURN_NONE;
102
103#undef CHECK
104}
105
106
Niklas Fiekas794e7d12020-06-15 14:33:48 +0200107static int
108check_bit_length(unsigned long x, int expected)
109{
110 // Use volatile to prevent the compiler to optimize out the whole test
111 volatile unsigned long u = x;
112 int len = _Py_bit_length(u);
113 if (len != expected) {
114 PyErr_Format(PyExc_AssertionError,
115 "_Py_bit_length(%lu) returns %i, expected %i",
116 x, len, expected);
117 return -1;
118 }
119 return 0;
120}
121
122
123static PyObject*
124test_bit_length(PyObject *self, PyObject *Py_UNUSED(args))
125{
126#define CHECK(X, RESULT) \
127 do { \
128 if (check_bit_length(X, RESULT) < 0) { \
129 return NULL; \
130 } \
131 } while (0)
132
133 CHECK(0, 0);
134 CHECK(1, 1);
135 CHECK(0x1000, 13);
136 CHECK(0x1234, 13);
137 CHECK(0x54321, 19);
138 CHECK(0x7FFFFFFF, 31);
139 CHECK(0xFFFFFFFF, 32);
140 Py_RETURN_NONE;
141
142#undef CHECK
143}
144
145
Victor Stinnera482dc52020-05-14 21:55:47 +0200146#define TO_PTR(ch) ((void*)(uintptr_t)ch)
147#define FROM_PTR(ptr) ((uintptr_t)ptr)
148#define VALUE(key) (1 + ((int)(key) - 'a'))
149
150static Py_uhash_t
151hash_char(const void *key)
152{
153 char ch = (char)FROM_PTR(key);
154 return ch;
155}
156
157
158static int
159hashtable_cb(_Py_hashtable_t *table,
160 const void *key_ptr, const void *value_ptr,
161 void *user_data)
162{
163 int *count = (int *)user_data;
164 char key = (char)FROM_PTR(key_ptr);
165 int value = (int)FROM_PTR(value_ptr);
166 assert(value == VALUE(key));
167 *count += 1;
168 return 0;
169}
170
171
172static PyObject*
173test_hashtable(PyObject *self, PyObject *Py_UNUSED(args))
174{
175 _Py_hashtable_t *table = _Py_hashtable_new(hash_char,
176 _Py_hashtable_compare_direct);
177 if (table == NULL) {
178 return PyErr_NoMemory();
179 }
180
Victor Stinnerd2dc8272020-05-14 22:44:32 +0200181 // Using an newly allocated table must not crash
182 assert(table->nentries == 0);
183 assert(table->nbuckets > 0);
184 assert(_Py_hashtable_get(table, TO_PTR('x')) == NULL);
185
Victor Stinnera482dc52020-05-14 21:55:47 +0200186 // Test _Py_hashtable_set()
187 char key;
188 for (key='a'; key <= 'z'; key++) {
189 int value = VALUE(key);
190 if (_Py_hashtable_set(table, TO_PTR(key), TO_PTR(value)) < 0) {
191 _Py_hashtable_destroy(table);
192 return PyErr_NoMemory();
193 }
194 }
195 assert(table->nentries == 26);
196 assert(table->nbuckets > table->nentries);
197
198 // Test _Py_hashtable_get_entry()
199 for (key='a'; key <= 'z'; key++) {
200 _Py_hashtable_entry_t *entry = _Py_hashtable_get_entry(table, TO_PTR(key));
201 assert(entry != NULL);
Christian Heimes4901ea92020-06-22 09:41:48 +0200202 assert(entry->key == TO_PTR(key));
203 assert(entry->value == TO_PTR(VALUE(key)));
Victor Stinnera482dc52020-05-14 21:55:47 +0200204 }
205
206 // Test _Py_hashtable_get()
207 for (key='a'; key <= 'z'; key++) {
208 void *value_ptr = _Py_hashtable_get(table, TO_PTR(key));
Victor Stinnerd2dc8272020-05-14 22:44:32 +0200209 assert((int)FROM_PTR(value_ptr) == VALUE(key));
Victor Stinnera482dc52020-05-14 21:55:47 +0200210 }
211
212 // Test _Py_hashtable_steal()
213 key = 'p';
214 void *value_ptr = _Py_hashtable_steal(table, TO_PTR(key));
Victor Stinnerd2dc8272020-05-14 22:44:32 +0200215 assert((int)FROM_PTR(value_ptr) == VALUE(key));
Victor Stinnera482dc52020-05-14 21:55:47 +0200216 assert(table->nentries == 25);
Victor Stinnerd2dc8272020-05-14 22:44:32 +0200217 assert(_Py_hashtable_get_entry(table, TO_PTR(key)) == NULL);
Victor Stinnera482dc52020-05-14 21:55:47 +0200218
219 // Test _Py_hashtable_foreach()
220 int count = 0;
221 int res = _Py_hashtable_foreach(table, hashtable_cb, &count);
222 assert(res == 0);
223 assert(count == 25);
224
225 // Test _Py_hashtable_clear()
226 _Py_hashtable_clear(table);
227 assert(table->nentries == 0);
Victor Stinnerd2dc8272020-05-14 22:44:32 +0200228 assert(table->nbuckets > 0);
Victor Stinnera482dc52020-05-14 21:55:47 +0200229 assert(_Py_hashtable_get(table, TO_PTR('x')) == NULL);
230
231 _Py_hashtable_destroy(table);
232 Py_RETURN_NONE;
233}
234
235
Victor Stinnerf3cb8142020-11-05 18:12:33 +0100236static PyObject *
237test_get_config(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(args))
238{
239 PyConfig config;
240 PyConfig_InitIsolatedConfig(&config);
241 if (_PyInterpreterState_GetConfigCopy(&config) < 0) {
242 PyConfig_Clear(&config);
243 return NULL;
244 }
245 PyObject *dict = _PyConfig_AsDict(&config);
246 PyConfig_Clear(&config);
247 return dict;
248}
249
250
251static PyObject *
252test_set_config(PyObject *Py_UNUSED(self), PyObject *dict)
253{
254 PyConfig config;
255 PyConfig_InitIsolatedConfig(&config);
256 if (_PyConfig_FromDict(&config, dict) < 0) {
Victor Stinnerdc42af82020-11-05 18:58:07 +0100257 goto error;
Victor Stinnerf3cb8142020-11-05 18:12:33 +0100258 }
259 if (_PyInterpreterState_SetConfig(&config) < 0) {
Victor Stinnerdc42af82020-11-05 18:58:07 +0100260 goto error;
Victor Stinnerf3cb8142020-11-05 18:12:33 +0100261 }
262 PyConfig_Clear(&config);
263 Py_RETURN_NONE;
Victor Stinnerdc42af82020-11-05 18:58:07 +0100264
265error:
266 PyConfig_Clear(&config);
267 return NULL;
Victor Stinnerf3cb8142020-11-05 18:12:33 +0100268}
269
270
Victor Stinner52a327c2020-12-23 03:41:08 +0100271static PyObject*
272test_atomic_funcs(PyObject *self, PyObject *Py_UNUSED(args))
273{
274 // Test _Py_atomic_size_get() and _Py_atomic_size_set()
275 Py_ssize_t var = 1;
276 _Py_atomic_size_set(&var, 2);
277 assert(_Py_atomic_size_get(&var) == 2);
278 Py_RETURN_NONE;
279}
280
281
Victor Stinner23bace22019-04-18 11:37:26 +0200282static PyMethodDef TestMethods[] = {
283 {"get_configs", get_configs, METH_NOARGS},
Victor Stinner3f2f4fe2020-03-13 13:07:31 +0100284 {"get_recursion_depth", get_recursion_depth, METH_NOARGS},
Victor Stinner1ae035b2020-04-17 17:47:20 +0200285 {"test_bswap", test_bswap, METH_NOARGS},
Victor Stinnerc6b292c2020-06-08 16:30:33 +0200286 {"test_popcount", test_popcount, METH_NOARGS},
Niklas Fiekas794e7d12020-06-15 14:33:48 +0200287 {"test_bit_length", test_bit_length, METH_NOARGS},
Victor Stinnera482dc52020-05-14 21:55:47 +0200288 {"test_hashtable", test_hashtable, METH_NOARGS},
Victor Stinnerf3cb8142020-11-05 18:12:33 +0100289 {"get_config", test_get_config, METH_NOARGS},
290 {"set_config", test_set_config, METH_O},
Victor Stinner52a327c2020-12-23 03:41:08 +0100291 {"test_atomic_funcs", test_atomic_funcs, METH_NOARGS},
Victor Stinner23bace22019-04-18 11:37:26 +0200292 {NULL, NULL} /* sentinel */
293};
294
295
296static struct PyModuleDef _testcapimodule = {
297 PyModuleDef_HEAD_INIT,
298 "_testinternalcapi",
299 NULL,
300 -1,
301 TestMethods,
302 NULL,
303 NULL,
304 NULL,
305 NULL
306};
307
308
309PyMODINIT_FUNC
310PyInit__testinternalcapi(void)
311{
Victor Stinner01355982020-04-13 11:38:42 +0200312 PyObject *module = PyModule_Create(&_testcapimodule);
313 if (module == NULL) {
314 return NULL;
315 }
316
317 if (PyModule_AddObject(module, "SIZEOF_PYGC_HEAD",
318 PyLong_FromSsize_t(sizeof(PyGC_Head))) < 0) {
319 goto error;
320 }
321
322 return module;
323
324error:
325 Py_DECREF(module);
326 return NULL;
Victor Stinner23bace22019-04-18 11:37:26 +0200327}