LCOV - code coverage report
Current view: top level - Python - structmember.c (source / functions) Hit Total Coverage
Test: CPython lcov report Lines: 181 220 82.3 %
Date: 2022-07-07 18:19:46 Functions: 2 2 100.0 %

          Line data    Source code
       1             : 
       2             : /* Map C struct members to Python object attributes */
       3             : 
       4             : #include "Python.h"
       5             : #include "structmember.h"         // PyMemberDef
       6             : 
       7             : PyObject *
       8    12153300 : PyMember_GetOne(const char *obj_addr, PyMemberDef *l)
       9             : {
      10             :     PyObject *v;
      11             : 
      12    12153300 :     const char* addr = obj_addr + l->offset;
      13    12153300 :     switch (l->type) {
      14       48466 :     case T_BOOL:
      15       48466 :         v = PyBool_FromLong(*(char*)addr);
      16       48466 :         break;
      17           2 :     case T_BYTE:
      18           2 :         v = PyLong_FromLong(*(char*)addr);
      19           2 :         break;
      20           1 :     case T_UBYTE:
      21           1 :         v = PyLong_FromUnsignedLong(*(unsigned char*)addr);
      22           1 :         break;
      23           2 :     case T_SHORT:
      24           2 :         v = PyLong_FromLong(*(short*)addr);
      25           2 :         break;
      26           1 :     case T_USHORT:
      27           1 :         v = PyLong_FromUnsignedLong(*(unsigned short*)addr);
      28           1 :         break;
      29       68448 :     case T_INT:
      30       68448 :         v = PyLong_FromLong(*(int*)addr);
      31       68448 :         break;
      32      314764 :     case T_UINT:
      33      314764 :         v = PyLong_FromUnsignedLong(*(unsigned int*)addr);
      34      314764 :         break;
      35          14 :     case T_LONG:
      36          14 :         v = PyLong_FromLong(*(long*)addr);
      37          14 :         break;
      38       16663 :     case T_ULONG:
      39       16663 :         v = PyLong_FromUnsignedLong(*(unsigned long*)addr);
      40       16663 :         break;
      41        1010 :     case T_PYSSIZET:
      42        1010 :         v = PyLong_FromSsize_t(*(Py_ssize_t*)addr);
      43        1010 :         break;
      44           0 :     case T_FLOAT:
      45           0 :         v = PyFloat_FromDouble((double)*(float*)addr);
      46           0 :         break;
      47      254852 :     case T_DOUBLE:
      48      254852 :         v = PyFloat_FromDouble(*(double*)addr);
      49      254852 :         break;
      50       13074 :     case T_STRING:
      51       13074 :         if (*(char**)addr == NULL) {
      52        1629 :             Py_INCREF(Py_None);
      53        1629 :             v = Py_None;
      54             :         }
      55             :         else
      56       11445 :             v = PyUnicode_FromString(*(char**)addr);
      57       13074 :         break;
      58           1 :     case T_STRING_INPLACE:
      59           1 :         v = PyUnicode_FromString((char*)addr);
      60           1 :         break;
      61           0 :     case T_CHAR:
      62           0 :         v = PyUnicode_FromStringAndSize((char*)addr, 1);
      63           0 :         break;
      64    10833100 :     case T_OBJECT:
      65    10833100 :         v = *(PyObject **)addr;
      66    10833100 :         if (v == NULL)
      67        2402 :             v = Py_None;
      68    10833100 :         Py_INCREF(v);
      69    10833100 :         break;
      70      602920 :     case T_OBJECT_EX:
      71      602920 :         v = *(PyObject **)addr;
      72      602920 :         if (v == NULL) {
      73       84373 :             PyObject *obj = (PyObject *)obj_addr;
      74       84373 :             PyTypeObject *tp = Py_TYPE(obj);
      75       84373 :             PyErr_Format(PyExc_AttributeError,
      76             :                          "'%.200s' object has no attribute '%s'",
      77             :                          tp->tp_name, l->name);
      78             :        }
      79      602920 :         Py_XINCREF(v);
      80      602920 :         break;
      81           5 :     case T_LONGLONG:
      82           5 :         v = PyLong_FromLongLong(*(long long *)addr);
      83           5 :         break;
      84           2 :     case T_ULONGLONG:
      85           2 :         v = PyLong_FromUnsignedLongLong(*(unsigned long long *)addr);
      86           2 :         break;
      87           0 :     case T_NONE:
      88           0 :         v = Py_None;
      89           0 :         Py_INCREF(v);
      90           0 :         break;
      91           0 :     default:
      92           0 :         PyErr_SetString(PyExc_SystemError, "bad memberdescr type");
      93           0 :         v = NULL;
      94             :     }
      95    12153300 :     return v;
      96             : }
      97             : 
      98             : #define WARN(msg)                                               \
      99             :     do {                                                        \
     100             :     if (PyErr_WarnEx(PyExc_RuntimeWarning, msg, 1) < 0)         \
     101             :         return -1;                                              \
     102             :     } while (0)
     103             : 
     104             : int
     105     3815840 : PyMember_SetOne(char *addr, PyMemberDef *l, PyObject *v)
     106             : {
     107             :     PyObject *oldv;
     108             : 
     109     3815840 :     addr += l->offset;
     110             : 
     111     3815840 :     if ((l->flags & READONLY))
     112             :     {
     113         110 :         PyErr_SetString(PyExc_AttributeError, "readonly attribute");
     114         110 :         return -1;
     115             :     }
     116     3815730 :     if (v == NULL) {
     117         223 :         if (l->type == T_OBJECT_EX) {
     118             :             /* Check if the attribute is set. */
     119         213 :             if (*(PyObject **)addr == NULL) {
     120           2 :                 PyErr_SetString(PyExc_AttributeError, l->name);
     121           2 :                 return -1;
     122             :             }
     123             :         }
     124          10 :         else if (l->type != T_OBJECT) {
     125           1 :             PyErr_SetString(PyExc_TypeError,
     126             :                             "can't delete numeric/char attribute");
     127           1 :             return -1;
     128             :         }
     129             :     }
     130     3815730 :     switch (l->type) {
     131       22327 :     case T_BOOL:{
     132       22327 :         if (!PyBool_Check(v)) {
     133           6 :             PyErr_SetString(PyExc_TypeError,
     134             :                             "attribute value type must be bool");
     135           6 :             return -1;
     136             :         }
     137       22321 :         if (v == Py_True)
     138       22102 :             *(char*)addr = (char) 1;
     139             :         else
     140         219 :             *(char*)addr = (char) 0;
     141       22321 :         break;
     142             :         }
     143           9 :     case T_BYTE:{
     144           9 :         long long_val = PyLong_AsLong(v);
     145           9 :         if ((long_val == -1) && PyErr_Occurred())
     146           5 :             return -1;
     147           4 :         *(char*)addr = (char)long_val;
     148             :         /* XXX: For compatibility, only warn about truncations
     149             :            for now. */
     150           4 :         if ((long_val > CHAR_MAX) || (long_val < CHAR_MIN))
     151           2 :             WARN("Truncation of value to char");
     152           4 :         break;
     153             :         }
     154           7 :     case T_UBYTE:{
     155           7 :         long long_val = PyLong_AsLong(v);
     156           7 :         if ((long_val == -1) && PyErr_Occurred())
     157           5 :             return -1;
     158           2 :         *(unsigned char*)addr = (unsigned char)long_val;
     159           2 :         if ((long_val > UCHAR_MAX) || (long_val < 0))
     160           1 :             WARN("Truncation of value to unsigned char");
     161           2 :         break;
     162             :         }
     163           9 :     case T_SHORT:{
     164           9 :         long long_val = PyLong_AsLong(v);
     165           9 :         if ((long_val == -1) && PyErr_Occurred())
     166           5 :             return -1;
     167           4 :         *(short*)addr = (short)long_val;
     168           4 :         if ((long_val > SHRT_MAX) || (long_val < SHRT_MIN))
     169           2 :             WARN("Truncation of value to short");
     170           4 :         break;
     171             :         }
     172           7 :     case T_USHORT:{
     173           7 :         long long_val = PyLong_AsLong(v);
     174           7 :         if ((long_val == -1) && PyErr_Occurred())
     175           5 :             return -1;
     176           2 :         *(unsigned short*)addr = (unsigned short)long_val;
     177           2 :         if ((long_val > USHRT_MAX) || (long_val < 0))
     178           1 :             WARN("Truncation of value to unsigned short");
     179           2 :         break;
     180             :         }
     181          12 :     case T_INT:{
     182          12 :         long long_val = PyLong_AsLong(v);
     183          12 :         if ((long_val == -1) && PyErr_Occurred())
     184           5 :             return -1;
     185           7 :         *(int *)addr = (int)long_val;
     186           7 :         if ((long_val > INT_MAX) || (long_val < INT_MIN))
     187           0 :             WARN("Truncation of value to int");
     188           7 :         break;
     189             :         }
     190           6 :     case T_UINT:{
     191           6 :         unsigned long ulong_val = PyLong_AsUnsignedLong(v);
     192           6 :         if ((ulong_val == (unsigned long)-1) && PyErr_Occurred()) {
     193             :             /* XXX: For compatibility, accept negative int values
     194             :                as well. */
     195           5 :             PyErr_Clear();
     196           5 :             ulong_val = PyLong_AsLong(v);
     197          10 :             if ((ulong_val == (unsigned long)-1) &&
     198           5 :                 PyErr_Occurred())
     199           5 :                 return -1;
     200           0 :             *(unsigned int *)addr = (unsigned int)ulong_val;
     201           0 :             WARN("Writing negative value into unsigned field");
     202             :         } else
     203           1 :             *(unsigned int *)addr = (unsigned int)ulong_val;
     204           1 :         if (ulong_val > UINT_MAX)
     205           0 :             WARN("Truncation of value to unsigned int");
     206           1 :         break;
     207             :         }
     208           7 :     case T_LONG:{
     209           7 :         *(long*)addr = PyLong_AsLong(v);
     210           7 :         if ((*(long*)addr == -1) && PyErr_Occurred())
     211           5 :             return -1;
     212           2 :         break;
     213             :         }
     214           6 :     case T_ULONG:{
     215           6 :         *(unsigned long*)addr = PyLong_AsUnsignedLong(v);
     216           6 :         if ((*(unsigned long*)addr == (unsigned long)-1)
     217           6 :             && PyErr_Occurred()) {
     218             :             /* XXX: For compatibility, accept negative int values
     219             :                as well. */
     220           5 :             PyErr_Clear();
     221           5 :             *(unsigned long*)addr = PyLong_AsLong(v);
     222           5 :             if ((*(unsigned long*)addr == (unsigned long)-1)
     223           5 :                 && PyErr_Occurred())
     224           5 :                 return -1;
     225           0 :             WARN("Writing negative value into unsigned field");
     226             :         }
     227           1 :         break;
     228             :         }
     229          16 :     case T_PYSSIZET:{
     230          16 :         *(Py_ssize_t*)addr = PyLong_AsSsize_t(v);
     231          16 :         if ((*(Py_ssize_t*)addr == (Py_ssize_t)-1)
     232           5 :             && PyErr_Occurred())
     233           5 :                         return -1;
     234          11 :         break;
     235             :         }
     236           0 :     case T_FLOAT:{
     237           0 :         double double_val = PyFloat_AsDouble(v);
     238           0 :         if ((double_val == -1) && PyErr_Occurred())
     239           0 :             return -1;
     240           0 :         *(float*)addr = (float)double_val;
     241           0 :         break;
     242             :         }
     243           0 :     case T_DOUBLE:
     244           0 :         *(double*)addr = PyFloat_AsDouble(v);
     245           0 :         if ((*(double*)addr == -1) && PyErr_Occurred())
     246           0 :             return -1;
     247           0 :         break;
     248     3793310 :     case T_OBJECT:
     249             :     case T_OBJECT_EX:
     250     3793310 :         Py_XINCREF(v);
     251     3793310 :         oldv = *(PyObject **)addr;
     252     3793310 :         *(PyObject **)addr = v;
     253     3793310 :         Py_XDECREF(oldv);
     254     3793310 :         break;
     255           0 :     case T_CHAR: {
     256             :         const char *string;
     257             :         Py_ssize_t len;
     258             : 
     259           0 :         string = PyUnicode_AsUTF8AndSize(v, &len);
     260           0 :         if (string == NULL || len != 1) {
     261           0 :             PyErr_BadArgument();
     262           0 :             return -1;
     263             :         }
     264           0 :         *(char*)addr = string[0];
     265           0 :         break;
     266             :         }
     267           1 :     case T_STRING:
     268             :     case T_STRING_INPLACE:
     269           1 :         PyErr_SetString(PyExc_TypeError, "readonly attribute");
     270           1 :         return -1;
     271           8 :     case T_LONGLONG:{
     272             :         long long value;
     273           8 :         *(long long*)addr = value = PyLong_AsLongLong(v);
     274           8 :         if ((value == -1) && PyErr_Occurred())
     275           5 :             return -1;
     276           3 :         break;
     277             :         }
     278           7 :     case T_ULONGLONG:{
     279             :         unsigned long long value;
     280             :         /* ??? PyLong_AsLongLong accepts an int, but PyLong_AsUnsignedLongLong
     281             :             doesn't ??? */
     282           7 :         if (PyLong_Check(v))
     283           2 :             *(unsigned long long*)addr = value = PyLong_AsUnsignedLongLong(v);
     284             :         else
     285           5 :             *(unsigned long long*)addr = value = PyLong_AsLong(v);
     286           7 :         if ((value == (unsigned long long)-1) && PyErr_Occurred())
     287           5 :             return -1;
     288           2 :         break;
     289             :         }
     290           0 :     default:
     291           0 :         PyErr_Format(PyExc_SystemError,
     292             :                      "bad memberdescr type for %s", l->name);
     293           0 :         return -1;
     294             :     }
     295     3815670 :     return 0;
     296             : }

Generated by: LCOV version 1.14