[3.6] bpo-30416: Protect the optimizer during constant folding. (#4865) · python/cpython@b580f4f (original) (raw)
`@@ -167,6 +167,37 @@ copy_op_arg(_Py_CODEUNIT *codestr, Py_ssize_t i, unsigned char op,
`
167
167
`return maxi - 1;
`
168
168
`}
`
169
169
``
``
170
`+
/* Check whether a collection doesn't containing too much items (including
`
``
171
`+
subcollections). This protects from creating a constant that needs
`
``
172
`+
too much time for calculating a hash.
`
``
173
`+
"limit" is the maximal number of items.
`
``
174
`+
Returns the negative number if the total number of items exceeds the
`
``
175
`+
limit. Otherwise returns the limit minus the total number of items.
`
``
176
`+
*/
`
``
177
+
``
178
`+
static Py_ssize_t
`
``
179
`+
check_complexity(PyObject *obj, Py_ssize_t limit)
`
``
180
`+
{
`
``
181
`+
if (PyTuple_Check(obj)) {
`
``
182
`+
Py_ssize_t i;
`
``
183
`+
limit -= PyTuple_GET_SIZE(obj);
`
``
184
`+
for (i = 0; limit >= 0 && i < PyTuple_GET_SIZE(obj); i++) {
`
``
185
`+
limit = check_complexity(PyTuple_GET_ITEM(obj, i), limit);
`
``
186
`+
}
`
``
187
`+
return limit;
`
``
188
`+
}
`
``
189
`+
else if (PyFrozenSet_Check(obj)) {
`
``
190
`+
Py_ssize_t i = 0;
`
``
191
`+
PyObject *item;
`
``
192
`+
Py_hash_t hash;
`
``
193
`+
limit -= PySet_GET_SIZE(obj);
`
``
194
`+
while (limit >= 0 && _PySet_NextEntry(obj, &i, &item, &hash)) {
`
``
195
`+
limit = check_complexity(item, limit);
`
``
196
`+
}
`
``
197
`+
}
`
``
198
`+
return limit;
`
``
199
`+
}
`
``
200
+
170
201
`/* Replace LOAD_CONST c1, LOAD_CONST c2 ... LOAD_CONST cn, BUILD_TUPLE n
`
171
202
` with LOAD_CONST (c1, c2, ... cn).
`
172
203
` The consts table must still be in list form so that the
`
`@@ -218,6 +249,101 @@ fold_tuple_on_constants(_Py_CODEUNIT *codestr, Py_ssize_t c_start,
`
218
249
`return copy_op_arg(codestr, c_start, LOAD_CONST, len_consts, opcode_end);
`
219
250
`}
`
220
251
``
``
252
`+
#define MAX_INT_SIZE 128 /* bits */
`
``
253
`+
#define MAX_COLLECTION_SIZE 20 /* items */
`
``
254
`+
#define MAX_STR_SIZE 20 /* characters */
`
``
255
`+
#define MAX_TOTAL_ITEMS 1024 /* including nested collections */
`
``
256
+
``
257
`+
static PyObject *
`
``
258
`+
safe_multiply(PyObject *v, PyObject *w)
`
``
259
`+
{
`
``
260
`+
if (PyLong_Check(v) && PyLong_Check(w) && Py_SIZE(v) && Py_SIZE(w)) {
`
``
261
`+
size_t vbits = _PyLong_NumBits(v);
`
``
262
`+
size_t wbits = _PyLong_NumBits(w);
`
``
263
`+
if (vbits == (size_t)-1 || wbits == (size_t)-1) {
`
``
264
`+
return NULL;
`
``
265
`+
}
`
``
266
`+
if (vbits + wbits > MAX_INT_SIZE) {
`
``
267
`+
return NULL;
`
``
268
`+
}
`
``
269
`+
}
`
``
270
`+
else if (PyLong_Check(v) && (PyTuple_Check(w) || PyFrozenSet_Check(w))) {
`
``
271
`+
Py_ssize_t size = PyTuple_Check(w) ? PyTuple_GET_SIZE(w) :
`
``
272
`+
PySet_GET_SIZE(w);
`
``
273
`+
if (size) {
`
``
274
`+
long n = PyLong_AsLong(v);
`
``
275
`+
if (n < 0 || n > MAX_COLLECTION_SIZE / size) {
`
``
276
`+
return NULL;
`
``
277
`+
}
`
``
278
`+
if (n && check_complexity(w, MAX_TOTAL_ITEMS / n) < 0) {
`
``
279
`+
return NULL;
`
``
280
`+
}
`
``
281
`+
}
`
``
282
`+
}
`
``
283
`+
else if (PyLong_Check(v) && (PyUnicode_Check(w) || PyBytes_Check(w))) {
`
``
284
`+
Py_ssize_t size = PyUnicode_Check(w) ? PyUnicode_GET_LENGTH(w) :
`
``
285
`+
PyBytes_GET_SIZE(w);
`
``
286
`+
if (size) {
`
``
287
`+
long n = PyLong_AsLong(v);
`
``
288
`+
if (n < 0 || n > MAX_STR_SIZE / size) {
`
``
289
`+
return NULL;
`
``
290
`+
}
`
``
291
`+
}
`
``
292
`+
}
`
``
293
`+
else if (PyLong_Check(w) &&
`
``
294
`+
(PyTuple_Check(v) || PyFrozenSet_Check(v) ||
`
``
295
`+
PyUnicode_Check(v) || PyBytes_Check(v)))
`
``
296
`+
{
`
``
297
`+
return safe_multiply(w, v);
`
``
298
`+
}
`
``
299
+
``
300
`+
return PyNumber_Multiply(v, w);
`
``
301
`+
}
`
``
302
+
``
303
`+
static PyObject *
`
``
304
`+
safe_power(PyObject *v, PyObject *w)
`
``
305
`+
{
`
``
306
`+
if (PyLong_Check(v) && PyLong_Check(w) && Py_SIZE(v) && Py_SIZE(w) > 0) {
`
``
307
`+
size_t vbits = _PyLong_NumBits(v);
`
``
308
`+
size_t wbits = PyLong_AsSize_t(w);
`
``
309
`+
if (vbits == (size_t)-1 || wbits == (size_t)-1) {
`
``
310
`+
return NULL;
`
``
311
`+
}
`
``
312
`+
if (vbits > MAX_INT_SIZE / wbits) {
`
``
313
`+
return NULL;
`
``
314
`+
}
`
``
315
`+
}
`
``
316
+
``
317
`+
return PyNumber_Power(v, w, Py_None);
`
``
318
`+
}
`
``
319
+
``
320
`+
static PyObject *
`
``
321
`+
safe_lshift(PyObject *v, PyObject *w)
`
``
322
`+
{
`
``
323
`+
if (PyLong_Check(v) && PyLong_Check(w) && Py_SIZE(v) && Py_SIZE(w)) {
`
``
324
`+
size_t vbits = _PyLong_NumBits(v);
`
``
325
`+
size_t wbits = PyLong_AsSize_t(w);
`
``
326
`+
if (vbits == (size_t)-1 || wbits == (size_t)-1) {
`
``
327
`+
return NULL;
`
``
328
`+
}
`
``
329
`+
if (wbits > MAX_INT_SIZE || vbits > MAX_INT_SIZE - wbits) {
`
``
330
`+
return NULL;
`
``
331
`+
}
`
``
332
`+
}
`
``
333
+
``
334
`+
return PyNumber_Lshift(v, w);
`
``
335
`+
}
`
``
336
+
``
337
`+
static PyObject *
`
``
338
`+
safe_mod(PyObject *v, PyObject *w)
`
``
339
`+
{
`
``
340
`+
if (PyUnicode_Check(v) || PyBytes_Check(v)) {
`
``
341
`+
return NULL;
`
``
342
`+
}
`
``
343
+
``
344
`+
return PyNumber_Remainder(v, w);
`
``
345
`+
}
`
``
346
+
221
347
`/* Replace LOAD_CONST c1, LOAD_CONST c2, BINOP
`
222
348
` with LOAD_CONST binop(c1,c2)
`
223
349
` The consts table must still be in list form so that the
`
`@@ -234,7 +360,7 @@ fold_binops_on_constants(_Py_CODEUNIT *codestr, Py_ssize_t c_start,
`
234
360
`PyObject *consts, PyObject **objs)
`
235
361
`{
`
236
362
`PyObject *newconst, *v, *w;
`
237
``
`-
Py_ssize_t len_consts, size;
`
``
363
`+
Py_ssize_t len_consts;
`
238
364
``
239
365
`/* Pre-conditions */
`
240
366
`assert(PyList_CheckExact(consts));
`
`@@ -245,10 +371,10 @@ fold_binops_on_constants(_Py_CODEUNIT *codestr, Py_ssize_t c_start,
`
245
371
`w = objs[1];
`
246
372
`switch (opcode) {
`
247
373
`case BINARY_POWER:
`
248
``
`-
newconst = PyNumber_Power(v, w, Py_None);
`
``
374
`+
newconst = safe_power(v, w);
`
249
375
`break;
`
250
376
`case BINARY_MULTIPLY:
`
251
``
`-
newconst = PyNumber_Multiply(v, w);
`
``
377
`+
newconst = safe_multiply(v, w);
`
252
378
`break;
`
253
379
`case BINARY_TRUE_DIVIDE:
`
254
380
`newconst = PyNumber_TrueDivide(v, w);
`
`@@ -257,7 +383,7 @@ fold_binops_on_constants(_Py_CODEUNIT *codestr, Py_ssize_t c_start,
`
257
383
`newconst = PyNumber_FloorDivide(v, w);
`
258
384
`break;
`
259
385
`case BINARY_MODULO:
`
260
``
`-
newconst = PyNumber_Remainder(v, w);
`
``
386
`+
newconst = safe_mod(v, w);
`
261
387
`break;
`
262
388
`case BINARY_ADD:
`
263
389
`newconst = PyNumber_Add(v, w);
`
`@@ -269,7 +395,7 @@ fold_binops_on_constants(_Py_CODEUNIT *codestr, Py_ssize_t c_start,
`
269
395
`newconst = PyObject_GetItem(v, w);
`
270
396
`break;
`
271
397
`case BINARY_LSHIFT:
`
272
``
`-
newconst = PyNumber_Lshift(v, w);
`
``
398
`+
newconst = safe_lshift(v, w);
`
273
399
`break;
`
274
400
`case BINARY_RSHIFT:
`
275
401
`newconst = PyNumber_Rshift(v, w);
`
`@@ -296,16 +422,6 @@ fold_binops_on_constants(_Py_CODEUNIT *codestr, Py_ssize_t c_start,
`
296
422
` }
`
297
423
`return -1;
`
298
424
` }
`
299
``
`-
size = PyObject_Size(newconst);
`
300
``
`-
if (size == -1) {
`
301
``
`-
if (PyErr_ExceptionMatches(PyExc_KeyboardInterrupt)) {
`
302
``
`-
return -1;
`
303
``
`-
}
`
304
``
`-
PyErr_Clear();
`
305
``
`-
} else if (size > 20) {
`
306
``
`-
Py_DECREF(newconst);
`
307
``
`-
return -1;
`
308
``
`-
}
`
309
425
``
310
426
`/* Append folded constant into consts table */
`
311
427
`if (PyList_Append(consts, newconst)) {
`