Coverage Report

Created: 2022-07-08 09:39

/home/mdboom/Work/builds/cpython/Python/structmember.c
Line
Count
Source (jump to first uncovered line)
1
2
/* Map C struct members to Python object attributes */
3
4
#include "Python.h"
5
#include "structmember.h"         // PyMemberDef
6
7
PyObject *
8
PyMember_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:
  Branch (14:5): [True: 41.3k, False: 3.91M]
15
        v = PyBool_FromLong(*(char*)addr);
16
        break;
17
    case T_BYTE:
  Branch (17:5): [True: 2, False: 3.95M]
18
        v = PyLong_FromLong(*(char*)addr);
19
        break;
20
    case T_UBYTE:
  Branch (20:5): [True: 1, False: 3.95M]
21
        v = PyLong_FromUnsignedLong(*(unsigned char*)addr);
22
        break;
23
    case T_SHORT:
  Branch (23:5): [True: 2, False: 3.95M]
24
        v = PyLong_FromLong(*(short*)addr);
25
        break;
26
    case T_USHORT:
  Branch (26:5): [True: 1, False: 3.95M]
27
        v = PyLong_FromUnsignedLong(*(unsigned short*)addr);
28
        break;
29
    case T_INT:
  Branch (29:5): [True: 55.4k, False: 3.90M]
30
        v = PyLong_FromLong(*(int*)addr);
31
        break;
32
    case T_UINT:
  Branch (32:5): [True: 79.7k, False: 3.87M]
33
        v = PyLong_FromUnsignedLong(*(unsigned int*)addr);
34
        break;
35
    case T_LONG:
  Branch (35:5): [True: 15, False: 3.95M]
36
        v = PyLong_FromLong(*(long*)addr);
37
        break;
38
    case T_ULONG:
  Branch (38:5): [True: 14.7k, False: 3.94M]
39
        v = PyLong_FromUnsignedLong(*(unsigned long*)addr);
40
        break;
41
    case T_PYSSIZET:
  Branch (41:5): [True: 863, False: 3.95M]
42
        v = PyLong_FromSsize_t(*(Py_ssize_t*)addr);
43
        break;
44
    case T_FLOAT:
  Branch (44:5): [True: 0, False: 3.95M]
45
        v = PyFloat_FromDouble((double)*(float*)addr);
46
        break;
47
    case T_DOUBLE:
  Branch (47:5): [True: 254k, False: 3.70M]
48
        v = PyFloat_FromDouble(*(double*)addr);
49
        break;
50
    case T_STRING:
  Branch (50:5): [True: 10.3k, False: 3.94M]
