LCOV - code coverage report
Current view: top level - Python - structmember.c (source / functions) Hit Total Coverage
Test: CPython 3.12 LCOV report [commit acb105a7c1f] Lines: 181 220 82.3 %
Date: 2022-07-20 13:12:14 Functions: 2 2 100.0 %
Branches: 112 163 68.7 %

           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                 :   10244498 : PyMember_GetOne(const char *obj_addr, PyMemberDef *l)
       9                 :            : {
      10                 :            :     PyObject *v;
      11                 :            : 
      12                 :   10244498 :     const char* addr = obj_addr + l->offset;
      13   [ +  +  +  +  :   10244498 :     switch (l->type) {
          +  +  +  +  +  
          +  -  +  +  +  
          -  +  +  +  +  
                   -  - ]
      14                 :      48500 :     case T_BOOL:
      15                 :      48500 :         v = PyBool_FromLong(*(char*)addr);
      16                 :      48500 :         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                 :      66492 :     case T_INT:
      30                 :      66492 :         v = PyLong_FromLong(*(int*)addr);
      31                 :      66492 :         break;
      32                 :     296127 :     case T_UINT:
      33                 :     296127 :         v = PyLong_FromUnsignedLong(*(unsigned int*)addr);
      34                 :     296127 :         break;
      35                 :         15 :     case T_LONG:
      36                 :         15 :         v = PyLong_FromLong(*(long*)addr);
      37                 :         15 :         break;
      38                 :      16179 :     case T_ULONG:
      39                 :      16179 :         v = PyLong_FromUnsignedLong(*(unsigned long*)addr);
      40                 :      16179 :         break;
      41                 :       1011 :     case T_PYSSIZET:
      42                 :       1011 :         v = PyLong_FromSsize_t(*(Py_ssize_t*)addr);
      43                 :       1011 :         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                 :      12949 :     case T_STRING:
      51         [ +  + ]:      12949 :         if (*(char**)addr == NULL) {
      52                 :       1619 :             Py_INCREF(Py_None);
      53                 :       1619 :             v = Py_None;
      54                 :            :         }
      55                 :            :         else
      56                 :      11330 :             v = PyUnicode_FromString(*(char**)addr);
      57                 :      12949 :         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                 :    8944254 :     case T_OBJECT:
      65                 :    8944254 :         v = *(PyObject **)addr;
      66         [ +  + ]:    8944254 :         if (v == NULL)
      67                 :       2401 :             v = Py_None;
      68                 :    8944254 :         Py_INCREF(v);
      69                 :    8944254 :         break;
      70                 :     604105 :     case T_OBJECT_EX:
      71                 :     604105 :         v = *(PyObject **)addr;
      72         [ +  + ]:     604105 :         if (v == NULL) {
      73                 :      83886 :             PyObject *obj = (PyObject *)obj_addr;
      74                 :      83886 :             PyTypeObject *tp = Py_TYPE(obj);
      75                 :      83886 :             PyErr_Format(PyExc_AttributeError,
      76                 :            :                          "'%.200s' object has no attribute '%s'",
      77                 :            :                          tp->tp_name, l->name);
      78                 :            :        }
      79                 :     604105 :         Py_XINCREF(v);
      80                 :     604105 :         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                 :   10244498 :     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                 :    3646564 : PyMember_SetOne(char *addr, PyMemberDef *l, PyObject *v)
     106                 :            : {
     107                 :            :     PyObject *oldv;
     108                 :            : 
     109                 :    3646564 :     addr += l->offset;
     110                 :            : 
     111         [ +  + ]:    3646564 :     if ((l->flags & READONLY))
     112                 :            :     {
     113                 :        110 :         PyErr_SetString(PyExc_AttributeError, "readonly attribute");
     114                 :        110 :         return -1;
     115                 :            :     }
     116         [ +  + ]:    3646454 :     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   [ +  +  +  +  :    3646451 :     switch (l->type) {
          +  +  +  +  +  
          +  -  -  +  -  
             +  +  +  - ]
     131                 :      22358 :     case T_BOOL:{
     132         [ +  + ]:      22358 :         if (!PyBool_Check(v)) {
     133                 :          6 :             PyErr_SetString(PyExc_TypeError,
     134                 :            :                             "attribute value type must be bool");
     135                 :          6 :             return -1;
     136                 :            :         }
     137         [ +  + ]:      22352 :         if (v == Py_True)
     138                 :      22131 :             *(char*)addr = (char) 1;
     139                 :            :         else
     140                 :        221 :             *(char*)addr = (char) 0;
     141                 :      22352 :         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                 :    3623998 :     case T_OBJECT:
     249                 :            :     case T_OBJECT_EX:
     250                 :    3623998 :         Py_XINCREF(v);
     251                 :    3623998 :         oldv = *(PyObject **)addr;
     252                 :    3623998 :         *(PyObject **)addr = v;
     253                 :    3623998 :         Py_XDECREF(oldv);
     254                 :    3623998 :         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                 :    3646389 :     return 0;
     296                 :            : }

Generated by: LCOV version 1.14