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