LCOV - code coverage report
Current view: top level - Modules - _testinternalcapi.c (source / functions) Hit Total Coverage
Test: CPython 3.12 LCOV report [commit acb105a7c1f] Lines: 225 270 83.3 %
Date: 2022-07-20 13:12:14 Functions: 23 24 95.8 %
Branches: 92 172 53.5 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * C Extension module to test Python internal C APIs (Include/internal).
       3                 :            :  */
       4                 :            : 
       5                 :            : #ifndef Py_BUILD_CORE_BUILTIN
       6                 :            : #  define Py_BUILD_CORE_MODULE 1
       7                 :            : #endif
       8                 :            : 
       9                 :            : /* Always enable assertions */
      10                 :            : #undef NDEBUG
      11                 :            : 
      12                 :            : #define PY_SSIZE_T_CLEAN
      13                 :            : 
      14                 :            : #include "Python.h"
      15                 :            : #include "pycore_atomic_funcs.h" // _Py_atomic_int_get()
      16                 :            : #include "pycore_bitutils.h"     // _Py_bswap32()
      17                 :            : #include "pycore_fileutils.h"    // _Py_normpath
      18                 :            : #include "pycore_frame.h"        // _PyInterpreterFrame
      19                 :            : #include "pycore_gc.h"           // PyGC_Head
      20                 :            : #include "pycore_hashtable.h"    // _Py_hashtable_new()
      21                 :            : #include "pycore_initconfig.h"   // _Py_GetConfigsAsDict()
      22                 :            : #include "pycore_pathconfig.h"   // _PyPathConfig_ClearGlobal()
      23                 :            : #include "pycore_interp.h"       // _PyInterpreterState_GetConfigCopy()
      24                 :            : #include "pycore_pyerrors.h"     // _Py_UTF8_Edit_Cost()
      25                 :            : #include "pycore_pystate.h"      // _PyThreadState_GET()
      26                 :            : #include "osdefs.h"              // MAXPATHLEN
      27                 :            : 
      28                 :            : 
      29                 :            : static PyObject *
      30                 :         41 : get_configs(PyObject *self, PyObject *Py_UNUSED(args))
      31                 :            : {
      32                 :         41 :     return _Py_GetConfigsAsDict();
      33                 :            : }
      34                 :            : 
      35                 :            : 
      36                 :            : static PyObject*
      37                 :        423 : get_recursion_depth(PyObject *self, PyObject *Py_UNUSED(args))
      38                 :            : {
      39                 :        423 :     PyThreadState *tstate = _PyThreadState_GET();
      40                 :            : 
      41                 :            :     /* subtract one to ignore the frame of the get_recursion_depth() call */
      42                 :            : 
      43                 :        423 :     return PyLong_FromLong(tstate->recursion_limit - tstate->recursion_remaining - 1);
      44                 :            : }
      45                 :            : 
      46                 :            : 
      47                 :            : static PyObject*
      48                 :          1 : test_bswap(PyObject *self, PyObject *Py_UNUSED(args))
      49                 :            : {
      50                 :          1 :     uint16_t u16 = _Py_bswap16(UINT16_C(0x3412));
      51         [ -  + ]:          1 :     if (u16 != UINT16_C(0x1234)) {
      52                 :          0 :         PyErr_Format(PyExc_AssertionError,
      53                 :            :                      "_Py_bswap16(0x3412) returns %u", u16);
      54                 :          0 :         return NULL;
      55                 :            :     }
      56                 :            : 
      57                 :          1 :     uint32_t u32 = _Py_bswap32(UINT32_C(0x78563412));
      58         [ -  + ]:          1 :     if (u32 != UINT32_C(0x12345678)) {
      59                 :          0 :         PyErr_Format(PyExc_AssertionError,
      60                 :            :                      "_Py_bswap32(0x78563412) returns %lu", u32);
      61                 :          0 :         return NULL;
      62                 :            :     }
      63                 :            : 
      64                 :          1 :     uint64_t u64 = _Py_bswap64(UINT64_C(0xEFCDAB9078563412));
      65         [ -  + ]:          1 :     if (u64 != UINT64_C(0x1234567890ABCDEF)) {
      66                 :          0 :         PyErr_Format(PyExc_AssertionError,
      67                 :            :                      "_Py_bswap64(0xEFCDAB9078563412) returns %llu", u64);
      68                 :          0 :         return NULL;
      69                 :            :     }
      70                 :            : 
      71                 :          1 :     Py_RETURN_NONE;
      72                 :            : }
      73                 :            : 
      74                 :            : 
      75                 :            : static int
      76                 :          8 : check_popcount(uint32_t x, int expected)
      77                 :            : {
      78                 :            :     // Use volatile to prevent the compiler to optimize out the whole test
      79                 :          8 :     volatile uint32_t u = x;
      80                 :          8 :     int bits = _Py_popcount32(u);
      81         [ -  + ]:          8 :     if (bits != expected) {
      82                 :          0 :         PyErr_Format(PyExc_AssertionError,
      83                 :            :                      "_Py_popcount32(%lu) returns %i, expected %i",
      84                 :            :                      (unsigned long)x, bits, expected);
      85                 :          0 :         return -1;
      86                 :            :     }
      87                 :          8 :     return 0;
      88                 :            : }
      89                 :            : 
      90                 :            : 
      91                 :            : static PyObject*
      92                 :          1 : test_popcount(PyObject *self, PyObject *Py_UNUSED(args))
      93                 :            : {
      94                 :            : #define CHECK(X, RESULT) \
      95                 :            :     do { \
      96                 :            :         if (check_popcount(X, RESULT) < 0) { \
      97                 :            :             return NULL; \
      98                 :            :         } \
      99                 :            :     } while (0)
     100                 :            : 
     101         [ -  + ]:          1 :     CHECK(0, 0);
     102         [ -  + ]:          1 :     CHECK(1, 1);
     103         [ -  + ]:          1 :     CHECK(0x08080808, 4);
     104         [ -  + ]:          1 :     CHECK(0x10000001, 2);
     105         [ -  + ]:          1 :     CHECK(0x10101010, 4);
     106         [ -  + ]:          1 :     CHECK(0x10204080, 4);
     107         [ -  + ]:          1 :     CHECK(0xDEADCAFE, 22);
     108         [ -  + ]:          1 :     CHECK(0xFFFFFFFF, 32);
     109                 :          1 :     Py_RETURN_NONE;
     110                 :            : 
     111                 :            : #undef CHECK
     112                 :            : }
     113                 :            : 
     114                 :            : 
     115                 :            : static int
     116                 :          7 : check_bit_length(unsigned long x, int expected)
     117                 :            : {
     118                 :            :     // Use volatile to prevent the compiler to optimize out the whole test
     119                 :          7 :     volatile unsigned long u = x;
     120                 :          7 :     int len = _Py_bit_length(u);
     121         [ -  + ]:          7 :     if (len != expected) {
     122                 :          0 :         PyErr_Format(PyExc_AssertionError,
     123                 :            :                      "_Py_bit_length(%lu) returns %i, expected %i",
     124                 :            :                      x, len, expected);
     125                 :          0 :         return -1;
     126                 :            :     }
     127                 :          7 :     return 0;
     128                 :            : }
     129                 :            : 
     130                 :            : 
     131                 :            : static PyObject*
     132                 :          1 : test_bit_length(PyObject *self, PyObject *Py_UNUSED(args))
     133                 :            : {
     134                 :            : #define CHECK(X, RESULT) \
     135                 :            :     do { \
     136                 :            :         if (check_bit_length(X, RESULT) < 0) { \
     137                 :            :             return NULL; \
     138                 :            :         } \
     139                 :            :     } while (0)
     140                 :            : 
     141         [ -  + ]:          1 :     CHECK(0, 0);
     142         [ -  + ]:          1 :     CHECK(1, 1);
     143         [ -  + ]:          1 :     CHECK(0x1000, 13);
     144         [ -  + ]:          1 :     CHECK(0x1234, 13);
     145         [ -  + ]:          1 :     CHECK(0x54321, 19);
     146         [ -  + ]:          1 :     CHECK(0x7FFFFFFF, 31);
     147         [ -  + ]:          1 :     CHECK(0xFFFFFFFF, 32);
     148                 :          1 :     Py_RETURN_NONE;
     149                 :            : 
     150                 :            : #undef CHECK
     151                 :            : }
     152                 :            : 
     153                 :            : 
     154                 :            : #define TO_PTR(ch) ((void*)(uintptr_t)ch)
     155                 :            : #define FROM_PTR(ptr) ((uintptr_t)ptr)
     156                 :            : #define VALUE(key) (1 + ((int)(key) - 'a'))
     157                 :            : 
     158                 :            : static Py_uhash_t
     159                 :         82 : hash_char(const void *key)
     160                 :            : {
     161                 :         82 :     char ch = (char)FROM_PTR(key);
     162                 :         82 :     return ch;
     163                 :            : }
     164                 :            : 
     165                 :            : 
     166                 :            : static int
     167                 :         25 : hashtable_cb(_Py_hashtable_t *table,
     168                 :            :              const void *key_ptr, const void *value_ptr,
     169                 :            :              void *user_data)
     170                 :            : {
     171                 :         25 :     int *count = (int *)user_data;
     172                 :         25 :     char key = (char)FROM_PTR(key_ptr);
     173                 :         25 :     int value = (int)FROM_PTR(value_ptr);
     174         [ -  + ]:         25 :     assert(value == VALUE(key));
     175                 :         25 :     *count += 1;
     176                 :         25 :     return 0;
     177                 :            : }
     178                 :            : 
     179                 :            : 
     180                 :            : static PyObject*
     181                 :          1 : test_hashtable(PyObject *self, PyObject *Py_UNUSED(args))
     182                 :            : {
     183                 :          1 :     _Py_hashtable_t *table = _Py_hashtable_new(hash_char,
     184                 :            :                                                _Py_hashtable_compare_direct);
     185         [ -  + ]:          1 :     if (table == NULL) {
     186                 :            :         return PyErr_NoMemory();
     187                 :            :     }
     188                 :            : 
     189                 :            :     // Using an newly allocated table must not crash
     190         [ -  + ]:          1 :     assert(table->nentries == 0);
     191         [ -  + ]:          1 :     assert(table->nbuckets > 0);
     192         [ -  + ]:          1 :     assert(_Py_hashtable_get(table, TO_PTR('x')) == NULL);
     193                 :            : 
     194                 :            :     // Test _Py_hashtable_set()
     195                 :            :     char key;
     196         [ +  + ]:         27 :     for (key='a'; key <= 'z'; key++) {
     197                 :         26 :         int value = VALUE(key);
     198         [ -  + ]:         26 :         if (_Py_hashtable_set(table, TO_PTR(key), TO_PTR(value)) < 0) {
     199                 :          0 :             _Py_hashtable_destroy(table);
     200                 :            :             return PyErr_NoMemory();
     201                 :            :         }
     202                 :            :     }
     203         [ -  + ]:          1 :     assert(table->nentries == 26);
     204         [ -  + ]:          1 :     assert(table->nbuckets > table->nentries);
     205                 :            : 
     206                 :            :     // Test _Py_hashtable_get_entry()
     207         [ +  + ]:         27 :     for (key='a'; key <= 'z'; key++) {
     208                 :         26 :         _Py_hashtable_entry_t *entry = _Py_hashtable_get_entry(table, TO_PTR(key));
     209         [ -  + ]:         26 :         assert(entry != NULL);
     210         [ -  + ]:         26 :         assert(entry->key == TO_PTR(key));
     211         [ -  + ]:         26 :         assert(entry->value == TO_PTR(VALUE(key)));
     212                 :            :     }
     213                 :            : 
     214                 :            :     // Test _Py_hashtable_get()
     215         [ +  + ]:         27 :     for (key='a'; key <= 'z'; key++) {
     216                 :         26 :         void *value_ptr = _Py_hashtable_get(table, TO_PTR(key));
     217         [ -  + ]:         26 :         assert((int)FROM_PTR(value_ptr) == VALUE(key));
     218                 :            :     }
     219                 :            : 
     220                 :            :     // Test _Py_hashtable_steal()
     221                 :          1 :     key = 'p';
     222                 :          1 :     void *value_ptr = _Py_hashtable_steal(table, TO_PTR(key));
     223         [ -  + ]:          1 :     assert((int)FROM_PTR(value_ptr) == VALUE(key));
     224         [ -  + ]:          1 :     assert(table->nentries == 25);
     225         [ -  + ]:          1 :     assert(_Py_hashtable_get_entry(table, TO_PTR(key)) == NULL);
     226                 :            : 
     227                 :            :     // Test _Py_hashtable_foreach()
     228                 :          1 :     int count = 0;
     229                 :          1 :     int res = _Py_hashtable_foreach(table, hashtable_cb, &count);
     230         [ -  + ]:          1 :     assert(res == 0);
     231         [ -  + ]:          1 :     assert(count == 25);
     232                 :            : 
     233                 :            :     // Test _Py_hashtable_clear()
     234                 :          1 :     _Py_hashtable_clear(table);
     235         [ -  + ]:          1 :     assert(table->nentries == 0);
     236         [ -  + ]:          1 :     assert(table->nbuckets > 0);
     237         [ -  + ]:          1 :     assert(_Py_hashtable_get(table, TO_PTR('x')) == NULL);
     238                 :            : 
     239                 :          1 :     _Py_hashtable_destroy(table);
     240                 :          1 :     Py_RETURN_NONE;
     241                 :            : }
     242                 :            : 
     243                 :            : 
     244                 :            : static PyObject *
     245                 :         41 : test_get_config(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(args))
     246                 :            : {
     247                 :            :     PyConfig config;
     248                 :         41 :     PyConfig_InitIsolatedConfig(&config);
     249         [ -  + ]:         41 :     if (_PyInterpreterState_GetConfigCopy(&config) < 0) {
     250                 :          0 :         PyConfig_Clear(&config);
     251                 :          0 :         return NULL;
     252                 :            :     }
     253                 :         41 :     PyObject *dict = _PyConfig_AsDict(&config);
     254                 :         41 :     PyConfig_Clear(&config);
     255                 :         41 :     return dict;
     256                 :            : }
     257                 :            : 
     258                 :            : 
     259                 :            : static PyObject *
     260                 :        187 : test_set_config(PyObject *Py_UNUSED(self), PyObject *dict)
     261                 :            : {
     262                 :            :     PyConfig config;
     263                 :        187 :     PyConfig_InitIsolatedConfig(&config);
     264         [ +  + ]:        187 :     if (_PyConfig_FromDict(&config, dict) < 0) {
     265                 :        146 :         goto error;
     266                 :            :     }
     267         [ -  + ]:         41 :     if (_PyInterpreterState_SetConfig(&config) < 0) {
     268                 :          0 :         goto error;
     269                 :            :     }
     270                 :         41 :     PyConfig_Clear(&config);
     271                 :         41 :     Py_RETURN_NONE;
     272                 :            : 
     273                 :        146 : error:
     274                 :        146 :     PyConfig_Clear(&config);
     275                 :        146 :     return NULL;
     276                 :            : }
     277                 :            : 
     278                 :            : 
     279                 :            : static PyObject *
     280                 :          7 : test_reset_path_config(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(arg))
     281                 :            : {
     282                 :          7 :     _PyPathConfig_ClearGlobal();
     283                 :          7 :     Py_RETURN_NONE;
     284                 :            : }
     285                 :            : 
     286                 :            : 
     287                 :            : static PyObject*
     288                 :          1 : test_atomic_funcs(PyObject *self, PyObject *Py_UNUSED(args))
     289                 :            : {
     290                 :            :     // Test _Py_atomic_size_get() and _Py_atomic_size_set()
     291                 :          1 :     Py_ssize_t var = 1;
     292                 :          1 :     _Py_atomic_size_set(&var, 2);
     293         [ -  + ]:          1 :     assert(_Py_atomic_size_get(&var) == 2);
     294                 :          1 :     Py_RETURN_NONE;
     295                 :            : }
     296                 :            : 
     297                 :            : 
     298                 :            : static int
     299                 :         19 : check_edit_cost(const char *a, const char *b, Py_ssize_t expected)
     300                 :            : {
     301                 :         19 :     int ret = -1;
     302                 :         19 :     PyObject *a_obj = NULL;
     303                 :         19 :     PyObject *b_obj = NULL;
     304                 :            : 
     305                 :         19 :     a_obj = PyUnicode_FromString(a);
     306         [ -  + ]:         19 :     if (a_obj == NULL) {
     307                 :          0 :         goto exit;
     308                 :            :     }
     309                 :         19 :     b_obj = PyUnicode_FromString(b);
     310         [ -  + ]:         19 :     if (b_obj == NULL) {
     311                 :          0 :         goto exit;
     312                 :            :     }
     313                 :         19 :     Py_ssize_t result = _Py_UTF8_Edit_Cost(a_obj, b_obj, -1);
     314         [ -  + ]:         19 :     if (result != expected) {
     315                 :          0 :         PyErr_Format(PyExc_AssertionError,
     316                 :            :                      "Edit cost from '%s' to '%s' returns %zd, expected %zd",
     317                 :            :                      a, b, result, expected);
     318                 :          0 :         goto exit;
     319                 :            :     }
     320                 :            :     // Check that smaller max_edits thresholds are exceeded.
     321                 :         19 :     Py_ssize_t max_edits = result;
     322         [ +  + ]:         71 :     while (max_edits > 0) {
     323                 :         52 :         max_edits /= 2;
     324                 :         52 :         Py_ssize_t result2 = _Py_UTF8_Edit_Cost(a_obj, b_obj, max_edits);
     325         [ -  + ]:         52 :         if (result2 <= max_edits) {
     326                 :          0 :             PyErr_Format(PyExc_AssertionError,
     327                 :            :                          "Edit cost from '%s' to '%s' (threshold %zd) "
     328                 :            :                          "returns %zd, expected greater than %zd",
     329                 :            :                          a, b, max_edits, result2, max_edits);
     330                 :          0 :             goto exit;
     331                 :            :         }
     332                 :            :     }
     333                 :            :     // Check that bigger max_edits thresholds don't change anything
     334                 :         19 :     Py_ssize_t result3 = _Py_UTF8_Edit_Cost(a_obj, b_obj, result * 2 + 1);
     335         [ -  + ]:         19 :     if (result3 != result) {
     336                 :          0 :         PyErr_Format(PyExc_AssertionError,
     337                 :            :                      "Edit cost from '%s' to '%s' (threshold %zd) "
     338                 :            :                      "returns %zd, expected %zd",
     339                 :            :                      a, b, result * 2, result3, result);
     340                 :          0 :         goto exit;
     341                 :            :     }
     342                 :         19 :     ret = 0;
     343                 :         19 : exit:
     344                 :         19 :     Py_XDECREF(a_obj);
     345                 :         19 :     Py_XDECREF(b_obj);
     346                 :         19 :     return ret;
     347                 :            : }
     348                 :            : 
     349                 :            : static PyObject *
     350                 :          1 : test_edit_cost(PyObject *self, PyObject *Py_UNUSED(args))
     351                 :            : {
     352                 :            :     #define CHECK(a, b, n) do {              \
     353                 :            :         if (check_edit_cost(a, b, n) < 0) {  \
     354                 :            :             return NULL;                     \
     355                 :            :         }                                    \
     356                 :            :     } while (0)                              \
     357                 :            : 
     358         [ -  + ]:          1 :     CHECK("", "", 0);
     359         [ -  + ]:          1 :     CHECK("", "a", 2);
     360         [ -  + ]:          1 :     CHECK("a", "A", 1);
     361         [ -  + ]:          1 :     CHECK("Apple", "Aple", 2);
     362         [ -  + ]:          1 :     CHECK("Banana", "B@n@n@", 6);
     363         [ -  + ]:          1 :     CHECK("Cherry", "Cherry!", 2);
     364         [ -  + ]:          1 :     CHECK("---0---", "------", 2);
     365         [ -  + ]:          1 :     CHECK("abc", "y", 6);
     366         [ -  + ]:          1 :     CHECK("aa", "bb", 4);
     367         [ -  + ]:          1 :     CHECK("aaaaa", "AAAAA", 5);
     368         [ -  + ]:          1 :     CHECK("wxyz", "wXyZ", 2);
     369         [ -  + ]:          1 :     CHECK("wxyz", "wXyZ123", 8);
     370         [ -  + ]:          1 :     CHECK("Python", "Java", 12);
     371         [ -  + ]:          1 :     CHECK("Java", "C#", 8);
     372         [ -  + ]:          1 :     CHECK("AbstractFoobarManager", "abstract_foobar_manager", 3+2*2);
     373         [ -  + ]:          1 :     CHECK("CPython", "PyPy", 10);
     374         [ -  + ]:          1 :     CHECK("CPython", "pypy", 11);
     375         [ -  + ]:          1 :     CHECK("AttributeError", "AttributeErrop", 2);
     376         [ -  + ]:          1 :     CHECK("AttributeError", "AttributeErrorTests", 10);
     377                 :            : 
     378                 :            :     #undef CHECK
     379                 :          1 :     Py_RETURN_NONE;
     380                 :            : }
     381                 :            : 
     382                 :            : 
     383                 :            : static PyObject *
     384                 :         34 : normalize_path(PyObject *self, PyObject *filename)
     385                 :            : {
     386                 :         34 :     Py_ssize_t size = -1;
     387                 :         34 :     wchar_t *encoded = PyUnicode_AsWideCharString(filename, &size);
     388         [ -  + ]:         34 :     if (encoded == NULL) {
     389                 :          0 :         return NULL;
     390                 :            :     }
     391                 :            : 
     392                 :         34 :     PyObject *result = PyUnicode_FromWideChar(_Py_normpath(encoded, size), -1);
     393                 :         34 :     PyMem_Free(encoded);
     394                 :            : 
     395                 :         34 :     return result;
     396                 :            : }
     397                 :            : 
     398                 :            : static PyObject *
     399                 :          0 : get_getpath_codeobject(PyObject *self, PyObject *Py_UNUSED(args)) {
     400                 :          0 :     return _Py_Get_Getpath_CodeObject();
     401                 :            : }
     402                 :            : 
     403                 :            : 
     404                 :            : static PyObject *
     405                 :         12 : encode_locale_ex(PyObject *self, PyObject *args)
     406                 :            : {
     407                 :            :     PyObject *unicode;
     408                 :         12 :     int current_locale = 0;
     409                 :            :     wchar_t *wstr;
     410                 :         12 :     PyObject *res = NULL;
     411                 :         12 :     const char *errors = NULL;
     412                 :            : 
     413         [ -  + ]:         12 :     if (!PyArg_ParseTuple(args, "U|is", &unicode, &current_locale, &errors)) {
     414                 :          0 :         return NULL;
     415                 :            :     }
     416                 :         12 :     wstr = PyUnicode_AsWideCharString(unicode, NULL);
     417         [ -  + ]:         12 :     if (wstr == NULL) {
     418                 :          0 :         return NULL;
     419                 :            :     }
     420                 :         12 :     _Py_error_handler error_handler = _Py_GetErrorHandler(errors);
     421                 :            : 
     422                 :         12 :     char *str = NULL;
     423                 :            :     size_t error_pos;
     424                 :         12 :     const char *reason = NULL;
     425                 :         12 :     int ret = _Py_EncodeLocaleEx(wstr,
     426                 :            :                                  &str, &error_pos, &reason,
     427                 :            :                                  current_locale, error_handler);
     428                 :         12 :     PyMem_Free(wstr);
     429                 :            : 
     430   [ +  -  +  +  :         12 :     switch(ret) {
                      - ]
     431                 :          9 :     case 0:
     432                 :          9 :         res = PyBytes_FromString(str);
     433                 :          9 :         PyMem_RawFree(str);
     434                 :          9 :         break;
     435                 :          0 :     case -1:
     436                 :            :         PyErr_NoMemory();
     437                 :          0 :         break;
     438                 :          1 :     case -2:
     439                 :          1 :         PyErr_Format(PyExc_RuntimeError, "encode error: pos=%zu, reason=%s",
     440                 :            :                      error_pos, reason);
     441                 :          1 :         break;
     442                 :          2 :     case -3:
     443                 :          2 :         PyErr_SetString(PyExc_ValueError, "unsupported error handler");
     444                 :          2 :         break;
     445                 :          0 :     default:
     446                 :          0 :         PyErr_SetString(PyExc_ValueError, "unknown error code");
     447                 :          0 :         break;
     448                 :            :     }
     449                 :         12 :     return res;
     450                 :            : }
     451                 :            : 
     452                 :            : 
     453                 :            : static PyObject *
     454                 :         18 : decode_locale_ex(PyObject *self, PyObject *args)
     455                 :            : {
     456                 :            :     char *str;
     457                 :         18 :     int current_locale = 0;
     458                 :         18 :     PyObject *res = NULL;
     459                 :         18 :     const char *errors = NULL;
     460                 :            : 
     461         [ -  + ]:         18 :     if (!PyArg_ParseTuple(args, "y|is", &str, &current_locale, &errors)) {
     462                 :          0 :         return NULL;
     463                 :            :     }
     464                 :         18 :     _Py_error_handler error_handler = _Py_GetErrorHandler(errors);
     465                 :            : 
     466                 :         18 :     wchar_t *wstr = NULL;
     467                 :         18 :     size_t wlen = 0;
     468                 :         18 :     const char *reason = NULL;
     469                 :         18 :     int ret = _Py_DecodeLocaleEx(str,
     470                 :            :                                  &wstr, &wlen, &reason,
     471                 :            :                                  current_locale, error_handler);
     472                 :            : 
     473   [ +  -  +  +  :         18 :     switch(ret) {
                      - ]
     474                 :         12 :     case 0:
     475                 :         12 :         res = PyUnicode_FromWideChar(wstr, wlen);
     476                 :         12 :         PyMem_RawFree(wstr);
     477                 :         12 :         break;
     478                 :          0 :     case -1:
     479                 :            :         PyErr_NoMemory();
     480                 :          0 :         break;
     481                 :          4 :     case -2:
     482                 :          4 :         PyErr_Format(PyExc_RuntimeError, "decode error: pos=%zu, reason=%s",
     483                 :            :                      wlen, reason);
     484                 :          4 :         break;
     485                 :          2 :     case -3:
     486                 :          2 :         PyErr_SetString(PyExc_ValueError, "unsupported error handler");
     487                 :          2 :         break;
     488                 :          0 :     default:
     489                 :          0 :         PyErr_SetString(PyExc_ValueError, "unknown error code");
     490                 :          0 :         break;
     491                 :            :     }
     492                 :         18 :     return res;
     493                 :            : }
     494                 :            : 
     495                 :            : static PyObject *record_list = NULL;
     496                 :            : 
     497                 :            : static PyObject *
     498                 :          2 : set_eval_frame_default(PyObject *self, PyObject *Py_UNUSED(args))
     499                 :            : {
     500                 :          2 :     _PyInterpreterState_SetEvalFrameFunc(PyInterpreterState_Get(), _PyEval_EvalFrameDefault);
     501         [ +  - ]:          2 :     Py_CLEAR(record_list);
     502                 :          2 :     Py_RETURN_NONE;
     503                 :            : }
     504                 :            : 
     505                 :            : static PyObject *
     506                 :        200 : record_eval(PyThreadState *tstate, struct _PyInterpreterFrame *f, int exc)
     507                 :            : {
     508                 :        200 :     PyList_Append(record_list, f->f_func->func_name);
     509                 :        200 :     return _PyEval_EvalFrameDefault(tstate, f, exc);
     510                 :            : }
     511                 :            : 
     512                 :            : 
     513                 :            : static PyObject *
     514                 :          2 : set_eval_frame_record(PyObject *self, PyObject *list)
     515                 :            : {
     516         [ -  + ]:          2 :     if (!PyList_Check(list)) {
     517                 :          0 :         PyErr_SetString(PyExc_TypeError, "argument must be a list");
     518                 :          0 :         return NULL;
     519                 :            :     }
     520         [ -  + ]:          2 :     Py_CLEAR(record_list);
     521                 :          2 :     Py_INCREF(list);
     522                 :          2 :     record_list = list;
     523                 :          2 :     _PyInterpreterState_SetEvalFrameFunc(PyInterpreterState_Get(), record_eval);
     524                 :          2 :     Py_RETURN_NONE;
     525                 :            : }
     526                 :            : 
     527                 :            : 
     528                 :            : static PyMethodDef TestMethods[] = {
     529                 :            :     {"get_configs", get_configs, METH_NOARGS},
     530                 :            :     {"get_recursion_depth", get_recursion_depth, METH_NOARGS},
     531                 :            :     {"test_bswap", test_bswap, METH_NOARGS},
     532                 :            :     {"test_popcount", test_popcount, METH_NOARGS},
     533                 :            :     {"test_bit_length", test_bit_length, METH_NOARGS},
     534                 :            :     {"test_hashtable", test_hashtable, METH_NOARGS},
     535                 :            :     {"get_config", test_get_config, METH_NOARGS},
     536                 :            :     {"set_config", test_set_config, METH_O},
     537                 :            :     {"reset_path_config", test_reset_path_config, METH_NOARGS},
     538                 :            :     {"test_atomic_funcs", test_atomic_funcs, METH_NOARGS},
     539                 :            :     {"test_edit_cost", test_edit_cost, METH_NOARGS},
     540                 :            :     {"normalize_path", normalize_path, METH_O, NULL},
     541                 :            :     {"get_getpath_codeobject", get_getpath_codeobject, METH_NOARGS, NULL},
     542                 :            :     {"EncodeLocaleEx", encode_locale_ex, METH_VARARGS},
     543                 :            :     {"DecodeLocaleEx", decode_locale_ex, METH_VARARGS},
     544                 :            :     {"set_eval_frame_default", set_eval_frame_default, METH_NOARGS, NULL},
     545                 :            :     {"set_eval_frame_record", set_eval_frame_record, METH_O, NULL},
     546                 :            :     {NULL, NULL} /* sentinel */
     547                 :            : };
     548                 :            : 
     549                 :            : 
     550                 :            : static struct PyModuleDef _testcapimodule = {
     551                 :            :     PyModuleDef_HEAD_INIT,
     552                 :            :     "_testinternalcapi",
     553                 :            :     NULL,
     554                 :            :     -1,
     555                 :            :     TestMethods,
     556                 :            :     NULL,
     557                 :            :     NULL,
     558                 :            :     NULL,
     559                 :            :     NULL
     560                 :            : };
     561                 :            : 
     562                 :            : 
     563                 :            : PyMODINIT_FUNC
     564                 :         64 : PyInit__testinternalcapi(void)
     565                 :            : {
     566                 :         64 :     PyObject *module = PyModule_Create(&_testcapimodule);
     567         [ -  + ]:         64 :     if (module == NULL) {
     568                 :          0 :         return NULL;
     569                 :            :     }
     570                 :            : 
     571         [ -  + ]:         64 :     if (PyModule_AddObject(module, "SIZEOF_PYGC_HEAD",
     572                 :            :                            PyLong_FromSsize_t(sizeof(PyGC_Head))) < 0) {
     573                 :          0 :         goto error;
     574                 :            :     }
     575                 :            : 
     576                 :         64 :     return module;
     577                 :            : 
     578                 :          0 : error:
     579                 :          0 :     Py_DECREF(module);
     580                 :          0 :     return NULL;
     581                 :            : }

Generated by: LCOV version 1.14