blob: be144bfba02665a5e261d37d62b3bfa056db5e22 [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 Stinner01355982020-04-13 11:38:42 +020016#include "pycore_gc.h" // PyGC_Head
Victor Stinnerf3cb8142020-11-05 18:12:33 +010017#include "pycore_hashtable.h" // _Py_hashtable_new()
18#include "pycore_initconfig.h" // _Py_GetConfigsAsDict()
19#include "pycore_interp.h" // _PyInterpreterState_GetConfigCopy()
Victor Stinner23bace22019-04-18 11:37:26 +020020
21
22static PyObject *
23get_configs(PyObject *self, PyObject *Py_UNUSED(args))
24{
Victor Stinner8f427482020-07-08 00:20:37 +020025 return _Py_GetConfigsAsDict();
Victor Stinner23bace22019-04-18 11:37:26 +020026}
27
28
Victor Stinner3f2f4fe2020-03-13 13:07:31 +010029static PyObject*
Victor Stinner1ae035b2020-04-17 17:47:20 +020030get_recursion_depth(PyObject *self, PyObject *Py_UNUSED(args))
Victor Stinner3f2f4fe2020-03-13 13:07:31 +010031{
32 PyThreadState *tstate = PyThreadState_Get();
33
34 /* subtract one to ignore the frame of the get_recursion_depth() call */
35 return PyLong_FromLong(tstate->recursion_depth - 1);
36}
37
38
Victor Stinner1ae035b2020-04-17 17:47:20 +020039static PyObject*
40test_bswap(PyObject *self, PyObject *Py_UNUSED(args))
41{
42 uint16_t u16 = _Py_bswap16(UINT16_C(0x3412));
43 if (u16 != UINT16_C(0x1234)) {
44 PyErr_Format(PyExc_AssertionError,
45 "_Py_bswap16(0x3412) returns %u", u16);
46 return NULL;
47 }
48
49 uint32_t u32 = _Py_bswap32(UINT32_C(0x78563412));
50 if (u32 != UINT32_C(0x12345678)) {
51 PyErr_Format(PyExc_AssertionError,
52 "_Py_bswap32(0x78563412) returns %lu", u32);
53 return NULL;
54 }
55
56 uint64_t u64 = _Py_bswap64(UINT64_C(0xEFCDAB9078563412));
57 if (u64 != UINT64_C(0x1234567890ABCDEF)) {
58 PyErr_Format(PyExc_AssertionError,
59 "_Py_bswap64(0xEFCDAB9078563412) returns %llu", u64);
60 return NULL;
61 }
62
63 Py_RETURN_NONE;
64}
65
66
Victor Stinnerc6b292c2020-06-08 16:30:33 +020067static int
68check_popcount(uint32_t x, int expected)
69{
70 // Use volatile to prevent the compiler to optimize out the whole test
71 volatile uint32_t u = x;
72 int bits = _Py_popcount32(u);
73 if (bits != expected) {
74 PyErr_Format(PyExc_AssertionError,
75 "_Py_popcount32(%lu) returns %i, expected %i",
76 (unsigned long)x, bits, expected);
77 return -1;
78 }
79 return 0;
80}
81
82
83static PyObject*
84test_popcount(PyObject *self, PyObject *Py_UNUSED(args))
85{
86#define CHECK(X, RESULT) \
87 do { \
88 if (check_popcount(X, RESULT) < 0) { \
89 return NULL; \
90 } \
91 } while (0)
92
93 CHECK(0, 0);
94 CHECK(1, 1);
95 CHECK(0x08080808, 4);
96 CHECK(0x10101010, 4);
97 CHECK(0x10204080, 4);
98 CHECK(0xDEADCAFE, 22);
99 CHECK(0xFFFFFFFF, 32);
100 Py_RETURN_NONE;
101
102#undef CHECK
103}
104
105
Niklas Fiekas794e7d12020-06-15 14:33:48 +0200106static int
107check_bit_length(unsigned long x, int expected)
108{
109 // Use volatile to prevent the compiler to optimize out the whole test
110 volatile unsigned long u = x;
111 int len = _Py_bit_length(u);
112 if (len != expected) {
113 PyErr_Format(PyExc_AssertionError,
114 "_Py_bit_length(%lu) returns %i, expected %i",
115 x, len, expected);
116 return -1;
117 }
118 return 0;
119}
120
121
122static PyObject*
123test_bit_length(PyObject *self, PyObject *Py_UNUSED(args))
124{
125#define CHECK(X, RESULT) \
126 do { \
127 if (check_bit_length(X, RESULT) < 0) { \
128 return NULL; \
129 } \
130 } while (0)
131
132 CHECK(0, 0);
133 CHECK(1, 1);
134 CHECK(0x1000, 13);
135 CHECK(0x1234, 13);
136 CHECK(0x54321, 19);
137 CHECK(0x7FFFFFFF, 31);
138 CHECK(0xFFFFFFFF, 32);
139 Py_RETURN_NONE;
140
141#undef CHECK
142}
143
144
Victor Stinnera482dc52020-05-14 21:55:47 +0200145#define TO_PTR(ch) ((void*)(uintptr_t)ch)
146#define FROM_PTR(ptr) ((uintptr_t)ptr)
147#define VALUE(key) (1 + ((int)(key) - 'a'))
148
149static Py_uhash_t
150hash_char(const void *key)
151{
152 char ch = (char)FROM_PTR(key);
153 return ch;
154}
155
156
157static int
158hashtable_cb(_Py_hashtable_t *table,
159 const void *key_ptr, const void *value_ptr,
160 void *user_data)
161{
162 int *count = (int *)user_data;
163 char key = (char)FROM_PTR(key_ptr);
164 int value = (int)FROM_PTR(value_ptr);
165 assert(value == VALUE(key));
166 *count += 1;
167 return 0;
168}
169
170
171static PyObject*
172test_hashtable(PyObject *self, PyObject *Py_UNUSED(args))
173{
174 _Py_hashtable_t *table = _Py_hashtable_new(hash_char,
175 _Py_hashtable_compare_direct);
176 if (table == NULL) {
177 return PyErr_NoMemory();
178 }
179
Victor Stinnerd2dc8272020-05-14 22:44:32 +0200180 // Using an newly allocated table must not crash
181 assert(table->nentries == 0);
182 assert(table->nbuckets > 0);
183 assert(_Py_hashtable_get(table, TO_PTR('x')) == NULL);
184
Victor Stinnera482dc52020-05-14 21:55:47 +0200185 // Test _Py_hashtable_set()
186 char key;
187 for (key='a'; key <= 'z'; key++) {
188 int value = VALUE(key);
189 if (_Py_hashtable_set(table, TO_PTR(key), TO_PTR(value)) < 0) {
190 _Py_hashtable_destroy(table);
191 return PyErr_NoMemory();
192 }
193 }
194 assert(table->nentries == 26);
195 assert(table->nbuckets > table->nentries);
196
197 // Test _Py_hashtable_get_entry()
198 for (key='a'; key <= 'z'; key++) {
199 _Py_hashtable_entry_t *entry = _Py_hashtable_get_entry(table, TO_PTR(key));
200 assert(entry != NULL);
Christian Heimes4901ea92020-06-22 09:41:48 +0200201 assert(entry->key == TO_PTR(key));
202 assert(entry->value == TO_PTR(VALUE(key)));
Victor Stinnera482dc52020-05-14 21:55:47 +0200203 }
204
205 // Test _Py_hashtable_get()
206 for (key='a'; key <= 'z'; key++) {
207 void *value_ptr = _Py_hashtable_get(table, TO_PTR(key));
Victor Stinnerd2dc8272020-05-14 22:44:32 +0200208 assert((int)FROM_PTR(value_ptr) == VALUE(key));
Victor Stinnera482dc52020-05-14 21:55:47 +0200209 }
210
211 // Test _Py_hashtable_steal()
212 key = 'p';
213 void *value_ptr = _Py_hashtable_steal(table, TO_PTR(key));
Victor Stinnerd2dc8272020-05-14 22:44:32 +0200214 assert((int)FROM_PTR(value_ptr) == VALUE(key));
Victor Stinnera482dc52020-05-14 21:55:47 +0200215 assert(table->nentries == 25);
Victor Stinnerd2dc8272020-05-14 22:44:32 +0200216 assert(_Py_hashtable_get_entry(table, TO_PTR(key)) == NULL);
Victor Stinnera482dc52020-05-14 21:55:47 +0200217
218 // Test _Py_hashtable_foreach()
219 int count = 0;
220 int res = _Py_hashtable_foreach(table, hashtable_cb, &count);
221 assert(res == 0);
222 assert(count == 25);
223
224 // Test _Py_hashtable_clear()
225 _Py_hashtable_clear(table);
226 assert(table->nentries == 0);
Victor Stinnerd2dc8272020-05-14 22:44:32 +0200227 assert(table->nbuckets > 0);
Victor Stinnera482dc52020-05-14 21:55:47 +0200228 assert(_Py_hashtable_get(table, TO_PTR('x')) == NULL);
229
230 _Py_hashtable_destroy(table);
231 Py_RETURN_NONE;
232}
233
234
Victor Stinnerf3cb8142020-11-05 18:12:33 +0100235static PyObject *
236test_get_config(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(args))
237{
238 PyConfig config;
239 PyConfig_InitIsolatedConfig(&config);
240 if (_PyInterpreterState_GetConfigCopy(&config) < 0) {
241 PyConfig_Clear(&config);
242 return NULL;
243 }
244 PyObject *dict = _PyConfig_AsDict(&config);
245 PyConfig_Clear(&config);
246 return dict;
247}
248
249
250static PyObject *
251test_set_config(PyObject *Py_UNUSED(self), PyObject *dict)
252{
253 PyConfig config;
254 PyConfig_InitIsolatedConfig(&config);
255 if (_PyConfig_FromDict(&config, dict) < 0) {
256 PyConfig_Clear(&config);
257 return NULL;
258 }
259 if (_PyInterpreterState_SetConfig(&config) < 0) {
260 return NULL;
261 }
262 PyConfig_Clear(&config);
263 Py_RETURN_NONE;
264}
265
266
Victor Stinner23bace22019-04-18 11:37:26 +0200267static PyMethodDef TestMethods[] = {
268 {"get_configs", get_configs, METH_NOARGS},
Victor Stinner3f2f4fe2020-03-13 13:07:31 +0100269 {"get_recursion_depth", get_recursion_depth, METH_NOARGS},
Victor Stinner1ae035b2020-04-17 17:47:20 +0200270 {"test_bswap", test_bswap, METH_NOARGS},
Victor Stinnerc6b292c2020-06-08 16:30:33 +0200271 {"test_popcount", test_popcount, METH_NOARGS},
Niklas Fiekas794e7d12020-06-15 14:33:48 +0200272 {"test_bit_length", test_bit_length, METH_NOARGS},
Victor Stinnera482dc52020-05-14 21:55:47 +0200273 {"test_hashtable", test_hashtable, METH_NOARGS},
Victor Stinnerf3cb8142020-11-05 18:12:33 +0100274 {"get_config", test_get_config, METH_NOARGS},
275 {"set_config", test_set_config, METH_O},
Victor Stinner23bace22019-04-18 11:37:26 +0200276 {NULL, NULL} /* sentinel */
277};
278
279
280static struct PyModuleDef _testcapimodule = {
281 PyModuleDef_HEAD_INIT,
282 "_testinternalcapi",
283 NULL,
284 -1,
285 TestMethods,
286 NULL,
287 NULL,
288 NULL,
289 NULL
290};
291
292
293PyMODINIT_FUNC
294PyInit__testinternalcapi(void)
295{
Victor Stinner01355982020-04-13 11:38:42 +0200296 PyObject *module = PyModule_Create(&_testcapimodule);
297 if (module == NULL) {
298 return NULL;
299 }
300
301 if (PyModule_AddObject(module, "SIZEOF_PYGC_HEAD",
302 PyLong_FromSsize_t(sizeof(PyGC_Head))) < 0) {
303 goto error;
304 }
305
306 return module;
307
308error:
309 Py_DECREF(module);
310 return NULL;
Victor Stinner23bace22019-04-18 11:37:26 +0200311}