51
        if (*(char**)addr == NULL) {
  Branch (51:13): [True: 1.35k, False: 9.03k]
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:
  Branch (58:5): [True: 1, False: 3.95M]
59
        v = PyUnicode_FromString((char*)addr);
60
        break;
61
    case T_CHAR:
  Branch (61:5): [True: 0, False: 3.95M]
62
        v = PyUnicode_FromStringAndSize((char*)addr, 1);
63
        break;
64
    case T_OBJECT:
  Branch (64:5): [True: 3.19M, False: 768k]
65
        v = *(PyObject **)addr;
66
        if (v == NULL)
  Branch (66:13): [True: 2.27k, False: 3.18M]
67
            v = Py_None;
68
        Py_INCREF(v);
69
        break;
70
    case T_OBJECT_EX:
  Branch (70:5): [True: 310k, False: 3.64M]
71
        v = *(PyObject **)addr;
72
        if (v == NULL) {
  Branch (72:13): [True: 68.7k, False: 242k]
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:
  Branch (81:5): [True: 5, False: 3.95M]
82
        v = PyLong_FromLongLong(*(long long *)addr);
83
        break;
84
    case T_ULONGLONG:
  Branch (84:5): [True: 2, False: 3.95M]
85
        v = PyLong_FromUnsignedLongLong(*(unsigned long long *)addr);
86
        break;
87
    case T_NONE:
  Branch (87:5): [True: 0, False: 3.95M]
88
        v = Py_None;
89
        Py_INCREF(v);
90
        break;
91
    default:
  Branch (91:5): [True: 0, False: 3.95M]
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 -10
; \
102
    } while (0)
103
104
int
105
PyMember_SetOne(char *addr, PyMemberDef *l, PyObject *v)
106
{
107
    PyObject *oldv;
108
109
    addr += l->offset;
110
111
    if ((l->flags & READONLY))
  Branch (111:9): [True: 110, False: 1.05M]
112
    {
113
        PyErr_SetString(PyExc_AttributeError, "readonly attribute");
114
        return -1;
115
    }
116
    if (v == NULL) {
  Branch (116:9): [True: 191, False: 1.05M]
117
        if (l->type == T_OBJECT_EX) {
  Branch (117:13): [True: 181, False: 10]
118
            /* Check if the attribute is set. */
119
            if (*(PyObject **)addr == NULL) {
  Branch (119:17): [True: 2, False: 179]
120
                PyErr_SetString(PyExc_AttributeError, l->name);
121
                return -1;
122
            }
123
        }
124
        else if (l->type != T_OBJECT) {
  Branch (124:18): [True: 1, False: 9]
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:{
  Branch (131:5): [True: 13.8k, False: 1.03M]
132
        if (!PyBool_Check(v)) {
  Branch (132:13): [True: 6, False: 13.8k]
133
            PyErr_SetString(PyExc_TypeError,
134
                            "attribute value type must be bool");
135
            return -1;
136
        }
137
        if (v == Py_True)
  Branch (137:13): [True: 13.6k, False: 219]
138
            *(char*)addr = (char) 1;
139
        else
140
            *(char*)addr = (char) 0;
141
        break;
142
        }
143
    case T_BYTE:{
  Branch (143:5): [True: 9, False: 1.05M]
144
        long long_val = PyLong_AsLong(v);
145
        if ((long_val == -1) && 
PyErr_Occurred()5
)
  Branch (145:13): [True: 5, False: 4]
  Branch (145:33): [True: 5, False: 0]
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)3
)
  Branch (150:13): [True: 1, False: 3]
  Branch (150:38): [True: 1, False: 2]
151
            WARN("Truncation of value to char");
152
        break;
153
        }
154
    case T_UBYTE:{
  Branch (154:5): [True: 7, False: 1.05M]
155
        long long_val = PyLong_AsLong(v);
156
        if ((long_val == -1) && 
PyErr_Occurred()5
)
  Branch (156:13): [True: 5, False: 2]
  Branch (156:33): [True: 5, False: 0]
157
            return -1;
158
        *(unsigned char*)addr = (unsigned char)long_val;
159
        if ((long_val > UCHAR_MAX) || 
(long_val < 0)1
)
  Branch (159:13): [True: 1, False: 1]
  Branch (159:39): [True: 0, False: 1]
160
            WARN("Truncation of value to unsigned char");
161
        break;
162
        }
163
    case T_SHORT:{
  Branch (163:5): [True: 9, False: 1.05M]
164
        long long_val = PyLong_AsLong(v);
165
        if ((long_val == -1) && 
PyErr_Occurred()5
)
  Branch (165:13): [True: 5, False: 4]
  Branch (165:33): [True: 5, False: 0]
166
            return -1;
167
        *(short*)addr = (short)long_val;
168
        if ((long_val > SHRT_MAX) || 
(long_val < SHRT_MIN)3
)
  Branch (168:13): [True: 1, False: 3]
  Branch (168:38): [True: 1, False: 2]
169
            WARN("Truncation of value to short");
170
        break;
171
        }
172
    case T_USHORT:{
  Branch (172:5): [True: 7, False: 1.05M]
173
        long long_val = PyLong_AsLong(v);
174
        if ((long_val == -1) && 
PyErr_Occurred()5
)
  Branch (174:13): [True: 5, False: 2]
  Branch (174:33): [True: 5, False: 0]
175
            return -1;
176
        *(unsigned short*)addr = (unsigned short)long_val;
177
        if ((long_val > USHRT_MAX) || 
(long_val < 0)1
)
  Branch (177:13): [True: 1, False: 1]
  Branch (177:39): [True: 0, False: 1]
178
            WARN("Truncation of value to unsigned short");
179
        break;
180
        }
181
    case T_INT:{
  Branch (181:5): [True: 12, False: 1.05M]
182
        long long_val = PyLong_AsLong(v);
183
        if ((long_val == -1) && 
PyErr_Occurred()5
)
  Branch (183:13): [True: 5, False: 7]
  Branch (183:33): [True: 5, False: 0]
184
            return -1;
185
        *(int *)addr = (int)long_val;
186
        if ((long_val > INT_MAX) || (long_val < INT_MIN))
  Branch (186:13): [True: 0, False: 7]
  Branch (186:37): [True: 0, False: 7]
187
            WARN("Truncation of value to int");
188
        break;
189
        }
190
    
case 6
T_UINT6
:{
  Branch (190:5): [True: 6, False: 1.05M]
191
        unsigned long ulong_val = PyLong_AsUnsignedLong(v);
192
        if ((ulong_val == (unsigned long)-1) && 
PyErr_Occurred()5
) {
  Branch (192:13): [True: 5, False: 1]
  Branch (192:49): [True: 5, False: 0]
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) &&
  Branch (197:17): [True: 5, False: 0]
198
                PyErr_Occurred())
  Branch (198:17): [True: 5, False: 0]
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)
  Branch (204:13): [True: 0, False: 1]
205
            WARN("Truncation of value to unsigned int");
206
        break;
207
        }
