bpo-30416: Protect the optimizer during constant folding. (#4860) · python/cpython@2e3f570 (original) (raw)

`@@ -125,6 +125,132 @@ fold_unaryop(expr_ty node, PyArena *arena)

`

125

125

`return make_const(node, newval, arena);

`

126

126

`}

`

127

127

``

``

128

`+

/* Check whether a collection doesn't containing too much items (including

`

``

129

`+

subcollections). This protects from creating a constant that needs

`

``

130

`+

too much time for calculating a hash.

`

``

131

`+

"limit" is the maximal number of items.

`

``

132

`+

Returns the negative number if the total number of items exceeds the

`

``

133

`+

limit. Otherwise returns the limit minus the total number of items.

`

``

134

`+

*/

`

``

135

+

``

136

`+

static Py_ssize_t

`

``

137

`+

check_complexity(PyObject *obj, Py_ssize_t limit)

`

``

138

`+

{

`

``

139

`+

if (PyTuple_Check(obj)) {

`

``

140

`+

Py_ssize_t i;

`

``

141

`+

limit -= PyTuple_GET_SIZE(obj);

`

``

142

`+

for (i = 0; limit >= 0 && i < PyTuple_GET_SIZE(obj); i++) {

`

``

143

`+

limit = check_complexity(PyTuple_GET_ITEM(obj, i), limit);

`

``

144

`+

}

`

``

145

`+

return limit;

`

``

146

`+

}

`

``

147

`+

else if (PyFrozenSet_Check(obj)) {

`

``

148

`+

Py_ssize_t i = 0;

`

``

149

`+

PyObject *item;

`

``

150

`+

Py_hash_t hash;

`

``

151

`+

limit -= PySet_GET_SIZE(obj);

`

``

152

`+

while (limit >= 0 && _PySet_NextEntry(obj, &i, &item, &hash)) {

`

``

153

`+

limit = check_complexity(item, limit);

`

``

154

`+

}

`

``

155

`+

}

`

``

156

`+

return limit;

`

``

157

`+

}

`

``

158

+

``

159

`+

#define MAX_INT_SIZE 128 /* bits */

`

``

160

`+

#define MAX_COLLECTION_SIZE 256 /* items */

`

``

161

`+

#define MAX_STR_SIZE 4096 /* characters */

`

``

162

`+

#define MAX_TOTAL_ITEMS 1024 /* including nested collections */

`

``

163

+

``

164

`+

static PyObject *

`

``

165

`+

safe_multiply(PyObject *v, PyObject *w)

`

``

166

`+

{

`

``

167

`+

if (PyLong_Check(v) && PyLong_Check(w) && Py_SIZE(v) && Py_SIZE(w)) {

`

``

168

`+

size_t vbits = _PyLong_NumBits(v);

`

``

169

`+

size_t wbits = _PyLong_NumBits(w);

`

``

170

`+

if (vbits == (size_t)-1 || wbits == (size_t)-1) {

`

``

171

`+

return NULL;

`

``

172

`+

}

`

``

173

`+

if (vbits + wbits > MAX_INT_SIZE) {

`

``

174

`+

return NULL;

`

``

175

`+

}

`

``

176

`+

}

`

``

177

`+

else if (PyLong_Check(v) && (PyTuple_Check(w) || PyFrozenSet_Check(w))) {

`

``

178

`+

Py_ssize_t size = PyTuple_Check(w) ? PyTuple_GET_SIZE(w) :

`

``

179

`+

PySet_GET_SIZE(w);

`

``

180

`+

if (size) {

`

``

181

`+

long n = PyLong_AsLong(v);

`

``

182

`+

if (n < 0 || n > MAX_COLLECTION_SIZE / size) {

`

``

183

`+

return NULL;

`

``

184

`+

}

`

``

185

`+

if (n && check_complexity(w, MAX_TOTAL_ITEMS / n) < 0) {

`

``

186

`+

return NULL;

`

``

187

`+

}

`

``

188

`+

}

`

``

189

`+

}

`

``

190

`+

else if (PyLong_Check(v) && (PyUnicode_Check(w) || PyBytes_Check(w))) {

`

``

191

`+

Py_ssize_t size = PyUnicode_Check(w) ? PyUnicode_GET_LENGTH(w) :

`

``

192

`+

PyBytes_GET_SIZE(w);

`

``

193

`+

if (size) {

`

``

194

`+

long n = PyLong_AsLong(v);

`

``

195

`+

if (n < 0 || n > MAX_STR_SIZE / size) {

`

``

196

`+

return NULL;

`

``

197

`+

}

`

``

198

`+

}

`

``

199

`+

}

`

``

200

`+

else if (PyLong_Check(w) &&

`

``

201

`+

(PyTuple_Check(v) || PyFrozenSet_Check(v) ||

`

``

202

`+

PyUnicode_Check(v) || PyBytes_Check(v)))

`

``

203

`+

{

`

``

204

`+

return safe_multiply(w, v);

`

``

205

`+

}

`

``

206

+

``

207

`+

return PyNumber_Multiply(v, w);

`

``

208

`+

}

`

``

209

+

``

210

`+

static PyObject *

`

``

211

`+

safe_power(PyObject *v, PyObject *w)

`

``

212

`+

{

`

``

213

`+

if (PyLong_Check(v) && PyLong_Check(w) && Py_SIZE(v) && Py_SIZE(w) > 0) {

`

``

214

`+

size_t vbits = _PyLong_NumBits(v);

`

``

215

`+

size_t wbits = PyLong_AsSize_t(w);

`

``

216

`+

if (vbits == (size_t)-1 || wbits == (size_t)-1) {

`

``

217

`+

return NULL;

`

``

218

`+

}

`

``

219

`+

if (vbits > MAX_INT_SIZE / wbits) {

`

``

220

`+

return NULL;

`

``

221

`+

}

`

``

222

`+

}

`

``

223

+

``

224

`+

return PyNumber_Power(v, w, Py_None);

`

``

225

`+

}

`

``

226

+

``

227

`+

static PyObject *

`

``

228

`+

safe_lshift(PyObject *v, PyObject *w)

`

``

229

`+

{

`

``

230

`+

if (PyLong_Check(v) && PyLong_Check(w) && Py_SIZE(v) && Py_SIZE(w)) {

`

``

231

`+

size_t vbits = _PyLong_NumBits(v);

`

``

232

`+

size_t wbits = PyLong_AsSize_t(w);

`

``

233

`+

if (vbits == (size_t)-1 || wbits == (size_t)-1) {

`

``

234

`+

return NULL;

`

``

235

`+

}

`

``

236

`+

if (wbits > MAX_INT_SIZE || vbits > MAX_INT_SIZE - wbits) {

`

``

237

`+

return NULL;

`

``

238

`+

}

`

``

239

`+

}

`

``

240

+

``

241

`+

return PyNumber_Lshift(v, w);

`

``

242

`+

}

`

``

243

+

``

244

`+

static PyObject *

`

``

245

`+

safe_mod(PyObject *v, PyObject *w)

`

``

246

`+

{

`

``

247

`+

if (PyUnicode_Check(v) || PyBytes_Check(v)) {

`

``

248

`+

return NULL;

`

``

249

`+

}

`

``

250

+

``

251

`+

return PyNumber_Remainder(v, w);

`

``

252

`+

}

`

``

253

+

128

254

`static int

`

129

255

`fold_binop(expr_ty node, PyArena *arena)

`

130

256

`{

`

`@@ -147,7 +273,7 @@ fold_binop(expr_ty node, PyArena *arena)

`

147

273

`newval = PyNumber_Subtract(lv, rv);

`

148

274

`break;

`

149

275

`case Mult:

`

150

``

`-

newval = PyNumber_Multiply(lv, rv);

`

``

276

`+

newval = safe_multiply(lv, rv);

`

151

277

`break;

`

152

278

`case Div:

`

153

279

`newval = PyNumber_TrueDivide(lv, rv);

`

`@@ -156,13 +282,13 @@ fold_binop(expr_ty node, PyArena *arena)

`

156

282

`newval = PyNumber_FloorDivide(lv, rv);

`

157

283

`break;

`

158

284

`case Mod:

`

159

``

`-

newval = PyNumber_Remainder(lv, rv);

`

``

285

`+

newval = safe_mod(lv, rv);

`

160

286

`break;

`

161

287

`case Pow:

`

162

``

`-

newval = PyNumber_Power(lv, rv, Py_None);

`

``

288

`+

newval = safe_power(lv, rv);

`

163

289

`break;

`

164

290

`case LShift:

`

165

``

`-

newval = PyNumber_Lshift(lv, rv);

`

``

291

`+

newval = safe_lshift(lv, rv);

`

166

292

`break;

`

167

293

`case RShift:

`

168

294

`newval = PyNumber_Rshift(lv, rv);

`

`@@ -180,27 +306,6 @@ fold_binop(expr_ty node, PyArena *arena)

`

180

306

`return 1;

`

181

307

` }

`

182

308

``

183

``

`-

if (newval == NULL) {

`

184

``

`-

if (PyErr_ExceptionMatches(PyExc_KeyboardInterrupt)) {

`

185

``

`-

return 0;

`

186

``

`-

}

`

187

``

`-

PyErr_Clear();

`

188

``

`-

return 1;

`

189

``

`-

}

`

190

``

-

191

``

`-

/* Avoid creating large constants. */

`

192

``

`-

Py_ssize_t size = PyObject_Size(newval);

`

193

``

`-

if (size == -1) {

`

194

``

`-

if (PyErr_ExceptionMatches(PyExc_KeyboardInterrupt)) {

`

195

``

`-

Py_DECREF(newval);

`

196

``

`-

return 0;

`

197

``

`-

}

`

198

``

`-

PyErr_Clear();

`

199

``

`-

}

`

200

``

`-

else if (size > 20) {

`

201

``

`-

Py_DECREF(newval);

`

202

``

`-

return 1;

`

203

``

`-

}

`

204

309

`return make_const(node, newval, arena);

`

205

310

`}

`

206

311

``