LCOV - code coverage report
Current view: top level - Python - structmember.c (source / functions) Hit Total Coverage
Test: CPython lcov report Lines: 23 218 10.6 %
Date: 2017-04-19 Functions: 2 5 40.0 %

          Line data    Source code
       1             : 
       2             : /* Map C struct members to Python object attributes */
       3             : 
       4             : #include "Python.h"
       5             : 
       6             : #include "structmember.h"
       7             : 
       8             : static PyObject *
       9           0 : listmembers(struct memberlist *mlist)
      10             : {
      11             :     int i, n;
      12             :     PyObject *v;
      13           0 :     for (n = 0; mlist[n].name != NULL; n++)
      14             :         ;
      15           0 :     v = PyList_New(n);
      16           0 :     if (v != NULL) {
      17           0 :         for (i = 0; i < n; i++)
      18           0 :             PyList_SetItem(v, i,
      19           0 :                            PyString_FromString(mlist[i].name));
      20           0 :         if (PyErr_Occurred()) {
      21           0 :             Py_DECREF(v);
      22           0 :             v = NULL;
      23             :         }
      24             :         else {
      25           0 :             PyList_Sort(v);
      26             :         }
      27             :     }
      28           0 :     return v;
      29             : }
      30             : 
      31             : PyObject *
      32           0 : PyMember_Get(const char *addr, struct memberlist *mlist, const char *name)
      33             : {
      34             :     struct memberlist *l;
      35             : 
      36           0 :     if (strcmp(name, "__members__") == 0)
      37           0 :         return listmembers(mlist);
      38           0 :     for (l = mlist; l->name != NULL; l++) {
      39           0 :         if (strcmp(l->name, name) == 0) {
      40             :             PyMemberDef copy;
      41           0 :             copy.name = l->name;
      42           0 :             copy.type = l->type;
      43           0 :             copy.offset = l->offset;
      44           0 :             copy.flags = l->flags;
      45           0 :             copy.doc = NULL;
      46           0 :             return PyMember_GetOne(addr, &copy);
      47             :         }
      48             :     }
      49           0 :     PyErr_SetString(PyExc_AttributeError, name);
      50           0 :     return NULL;
      51             : }
      52             : 
      53             : PyObject *
      54        1035 : PyMember_GetOne(const char *addr, PyMemberDef *l)
      55             : {
      56             :     PyObject *v;
      57        1035 :     if ((l->flags & READ_RESTRICTED) &&
      58           0 :         PyEval_GetRestricted()) {
      59           0 :         PyErr_SetString(PyExc_RuntimeError, "restricted attribute");
      60           0 :         return NULL;
      61             :     }
      62        1035 :     addr += l->offset;
      63        1035 :     switch (l->type) {
      64             :     case T_BOOL:
      65           0 :         v = PyBool_FromLong(*(char*)addr);
      66           0 :         break;
      67             :     case T_BYTE:
      68           0 :         v = PyInt_FromLong(*(char*)addr);
      69           0 :         break;
      70             :     case T_UBYTE:
      71           0 :         v = PyLong_FromUnsignedLong(*(unsigned char*)addr);
      72           0 :         break;
      73             :     case T_SHORT:
      74           0 :         v = PyInt_FromLong(*(short*)addr);
      75           0 :         break;
      76             :     case T_USHORT:
      77           0 :         v = PyLong_FromUnsignedLong(*(unsigned short*)addr);
      78           0 :         break;
      79             :     case T_INT:
      80         846 :         v = PyInt_FromLong(*(int*)addr);
      81         846 :         break;
      82             :     case T_UINT:
      83           0 :         v = PyLong_FromUnsignedLong(*(unsigned int*)addr);
      84           0 :         break;
      85             :     case T_LONG:
      86           0 :         v = PyInt_FromLong(*(long*)addr);
      87           0 :         break;
      88             :     case T_ULONG:
      89           0 :         v = PyLong_FromUnsignedLong(*(unsigned long*)addr);
      90           0 :         break;
      91             :     case T_PYSSIZET:
      92           0 :         v = PyInt_FromSsize_t(*(Py_ssize_t*)addr);
      93           0 :         break;
      94             :     case T_FLOAT:
      95           0 :         v = PyFloat_FromDouble((double)*(float*)addr);
      96           0 :         break;
      97             :     case T_DOUBLE:
      98           0 :         v = PyFloat_FromDouble(*(double*)addr);
      99           0 :         break;
     100             :     case T_STRING:
     101           0 :         if (*(char**)addr == NULL) {
     102           0 :             Py_INCREF(Py_None);
     103           0 :             v = Py_None;
     104             :         }
     105             :         else
     106           0 :             v = PyString_FromString(*(char**)addr);
     107           0 :         break;
     108             :     case T_STRING_INPLACE:
     109           0 :         v = PyString_FromString((char*)addr);
     110           0 :         break;
     111             :     case T_CHAR:
     112           0 :         v = PyString_FromStringAndSize((char*)addr, 1);
     113           0 :         break;
     114             :     case T_OBJECT:
     115         189 :         v = *(PyObject **)addr;
     116         189 :         if (v == NULL)
     117           0 :             v = Py_None;
     118         189 :         Py_INCREF(v);
     119         189 :         break;
     120             :     case T_OBJECT_EX:
     121           0 :         v = *(PyObject **)addr;
     122           0 :         if (v == NULL)
     123           0 :             PyErr_SetString(PyExc_AttributeError, l->name);
     124           0 :         Py_XINCREF(v);
     125           0 :         break;
     126             : #ifdef HAVE_LONG_LONG
     127             :     case T_LONGLONG:
     128           0 :         v = PyLong_FromLongLong(*(PY_LONG_LONG *)addr);
     129           0 :         break;
     130             :     case T_ULONGLONG:
     131           0 :         v = PyLong_FromUnsignedLongLong(*(unsigned PY_LONG_LONG *)addr);
     132           0 :         break;
     133             : #endif /* HAVE_LONG_LONG */
     134             :     default:
     135           0 :         PyErr_SetString(PyExc_SystemError, "bad memberdescr type");
     136           0 :         v = NULL;
     137             :     }
     138        1035 :     return v;
     139             : }
     140             : 
     141             : int
     142           0 : PyMember_Set(char *addr, struct memberlist *mlist, const char *name, PyObject *v)
     143             : {
     144             :     struct memberlist *l;
     145             : 
     146           0 :     for (l = mlist; l->name != NULL; l++) {
     147           0 :         if (strcmp(l->name, name) == 0) {
     148             :             PyMemberDef copy;
     149           0 :             copy.name = l->name;
     150           0 :             copy.type = l->type;
     151           0 :             copy.offset = l->offset;
     152           0 :             copy.flags = l->flags;
     153           0 :             copy.doc = NULL;
     154           0 :             return PyMember_SetOne(addr, &copy, v);
     155             :         }
     156             :     }
     157             : 
     158           0 :     PyErr_SetString(PyExc_AttributeError, name);
     159           0 :     return -1;
     160             : }
     161             : 
     162             : #define WARN(msg)                                       \
     163             :     do {                                                \
     164             :     if (PyErr_Warn(PyExc_RuntimeWarning, msg) < 0)      \
     165             :         return -1;                                      \
     166             :     } while (0)
     167             : 
     168             : int
     169           9 : PyMember_SetOne(char *addr, PyMemberDef *l, PyObject *v)
     170             : {
     171             :     PyObject *oldv;
     172             : 
     173           9 :     addr += l->offset;
     174             : 
     175           9 :     if ((l->flags & READONLY))
     176             :     {
     177           0 :         PyErr_SetString(PyExc_TypeError, "readonly attribute");
     178           0 :         return -1;
     179             :     }
     180           9 :     if ((l->flags & PY_WRITE_RESTRICTED) && PyEval_GetRestricted()) {
     181           0 :         PyErr_SetString(PyExc_RuntimeError, "restricted attribute");
     182           0 :         return -1;
     183             :     }
     184           9 :     if (v == NULL) {
     185           0 :         if (l->type == T_OBJECT_EX) {
     186             :             /* Check if the attribute is set. */
     187           0 :             if (*(PyObject **)addr == NULL) {
     188           0 :                 PyErr_SetString(PyExc_AttributeError, l->name);
     189           0 :                 return -1;
     190             :             }
     191             :         }
     192           0 :         else if (l->type != T_OBJECT) {
     193           0 :             PyErr_SetString(PyExc_TypeError,
     194             :                             "can't delete numeric/char attribute");
     195           0 :             return -1;
     196             :         }
     197             :     }
     198           9 :     switch (l->type) {
     199             :     case T_BOOL:{
     200           0 :         if (!PyBool_Check(v)) {
     201           0 :             PyErr_SetString(PyExc_TypeError,
     202             :                             "attribute value type must be bool");
     203           0 :             return -1;
     204             :         }
     205           0 :         if (v == Py_True)
     206           0 :             *(char*)addr = (char) 1;
     207             :         else
     208           0 :             *(char*)addr = (char) 0;
     209           0 :         break;
     210             :         }
     211             :     case T_BYTE:{
     212           0 :         long long_val = PyInt_AsLong(v);
     213           0 :         if ((long_val == -1) && PyErr_Occurred())
     214           0 :             return -1;
     215           0 :         *(char*)addr = (char)long_val;
     216             :         /* XXX: For compatibility, only warn about truncations
     217             :            for now. */
     218           0 :         if ((long_val > CHAR_MAX) || (long_val < CHAR_MIN))
     219           0 :             WARN("Truncation of value to char");
     220           0 :         break;
     221             :         }
     222             :     case T_UBYTE:{
     223           0 :         long long_val = PyInt_AsLong(v);
     224           0 :         if ((long_val == -1) && PyErr_Occurred())
     225           0 :             return -1;
     226           0 :         *(unsigned char*)addr = (unsigned char)long_val;
     227           0 :         if ((long_val > UCHAR_MAX) || (long_val < 0))
     228           0 :             WARN("Truncation of value to unsigned char");
     229           0 :         break;
     230             :         }
     231             :     case T_SHORT:{
     232           0 :         long long_val = PyInt_AsLong(v);
     233           0 :         if ((long_val == -1) && PyErr_Occurred())
     234           0 :             return -1;
     235           0 :         *(short*)addr = (short)long_val;
     236           0 :         if ((long_val > SHRT_MAX) || (long_val < SHRT_MIN))
     237           0 :             WARN("Truncation of value to short");
     238           0 :         break;
     239             :         }
     240             :     case T_USHORT:{
     241           0 :         long long_val = PyInt_AsLong(v);
     242           0 :         if ((long_val == -1) && PyErr_Occurred())
     243           0 :             return -1;
     244           0 :         *(unsigned short*)addr = (unsigned short)long_val;
     245           0 :         if ((long_val > USHRT_MAX) || (long_val < 0))
     246           0 :             WARN("Truncation of value to unsigned short");
     247           0 :         break;
     248             :         }
     249             :     case T_INT:{
     250           0 :         long long_val = PyInt_AsLong(v);
     251           0 :         if ((long_val == -1) && PyErr_Occurred())
     252           0 :             return -1;
     253           0 :         *(int *)addr = (int)long_val;
     254           0 :         if ((long_val > INT_MAX) || (long_val < INT_MIN))
     255           0 :             WARN("Truncation of value to int");
     256           0 :         break;
     257             :         }
     258             :     case T_UINT:{
     259           0 :         unsigned long ulong_val = PyLong_AsUnsignedLong(v);
     260           0 :         if ((ulong_val == (unsigned long)-1) && PyErr_Occurred()) {
     261             :             /* XXX: For compatibility, accept negative int values
     262             :                as well. */
     263           0 :             PyErr_Clear();
     264           0 :             ulong_val = PyLong_AsLong(v);
     265           0 :             if ((ulong_val == (unsigned long)-1) &&
     266           0 :                 PyErr_Occurred())
     267           0 :                 return -1;
     268           0 :             *(unsigned int *)addr = (unsigned int)ulong_val;
     269           0 :             WARN("Writing negative value into unsigned field");
     270             :         } else
     271           0 :             *(unsigned int *)addr = (unsigned int)ulong_val;
     272           0 :         if (ulong_val > UINT_MAX)
     273           0 :             WARN("Truncation of value to unsigned int");
     274           0 :         break;
     275             :         }
     276             :     case T_LONG:{
     277           0 :         *(long*)addr = PyLong_AsLong(v);
     278           0 :         if ((*(long*)addr == -1) && PyErr_Occurred())
     279           0 :             return -1;
     280           0 :         break;
     281             :         }
     282             :     case T_ULONG:{
     283           0 :         *(unsigned long*)addr = PyLong_AsUnsignedLong(v);
     284           0 :         if ((*(unsigned long*)addr == (unsigned long)-1)
     285           0 :             && PyErr_Occurred()) {
     286             :             /* XXX: For compatibility, accept negative int values
     287             :                as well. */
     288           0 :             PyErr_Clear();
     289           0 :             *(unsigned long*)addr = PyLong_AsLong(v);
     290           0 :             if ((*(unsigned long*)addr == (unsigned long)-1)
     291           0 :                 && PyErr_Occurred())
     292           0 :                 return -1;
     293           0 :             WARN("Writing negative value into unsigned field");
     294             :         }
     295           0 :         break;
     296             :         }
     297             :     case T_PYSSIZET:{
     298           0 :         *(Py_ssize_t*)addr = PyInt_AsSsize_t(v);
     299           0 :         if ((*(Py_ssize_t*)addr == (Py_ssize_t)-1)
     300           0 :             && PyErr_Occurred())
     301           0 :                         return -1;
     302           0 :         break;
     303             :         }
     304             :     case T_FLOAT:{
     305           0 :         double double_val = PyFloat_AsDouble(v);
     306           0 :         if ((double_val == -1) && PyErr_Occurred())
     307           0 :             return -1;
     308           0 :         *(float*)addr = (float)double_val;
     309           0 :         break;
     310             :         }
     311             :     case T_DOUBLE:
     312           0 :         *(double*)addr = PyFloat_AsDouble(v);
     313           0 :         if ((*(double*)addr == -1) && PyErr_Occurred())
     314           0 :             return -1;
     315           0 :         break;
     316             :     case T_OBJECT:
     317             :     case T_OBJECT_EX:
     318           9 :         Py_XINCREF(v);
     319           9 :         oldv = *(PyObject **)addr;
     320           9 :         *(PyObject **)addr = v;
     321           9 :         Py_XDECREF(oldv);
     322           9 :         break;
     323             :     case T_CHAR:
     324           0 :         if (PyString_Check(v) && PyString_Size(v) == 1) {
     325           0 :             *(char*)addr = PyString_AsString(v)[0];
     326             :         }
     327             :         else {
     328           0 :             PyErr_BadArgument();
     329           0 :             return -1;
     330             :         }
     331           0 :         break;
     332             :     case T_STRING:
     333             :     case T_STRING_INPLACE:
     334           0 :         PyErr_SetString(PyExc_TypeError, "readonly attribute");
     335           0 :         return -1;
     336             : #ifdef HAVE_LONG_LONG
     337             :     case T_LONGLONG:{
     338             :         PY_LONG_LONG value;
     339           0 :         *(PY_LONG_LONG*)addr = value = PyLong_AsLongLong(v);
     340           0 :         if ((value == -1) && PyErr_Occurred())
     341           0 :             return -1;
     342           0 :         break;
     343             :         }
     344             :     case T_ULONGLONG:{
     345             :         unsigned PY_LONG_LONG value;
     346             :         /* ??? PyLong_AsLongLong accepts an int, but PyLong_AsUnsignedLongLong
     347             :             doesn't ??? */
     348           0 :         if (PyLong_Check(v))
     349           0 :             *(unsigned PY_LONG_LONG*)addr = value = PyLong_AsUnsignedLongLong(v);
     350             :         else
     351           0 :             *(unsigned PY_LONG_LONG*)addr = value = PyInt_AsLong(v);
     352           0 :         if ((value == (unsigned PY_LONG_LONG)-1) && PyErr_Occurred())
     353           0 :             return -1;
     354           0 :         break;
     355             :         }
     356             : #endif /* HAVE_LONG_LONG */
     357             :     default:
     358           0 :         PyErr_Format(PyExc_SystemError,
     359             :                      "bad memberdescr type for %s", l->name);
     360           0 :         return -1;
     361             :     }
     362           9 :     return 0;
     363             : }

Generated by: LCOV version 1.10