blob: 7970e2f4f443fd340640611e05f08f05df3fd70f [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 Stinnerc6b292c2020-06-08 16:30:33 +020015#include "pycore_bitutils.h" // _Py_bswap32()
Victor Stinner3f2f4fe2020-03-13 13:07:31 +010016#include "pycore_initconfig.h" // _Py_GetConfigsAsDict()
Victor Stinnera482dc52020-05-14 21:55:47 +020017#include "pycore_hashtable.h" // _Py_hashtable_new()
Victor Stinner01355982020-04-13 11:38:42 +020018#include "pycore_gc.h" // PyGC_Head
Victor Stinner23bace22019-04-18 11:37:26 +020019
20
21static PyObject *
22get_configs(PyObject *self, PyObject *Py_UNUSED(args))
23{
24 return _Py_GetConfigsAsDict();
25}
26
27
Victor Stinner3f2f4fe2020-03-13 13:07:31 +010028static PyObject*
Victor Stinner1ae035b2020-04-17 17:47:20 +020029get_recursion_depth(PyObject *self, PyObject *Py_UNUSED(args))
Victor Stinner3f2f4fe2020-03-13 13:07:31 +010030{
31 PyThreadState *tstate = PyThreadState_Get();
32
33 /* subtract one to ignore the frame of the get_recursion_depth() call */
34 return PyLong_FromLong(tstate->recursion_depth - 1);
35}
36
37
Victor Stinner1ae035b2020-04-17 17:47:20 +020038static PyObject*
39test_bswap(PyObject *self, PyObject *Py_UNUSED(args))
40{
41 uint16_t u16 = _Py_bswap16(UINT16_C(0x3412));
42 if (u16 != UINT16_C(0x1234)) {
43 PyErr_Format(PyExc_AssertionError,
44 "_Py_bswap16(0x3412) returns %u", u16);
45 return NULL;
46 }
47
48 uint32_t u32 = _Py_bswap32(UINT32_C(0x78563412));
49 if (u32 != UINT32_C(0x12345678)) {
50 PyErr_Format(PyExc_AssertionError,
51 "_Py_bswap32(0x78563412) returns %lu", u32);
52 return NULL;
53 }
54
55 uint64_t u64 = _Py_bswap64(UINT64_C(0xEFCDAB9078563412));
56 if (u64 != UINT64_C(0x1234567890ABCDEF)) {
57 PyErr_Format(PyExc_AssertionError,
58 "_Py_bswap64(0xEFCDAB9078563412) returns %llu", u64);
59 return NULL;
60 }
61
62 Py_RETURN_NONE;
63}
64
65
Victor Stinnerc6b292c2020-06-08 16:30:33 +020066static int
67check_popcount(uint32_t x, int expected)
68{
69 // Use volatile to prevent the compiler to optimize out the whole test
70 volatile uint32_t u = x;
71 int bits = _Py_popcount32(u);
72 if (bits != expected) {
73 PyErr_Format(PyExc_AssertionError,
74 "_Py_popcount32(%lu) returns %i, expected %i",
75 (unsigned long)x, bits, expected);
76 return -1;
77 }
78 return 0;
79}
80
81
82static PyObject*
83test_popcount(PyObject *self, PyObject *Py_UNUSED(args))
84{
85#define CHECK(X, RESULT) \
86 do { \
87 if (check_popcount(X, RESULT) < 0) { \
88 return NULL; \
89 } \
90 } while (0)
91
92 CHECK(0, 0);
93 CHECK(1, 1);
94 CHECK(0x08080808, 4);
95 CHECK(0x10101010, 4);
96 CHECK(0x10204080, 4);
97 CHECK(0xDEADCAFE, 22);
98 CHECK(0xFFFFFFFF, 32);
99 Py_RETURN_NONE;
100
101#undef CHECK
102}
103
104
Niklas Fiekas794e7d12020-06-15 14:33:48 +0200105static int
106check_bit_length(unsigned long x, int expected)
107{
108 // Use volatile to prevent the compiler to optimize out the whole test
109 volatile unsigned long u = x;
110 int len = _Py_bit_length(u);
111 if (len != expected) {
112 PyErr_Format(PyExc_AssertionError,
113 "_Py_bit_length(%lu) returns %i, expected %i",
114 x, len, expected);
115 return -1;
116 }
117 return 0;
118}
119
120
121static PyObject*
122test_bit_length(PyObject *self, PyObject *Py_UNUSED(args))
123{
124#define CHECK(X, RESULT) \
125 do { \
126 if (check_bit_length(X, RESULT) < 0) { \
127 return NULL; \
128 } \
129 } while (0)
130
131 CHECK(0, 0);
132 CHECK(1, 1);
133 CHECK(0x1000, 13);
134 CHECK(0x1234, 13);
135 CHECK(0x54321, 19);
136 CHECK(0x7FFFFFFF, 31);
137 CHECK(0xFFFFFFFF, 32);
138 Py_RETURN_NONE;
139
140#undef CHECK
141}
142
143
Victor Stinnera482dc52020-05-14 21:55:47 +0200144#define TO_PTR(ch) ((void*)(uintptr_t)ch)
145#define FROM_PTR(ptr) ((uintptr_t)ptr)
146#define VALUE(key) (1 + ((int)(key) - 'a'))
147
148static Py_uhash_t
149hash_char(const void *key)
150{
151 char ch = (char)FROM_PTR(key);
152 return ch;
153}
154
155
156static int
157hashtable_cb(_Py_hashtable_t *table,
158 const void *key_ptr, const void *value_ptr,
159 void *user_data)
160{
161 int *count = (int *)user_data;
162 char key = (char)FROM_PTR(key_ptr);
163 int value = (int)FROM_PTR(value_ptr);
164 assert(value == VALUE(key));
165 *count += 1;
166 return 0;
167}
168
169
170static PyObject*
171test_hashtable(PyObject *self, PyObject *Py_UNUSED(args))
172{
173 _Py_hashtable_t *table = _Py_hashtable_new(hash_char,
174 _Py_hashtable_compare_direct);
175 if (table == NULL) {
176 return PyErr_NoMemory();
177 }
178
Victor Stinnerd2dc8272020-05-14 22:44:32 +0200179 // Using an newly allocated table must not crash
180 assert(table->nentries == 0);
181 assert(table->nbuckets > 0);
182 assert(_Py_hashtable_get(table, TO_PTR('x')) == NULL);
183
Victor Stinnera482dc52020-05-14 21:55:47 +0200184 // Test _Py_hashtable_set()
185 char key;
186 for (key='a'; key <= 'z'; key++) {
187 int value = VALUE(key);
188 if (_Py_hashtable_set(table, TO_PTR(key), TO_PTR(value)) < 0) {
189 _Py_hashtable_destroy(table);
190 return PyErr_NoMemory();
191 }
192 }
193 assert(table->nentries == 26);
194 assert(table->nbuckets > table->nentries);
195
196 // Test _Py_hashtable_get_entry()
197 for (key='a'; key <= 'z'; key++) {
198 _Py_hashtable_entry_t *entry = _Py_hashtable_get_entry(table, TO_PTR(key));
199 assert(entry != NULL);
200 assert(entry->key = TO_PTR(key));
201 assert(entry->value = TO_PTR(VALUE(key)));
202 }
203
204 // Test _Py_hashtable_get()
205 for (key='a'; key <= 'z'; key++) {
206 void *value_ptr = _Py_hashtable_get(table, TO_PTR(key));
Victor Stinnerd2dc8272020-05-14 22:44:32 +0200207 assert((int)FROM_PTR(value_ptr) == VALUE(key));
Victor Stinnera482dc52020-05-14 21:55:47 +0200208 }
209
210 // Test _Py_hashtable_steal()
211 key = 'p';
212 void *value_ptr = _Py_hashtable_steal(table, TO_PTR(key));
Victor Stinnerd2dc8272020-05-14 22:44:32 +0200213 assert((int)FROM_PTR(value_ptr) == VALUE(key));
Victor Stinnera482dc52020-05-14 21:55:47 +0200214 assert(table->nentries == 25);
Victor Stinnerd2dc8272020-05-14 22:44:32 +0200215 assert(_Py_hashtable_get_entry(table, TO_PTR(key)) == NULL);
Victor Stinnera482dc52020-05-14 21:55:47 +0200216
217 // Test _Py_hashtable_foreach()
218 int count = 0;
219 int res = _Py_hashtable_foreach(table, hashtable_cb, &count);
220 assert(res == 0);
221 assert(count == 25);
222
223 // Test _Py_hashtable_clear()
224 _Py_hashtable_clear(table);
225 assert(table->nentries == 0);
Victor Stinnerd2dc8272020-05-14 22:44:32 +0200226 assert(table->nbuckets > 0);
Victor Stinnera482dc52020-05-14 21:55:47 +0200227 assert(_Py_hashtable_get(table, TO_PTR('x')) == NULL);
228
229 _Py_hashtable_destroy(table);
230 Py_RETURN_NONE;
231}
232
233
Victor Stinner23bace22019-04-18 11:37:26 +0200234static PyMethodDef TestMethods[] = {
235 {"get_configs", get_configs, METH_NOARGS},
Victor Stinner3f2f4fe2020-03-13 13:07:31 +0100236 {"get_recursion_depth", get_recursion_depth, METH_NOARGS},
Victor Stinner1ae035b2020-04-17 17:47:20 +0200237 {"test_bswap", test_bswap, METH_NOARGS},
Victor Stinnerc6b292c2020-06-08 16:30:33 +0200238 {"test_popcount", test_popcount, METH_NOARGS},
Niklas Fiekas794e7d12020-06-15 14:33:48 +0200239 {"test_bit_length", test_bit_length, METH_NOARGS},
Victor Stinnera482dc52020-05-14 21:55:47 +0200240 {"test_hashtable", test_hashtable, METH_NOARGS},
Victor Stinner23bace22019-04-18 11:37:26 +0200241 {NULL, NULL} /* sentinel */
242};
243
244
245static struct PyModuleDef _testcapimodule = {
246 PyModuleDef_HEAD_INIT,
247 "_testinternalcapi",
248 NULL,
249 -1,
250 TestMethods,
251 NULL,
252 NULL,
253 NULL,
254 NULL
255};
256
257
258PyMODINIT_FUNC
259PyInit__testinternalcapi(void)
260{
Victor Stinner01355982020-04-13 11:38:42 +0200261 PyObject *module = PyModule_Create(&_testcapimodule);
262 if (module == NULL) {
263 return NULL;
264 }
265
266 if (PyModule_AddObject(module, "SIZEOF_PYGC_HEAD",
267 PyLong_FromSsize_t(sizeof(PyGC_Head))) < 0) {
268 goto error;
269 }
270
271 return module;
272
273error:
274 Py_DECREF(module);
275 return NULL;
Victor Stinner23bace22019-04-18 11:37:26 +0200276}