[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)) {

`