LCOV - code coverage report
Current view: top level - Python - structmember.c (source / functions) Hit Total Coverage
Test: CPython 3.12 LCOV report [commit 5e6661bce9] Lines: 42 217 19.4 %
Date: 2023-03-20 08:15:36 Functions: 2 2 100.0 %
Branches: 14 163 8.6 %

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

Generated by: LCOV version 1.14