208
    case T_LONG:{
  Branch (208:5): [True: 7, False: 1.05M]
209
        *(long*)addr = PyLong_AsLong(v);
210
        if ((*(long*)addr == -1) && 
PyErr_Occurred()5
)
  Branch (210:13): [True: 5, False: 2]
  Branch (210:37): [True: 5, False: 0]
211
            return -1;
212
        break;
213
        }
214
    case T_ULONG:{
  Branch (214:5): [True: 6, False: 1.05M]
215
        *(unsigned long*)addr = PyLong_AsUnsignedLong(v);
216
        if ((*(unsigned long*)addr == (unsigned long)-1)
  Branch (216:13): [True: 6, False: 0]
217
            && PyErr_Occurred()) {
  Branch (217:16): [True: 5, False: 1]
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)
  Branch (222:17): [True: 5, False: 0]
223
                && PyErr_Occurred())
  Branch (223:20): [True: 5, False: 0]
224
                return -1;
225
            WARN("Writing negative value into unsigned field");
226
        }
227
        break;
228
        }
229
    case T_PYSSIZET:{
  Branch (229:5): [True: 16, False: 1.05M]
230
        *(Py_ssize_t*)addr = PyLong_AsSsize_t(v);
231
        if ((*(Py_ssize_t*)addr == (Py_ssize_t)-1)
  Branch (231:13): [True: 5, False: 11]
232
            && 
PyErr_Occurred()5
)
  Branch (232:16): [True: 5, False: 0]
233
                        return -1;
234
        break;
235
        }
236
    
case 0
T_FLOAT0
:{
  Branch (236:5): [True: 0, False: 1.05M]
237
        double double_val = PyFloat_AsDouble(v);
238
        if ((double_val == -1) && PyErr_Occurred())
  Branch (238:13): [True: 0, False: 0]
  Branch (238:35): [True: 0, False: 0]
239
            return -1;
240
        *(float*)addr = (float)double_val;
241
        break;
242
        }
243
    case T_DOUBLE:
  Branch (243:5): [True: 0, False: 1.05M]
244
        *(double*)addr = PyFloat_AsDouble(v);
245
        if ((*(double*)addr == -1) && PyErr_Occurred())
  Branch (245:13): [True: 0, False: 0]
  Branch (245:39): [True: 0, False: 0]
246
            return -1;
247
        break;
248
    case T_OBJECT:
  Branch (248:5): [True: 830k, False: 220k]
249
    case T_OBJECT_EX:
  Branch (249:5): [True: 206k, False: 844k]
250
        Py_XINCREF(v);
251
        oldv = *(PyObject **)addr;
252
        *(PyObject **)addr = v;
253
        Py_XDECREF(oldv);
254
        break;
255
    case T_CHAR: {
  Branch (255:5): [True: 0, False: 1.05M]
256
        const char *string;
257
        Py_ssize_t len;
258
259
        string = PyUnicode_AsUTF8AndSize(v, &len);
260
        if (string == NULL || len != 1) {
  Branch (260:13): [True: 0, False: 0]
  Branch (260:31): [True: 0, False: 0]
261
            PyErr_BadArgument();
262
            return -1;
263
        }
264
        *(char*)addr = string[0];
265
        break;
266
        }
267
    case T_STRING:
  Branch (267:5): [True: 0, False: 1.05M]
268
    case T_STRING_INPLACE:
  Branch (268:5): [True: 1, False: 1.05M]
269
        PyErr_SetString(PyExc_TypeError, "readonly attribute");
270
        return -1;
271
    case T_LONGLONG:{
  Branch (271:5): [True: 8, False: 1.05M]
272
        long long value;
273
        *(long long*)addr = value = PyLong_AsLongLong(v);
274
        if ((value == -1) && 
PyErr_Occurred()5
)
  Branch (274:13): [True: 5, False: 3]
  Branch (274:30): [True: 5, False: 0]
275
            return -1;
276
        break;
277
        }
278
    case T_ULONGLONG:{
  Branch (278:5): [True: 7, False: 1.05M]
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()6
)
  Branch (286:13): [True: 6, False: 1]
  Branch (286:50): [True: 5, False: 1]
287
            return -1;
288
        break;
289
        }
290
    default:
  Branch (290:5): [True: 0, False: 1.05M]
291
        PyErr_Format(PyExc_SystemError,
292
                     "bad memberdescr type for %s", l->name);
293
        return -1;
294
    }
295
    return 0;
296
}