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