blob: f08bf8d83d474397a28a7d28a34fc99638516137 [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
Steve Dowerdcbaa1b2020-07-06 17:32:00 +010021#ifdef MS_WINDOWS
22#include <windows.h>
23
24static int
25_add_windows_config(PyObject *configs)
26{
27 HMODULE hPython3;
28 wchar_t py3path[MAX_PATH];
29 PyObject *dict = PyDict_New();
30 PyObject *obj = NULL;
31 if (!dict) {
32 return -1;
33 }
34
35 hPython3 = GetModuleHandleW(PY3_DLLNAME);
36 if (hPython3 && GetModuleFileNameW(hPython3, py3path, MAX_PATH)) {
37 obj = PyUnicode_FromWideChar(py3path, -1);
38 } else {
39 obj = Py_None;
40 Py_INCREF(obj);
41 }
42 if (obj &&
43 !PyDict_SetItemString(dict, "python3_dll", obj) &&
44 !PyDict_SetItemString(configs, "windows", dict)) {
45 Py_DECREF(obj);
46 Py_DECREF(dict);
47 return 0;
48 }
49 Py_DECREF(obj);
50 Py_DECREF(dict);
51 return -1;
52}
53#endif
54
55
Victor Stinner23bace22019-04-18 11:37:26 +020056static PyObject *
57get_configs(PyObject *self, PyObject *Py_UNUSED(args))
58{
Steve Dowerdcbaa1b2020-07-06 17:32:00 +010059 PyObject *dict = _Py_GetConfigsAsDict();
60#ifdef MS_WINDOWS
61 if (dict) {
62 if (_add_windows_config(dict) < 0) {
63 Py_CLEAR(dict);
64 }
65 }
66#endif
67 return dict;
Victor Stinner23bace22019-04-18 11:37:26 +020068}
69
70
Victor Stinner3f2f4fe2020-03-13 13:07:31 +010071static PyObject*
Victor Stinner1ae035b2020-04-17 17:47:20 +020072get_recursion_depth(PyObject *self, PyObject *Py_UNUSED(args))
Victor Stinner3f2f4fe2020-03-13 13:07:31 +010073{
74 PyThreadState *tstate = PyThreadState_Get();
75
76 /* subtract one to ignore the frame of the get_recursion_depth() call */
77 return PyLong_FromLong(tstate->recursion_depth - 1);
78}
79
80
Victor Stinner1ae035b2020-04-17 17:47:20 +020081static PyObject*
82test_bswap(PyObject *self, PyObject *Py_UNUSED(args))
83{
84 uint16_t u16 = _Py_bswap16(UINT16_C(0x3412));
85 if (u16 != UINT16_C(0x1234)) {
86 PyErr_Format(PyExc_AssertionError,
87 "_Py_bswap16(0x3412) returns %u", u16);
88 return NULL;
89 }
90
91 uint32_t u32 = _Py_bswap32(UINT32_C(0x78563412));
92 if (u32 != UINT32_C(0x12345678)) {
93 PyErr_Format(PyExc_AssertionError,
94 "_Py_bswap32(0x78563412) returns %lu", u32);
95 return NULL;
96 }
97
98 uint64_t u64 = _Py_bswap64(UINT64_C(0xEFCDAB9078563412));
99 if (u64 != UINT64_C(0x1234567890ABCDEF)) {
100 PyErr_Format(PyExc_AssertionError,
101 "_Py_bswap64(0xEFCDAB9078563412) returns %llu", u64);
102 return NULL;
103 }
104
105 Py_RETURN_NONE;
106}
107
108
Victor Stinnerc6b292c2020-06-08 16:30:33 +0200109static int
110check_popcount(uint32_t x, int expected)
111{
112 // Use volatile to prevent the compiler to optimize out the whole test
113 volatile uint32_t u = x;
114 int bits = _Py_popcount32(u);
115 if (bits != expected) {
116 PyErr_Format(PyExc_AssertionError,
117 "_Py_popcount32(%lu) returns %i, expected %i",
118 (unsigned long)x, bits, expected);
119 return -1;
120 }
121 return 0;
122}
123
124
125static PyObject*
126test_popcount(PyObject *self, PyObject *Py_UNUSED(args))
127{
128#define CHECK(X, RESULT) \
129 do { \
130 if (check_popcount(X, RESULT) < 0) { \
131 return NULL; \
132 } \
133 } while (0)
134
135 CHECK(0, 0);
136 CHECK(1, 1);
137 CHECK(0x08080808, 4);
138 CHECK(0x10101010, 4);
139 CHECK(0x10204080, 4);
140 CHECK(0xDEADCAFE, 22);
141 CHECK(0xFFFFFFFF, 32);
142 Py_RETURN_NONE;
143
144#undef CHECK
145}
146
147
Niklas Fiekas794e7d12020-06-15 14:33:48 +0200148static int
149check_bit_length(unsigned long x, int expected)
150{
151 // Use volatile to prevent the compiler to optimize out the whole test
152 volatile unsigned long u = x;
153 int len = _Py_bit_length(u);
154 if (len != expected) {
155 PyErr_Format(PyExc_AssertionError,
156 "_Py_bit_length(%lu) returns %i, expected %i",
157 x, len, expected);
158 return -1;
159 }
160 return 0;
161}
162
163
164static PyObject*
165test_bit_length(PyObject *self, PyObject *Py_UNUSED(args))
166{
167#define CHECK(X, RESULT) \
168 do { \
169 if (check_bit_length(X, RESULT) < 0) { \
170 return NULL; \
171 } \
172 } while (0)
173
174 CHECK(0, 0);
175 CHECK(1, 1);
176 CHECK(0x1000, 13);
177 CHECK(0x1234, 13);
178 CHECK(0x54321, 19);
179 CHECK(0x7FFFFFFF, 31);
180 CHECK(0xFFFFFFFF, 32);
181 Py_RETURN_NONE;
182
183#undef CHECK
184}
185
186
Victor Stinnera482dc52020-05-14 21:55:47 +0200187#define TO_PTR(ch) ((void*)(uintptr_t)ch)
188#define FROM_PTR(ptr) ((uintptr_t)ptr)
189#define VALUE(key) (1 + ((int)(key) - 'a'))
190
191static Py_uhash_t
192hash_char(const void *key)
193{
194 char ch = (char)FROM_PTR(key);
195 return ch;
196}
197
198
199static int
200hashtable_cb(_Py_hashtable_t *table,
201 const void *key_ptr, const void *value_ptr,
202 void *user_data)
203{
204 int *count = (int *)user_data;
205 char key = (char)FROM_PTR(key_ptr);
206 int value = (int)FROM_PTR(value_ptr);
207 assert(value == VALUE(key));
208 *count += 1;
209 return 0;
210}
211
212
213static PyObject*
214test_hashtable(PyObject *self, PyObject *Py_UNUSED(args))
215{
216 _Py_hashtable_t *table = _Py_hashtable_new(hash_char,
217 _Py_hashtable_compare_direct);
218 if (table == NULL) {
219 return PyErr_NoMemory();
220 }
221
Victor Stinnerd2dc8272020-05-14 22:44:32 +0200222 // Using an newly allocated table must not crash
223 assert(table->nentries == 0);
224 assert(table->nbuckets > 0);
225 assert(_Py_hashtable_get(table, TO_PTR('x')) == NULL);
226
Victor Stinnera482dc52020-05-14 21:55:47 +0200227 // Test _Py_hashtable_set()
228 char key;
229 for (key='a'; key <= 'z'; key++) {
230 int value = VALUE(key);
231 if (_Py_hashtable_set(table, TO_PTR(key), TO_PTR(value)) < 0) {
232 _Py_hashtable_destroy(table);
233 return PyErr_NoMemory();
234 }
235 }
236 assert(table->nentries == 26);
237 assert(table->nbuckets > table->nentries);
238
239 // Test _Py_hashtable_get_entry()
240 for (key='a'; key <= 'z'; key++) {
241 _Py_hashtable_entry_t *entry = _Py_hashtable_get_entry(table, TO_PTR(key));
242 assert(entry != NULL);
Christian Heimes4901ea92020-06-22 09:41:48 +0200243 assert(entry->key == TO_PTR(key));
244 assert(entry->value == TO_PTR(VALUE(key)));
Victor Stinnera482dc52020-05-14 21:55:47 +0200245 }
246
247 // Test _Py_hashtable_get()
248 for (key='a'; key <= 'z'; key++) {
249 void *value_ptr = _Py_hashtable_get(table, TO_PTR(key));
Victor Stinnerd2dc8272020-05-14 22:44:32 +0200250 assert((int)FROM_PTR(value_ptr) == VALUE(key));
Victor Stinnera482dc52020-05-14 21:55:47 +0200251 }
252
253 // Test _Py_hashtable_steal()
254 key = 'p';
255 void *value_ptr = _Py_hashtable_steal(table, TO_PTR(key));
Victor Stinnerd2dc8272020-05-14 22:44:32 +0200256 assert((int)FROM_PTR(value_ptr) == VALUE(key));
Victor Stinnera482dc52020-05-14 21:55:47 +0200257 assert(table->nentries == 25);
Victor Stinnerd2dc8272020-05-14 22:44:32 +0200258 assert(_Py_hashtable_get_entry(table, TO_PTR(key)) == NULL);
Victor Stinnera482dc52020-05-14 21:55:47 +0200259
260 // Test _Py_hashtable_foreach()
261 int count = 0;
262 int res = _Py_hashtable_foreach(table, hashtable_cb, &count);
263 assert(res == 0);
264 assert(count == 25);
265
266 // Test _Py_hashtable_clear()
267 _Py_hashtable_clear(table);
268 assert(table->nentries == 0);
Victor Stinnerd2dc8272020-05-14 22:44:32 +0200269 assert(table->nbuckets > 0);
Victor Stinnera482dc52020-05-14 21:55:47 +0200270 assert(_Py_hashtable_get(table, TO_PTR('x')) == NULL);
271
272 _Py_hashtable_destroy(table);
273 Py_RETURN_NONE;
274}
275
276
Victor Stinner23bace22019-04-18 11:37:26 +0200277static PyMethodDef TestMethods[] = {
278 {"get_configs", get_configs, METH_NOARGS},
Victor Stinner3f2f4fe2020-03-13 13:07:31 +0100279 {"get_recursion_depth", get_recursion_depth, METH_NOARGS},
Victor Stinner1ae035b2020-04-17 17:47:20 +0200280 {"test_bswap", test_bswap, METH_NOARGS},
Victor Stinnerc6b292c2020-06-08 16:30:33 +0200281 {"test_popcount", test_popcount, METH_NOARGS},
Niklas Fiekas794e7d12020-06-15 14:33:48 +0200282 {"test_bit_length", test_bit_length, METH_NOARGS},
Victor Stinnera482dc52020-05-14 21:55:47 +0200283 {"test_hashtable", test_hashtable, METH_NOARGS},
Victor Stinner23bace22019-04-18 11:37:26 +0200284 {NULL, NULL} /* sentinel */
285};
286
287
288static struct PyModuleDef _testcapimodule = {
289 PyModuleDef_HEAD_INIT,
290 "_testinternalcapi",
291 NULL,
292 -1,
293 TestMethods,
294 NULL,
295 NULL,
296 NULL,
297 NULL
298};
299
300
301PyMODINIT_FUNC
302PyInit__testinternalcapi(void)
303{
Victor Stinner01355982020-04-13 11:38:42 +0200304 PyObject *module = PyModule_Create(&_testcapimodule);
305 if (module == NULL) {
306 return NULL;
307 }
308
309 if (PyModule_AddObject(module, "SIZEOF_PYGC_HEAD",
310 PyLong_FromSsize_t(sizeof(PyGC_Head))) < 0) {
311 goto error;
312 }
313
314 return module;
315
316error:
317 Py_DECREF(module);
318 return NULL;
Victor Stinner23bace22019-04-18 11:37:26 +0200319}