blob: 4445d2e5c624a6053fe33514e02a23a1dff23c7b [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 Stinner1ae035b2020-04-17 17:47:20 +020015#include "pycore_byteswap.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
Miss Islington (bot)4981fe32020-07-06 09:52:13 -070021#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{
Miss Islington (bot)4981fe32020-07-06 09:52:13 -070059 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 Stinnera482dc52020-05-14 21:55:47 +0200109#define TO_PTR(ch) ((void*)(uintptr_t)ch)
110#define FROM_PTR(ptr) ((uintptr_t)ptr)
111#define VALUE(key) (1 + ((int)(key) - 'a'))
112
113static Py_uhash_t
114hash_char(const void *key)
115{
116 char ch = (char)FROM_PTR(key);
117 return ch;
118}
119
120
121static int
122hashtable_cb(_Py_hashtable_t *table,
123 const void *key_ptr, const void *value_ptr,
124 void *user_data)
125{
126 int *count = (int *)user_data;
127 char key = (char)FROM_PTR(key_ptr);
128 int value = (int)FROM_PTR(value_ptr);
129 assert(value == VALUE(key));
130 *count += 1;
131 return 0;
132}
133
134
135static PyObject*
136test_hashtable(PyObject *self, PyObject *Py_UNUSED(args))
137{
138 _Py_hashtable_t *table = _Py_hashtable_new(hash_char,
139 _Py_hashtable_compare_direct);
140 if (table == NULL) {
141 return PyErr_NoMemory();
142 }
143
Victor Stinnerd2dc8272020-05-14 22:44:32 +0200144 // Using an newly allocated table must not crash
145 assert(table->nentries == 0);
146 assert(table->nbuckets > 0);
147 assert(_Py_hashtable_get(table, TO_PTR('x')) == NULL);
148
Victor Stinnera482dc52020-05-14 21:55:47 +0200149 // Test _Py_hashtable_set()
150 char key;
151 for (key='a'; key <= 'z'; key++) {
152 int value = VALUE(key);
153 if (_Py_hashtable_set(table, TO_PTR(key), TO_PTR(value)) < 0) {
154 _Py_hashtable_destroy(table);
155 return PyErr_NoMemory();
156 }
157 }
158 assert(table->nentries == 26);
159 assert(table->nbuckets > table->nentries);
160
161 // Test _Py_hashtable_get_entry()
162 for (key='a'; key <= 'z'; key++) {
163 _Py_hashtable_entry_t *entry = _Py_hashtable_get_entry(table, TO_PTR(key));
164 assert(entry != NULL);
Miss Islington (bot)f19ed6b2020-06-22 01:01:48 -0700165 assert(entry->key == TO_PTR(key));
166 assert(entry->value == TO_PTR(VALUE(key)));
Victor Stinnera482dc52020-05-14 21:55:47 +0200167 }
168
169 // Test _Py_hashtable_get()
170 for (key='a'; key <= 'z'; key++) {
171 void *value_ptr = _Py_hashtable_get(table, TO_PTR(key));
Victor Stinnerd2dc8272020-05-14 22:44:32 +0200172 assert((int)FROM_PTR(value_ptr) == VALUE(key));
Victor Stinnera482dc52020-05-14 21:55:47 +0200173 }
174
175 // Test _Py_hashtable_steal()
176 key = 'p';
177 void *value_ptr = _Py_hashtable_steal(table, TO_PTR(key));
Victor Stinnerd2dc8272020-05-14 22:44:32 +0200178 assert((int)FROM_PTR(value_ptr) == VALUE(key));
Victor Stinnera482dc52020-05-14 21:55:47 +0200179 assert(table->nentries == 25);
Victor Stinnerd2dc8272020-05-14 22:44:32 +0200180 assert(_Py_hashtable_get_entry(table, TO_PTR(key)) == NULL);
Victor Stinnera482dc52020-05-14 21:55:47 +0200181
182 // Test _Py_hashtable_foreach()
183 int count = 0;
184 int res = _Py_hashtable_foreach(table, hashtable_cb, &count);
185 assert(res == 0);
186 assert(count == 25);
187
188 // Test _Py_hashtable_clear()
189 _Py_hashtable_clear(table);
190 assert(table->nentries == 0);
Victor Stinnerd2dc8272020-05-14 22:44:32 +0200191 assert(table->nbuckets > 0);
Victor Stinnera482dc52020-05-14 21:55:47 +0200192 assert(_Py_hashtable_get(table, TO_PTR('x')) == NULL);
193
194 _Py_hashtable_destroy(table);
195 Py_RETURN_NONE;
196}
197
198
Victor Stinner23bace22019-04-18 11:37:26 +0200199static PyMethodDef TestMethods[] = {
200 {"get_configs", get_configs, METH_NOARGS},
Victor Stinner3f2f4fe2020-03-13 13:07:31 +0100201 {"get_recursion_depth", get_recursion_depth, METH_NOARGS},
Victor Stinner1ae035b2020-04-17 17:47:20 +0200202 {"test_bswap", test_bswap, METH_NOARGS},
Victor Stinnera482dc52020-05-14 21:55:47 +0200203 {"test_hashtable", test_hashtable, METH_NOARGS},
Victor Stinner23bace22019-04-18 11:37:26 +0200204 {NULL, NULL} /* sentinel */
205};
206
207
208static struct PyModuleDef _testcapimodule = {
209 PyModuleDef_HEAD_INIT,
210 "_testinternalcapi",
211 NULL,
212 -1,
213 TestMethods,
214 NULL,
215 NULL,
216 NULL,
217 NULL
218};
219
220
221PyMODINIT_FUNC
222PyInit__testinternalcapi(void)
223{
Victor Stinner01355982020-04-13 11:38:42 +0200224 PyObject *module = PyModule_Create(&_testcapimodule);
225 if (module == NULL) {
226 return NULL;
227 }
228
229 if (PyModule_AddObject(module, "SIZEOF_PYGC_HEAD",
230 PyLong_FromSsize_t(sizeof(PyGC_Head))) < 0) {
231 goto error;
232 }
233
234 return module;
235
236error:
237 Py_DECREF(module);
238 return NULL;
Victor Stinner23bace22019-04-18 11:37:26 +0200239}