Coverage Report

Created: 2025-07-11 06:59

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