blob: 6d5af5917f1f07a93e85545463765b6eec776956 [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
Victor Stinnera482dc52020-05-14 21:55:47 +0200105#define TO_PTR(ch) ((void*)(uintptr_t)ch)
106#define FROM_PTR(ptr) ((uintptr_t)ptr)
107#define VALUE(key) (1 + ((int)(key) - 'a'))
108
109static Py_uhash_t
110hash_char(const void *key)
111{
112 char ch = (char)FROM_PTR(key);
113 return ch;
114}
115
116
117static int
118hashtable_cb(_Py_hashtable_t *table,
119 const void *key_ptr, const void *value_ptr,
120 void *user_data)
121{
122 int *count = (int *)user_data;
123 char key = (char)FROM_PTR(key_ptr);
124 int value = (int)FROM_PTR(value_ptr);
125 assert(value == VALUE(key));
126 *count += 1;
127 return 0;
128}
129
130
131static PyObject*
132test_hashtable(PyObject *self, PyObject *Py_UNUSED(args))
133{
134 _Py_hashtable_t *table = _Py_hashtable_new(hash_char,
135 _Py_hashtable_compare_direct);
136 if (table == NULL) {
137 return PyErr_NoMemory();
138 }
139
Victor Stinnerd2dc8272020-05-14 22:44:32 +0200140 // Using an newly allocated table must not crash
141 assert(table->nentries == 0);
142 assert(table->nbuckets > 0);
143 assert(_Py_hashtable_get(table, TO_PTR('x')) == NULL);
144
Victor Stinnera482dc52020-05-14 21:55:47 +0200145 // Test _Py_hashtable_set()
146 char key;
147 for (key='a'; key <= 'z'; key++) {
148 int value = VALUE(key);
149 if (_Py_hashtable_set(table, TO_PTR(key), TO_PTR(value)) < 0) {
150 _Py_hashtable_destroy(table);
151 return PyErr_NoMemory();
152 }
153 }
154 assert(table->nentries == 26);
155 assert(table->nbuckets > table->nentries);
156
157 // Test _Py_hashtable_get_entry()
158 for (key='a'; key <= 'z'; key++) {
159 _Py_hashtable_entry_t *entry = _Py_hashtable_get_entry(table, TO_PTR(key));
160 assert(entry != NULL);
161 assert(entry->key = TO_PTR(key));
162 assert(entry->value = TO_PTR(VALUE(key)));
163 }
164
165 // Test _Py_hashtable_get()
166 for (key='a'; key <= 'z'; key++) {
167 void *value_ptr = _Py_hashtable_get(table, TO_PTR(key));
Victor Stinnerd2dc8272020-05-14 22:44:32 +0200168 assert((int)FROM_PTR(value_ptr) == VALUE(key));
Victor Stinnera482dc52020-05-14 21:55:47 +0200169 }
170
171 // Test _Py_hashtable_steal()
172 key = 'p';
173 void *value_ptr = _Py_hashtable_steal(table, TO_PTR(key));
Victor Stinnerd2dc8272020-05-14 22:44:32 +0200174 assert((int)FROM_PTR(value_ptr) == VALUE(key));
Victor Stinnera482dc52020-05-14 21:55:47 +0200175 assert(table->nentries == 25);
Victor Stinnerd2dc8272020-05-14 22:44:32 +0200176 assert(_Py_hashtable_get_entry(table, TO_PTR(key)) == NULL);
Victor Stinnera482dc52020-05-14 21:55:47 +0200177
178 // Test _Py_hashtable_foreach()
179 int count = 0;
180 int res = _Py_hashtable_foreach(table, hashtable_cb, &count);
181 assert(res == 0);
182 assert(count == 25);
183
184 // Test _Py_hashtable_clear()
185 _Py_hashtable_clear(table);
186 assert(table->nentries == 0);
Victor Stinnerd2dc8272020-05-14 22:44:32 +0200187 assert(table->nbuckets > 0);
Victor Stinnera482dc52020-05-14 21:55:47 +0200188 assert(_Py_hashtable_get(table, TO_PTR('x')) == NULL);
189
190 _Py_hashtable_destroy(table);
191 Py_RETURN_NONE;
192}
193
194
Victor Stinner23bace22019-04-18 11:37:26 +0200195static PyMethodDef TestMethods[] = {
196 {"get_configs", get_configs, METH_NOARGS},
Victor Stinner3f2f4fe2020-03-13 13:07:31 +0100197 {"get_recursion_depth", get_recursion_depth, METH_NOARGS},
Victor Stinner1ae035b2020-04-17 17:47:20 +0200198 {"test_bswap", test_bswap, METH_NOARGS},
Victor Stinnerc6b292c2020-06-08 16:30:33 +0200199 {"test_popcount", test_popcount, METH_NOARGS},
Victor Stinnera482dc52020-05-14 21:55:47 +0200200 {"test_hashtable", test_hashtable, METH_NOARGS},
Victor Stinner23bace22019-04-18 11:37:26 +0200201 {NULL, NULL} /* sentinel */
202};
203
204
205static struct PyModuleDef _testcapimodule = {
206 PyModuleDef_HEAD_INIT,
207 "_testinternalcapi",
208 NULL,
209 -1,
210 TestMethods,
211 NULL,
212 NULL,
213 NULL,
214 NULL
215};
216
217
218PyMODINIT_FUNC
219PyInit__testinternalcapi(void)
220{
Victor Stinner01355982020-04-13 11:38:42 +0200221 PyObject *module = PyModule_Create(&_testcapimodule);
222 if (module == NULL) {
223 return NULL;
224 }
225
226 if (PyModule_AddObject(module, "SIZEOF_PYGC_HEAD",
227 PyLong_FromSsize_t(sizeof(PyGC_Head))) < 0) {
228 goto error;
229 }
230
231 return module;
232
233error:
234 Py_DECREF(module);
235 return NULL;
Victor Stinner23bace22019-04-18 11:37:26 +0200236}