From 733c8935f9dfd1be70c472649eb845ea22bbc878 Mon Sep 17 00:00:00 2001
From: Jeremy Hylton <jeremy@alum.mit.edu>
Date: Thu, 13 Dec 2001 19:51:56 +0000
Subject: Fix for SF bug [ #492403 ] exec() segfaults on closure's func_code

Based on the patch from Danny Yoo.  The fix is in exec_statement() in
ceval.c.

There are also changes to introduce use of PyCode_GetNumFree() in
several places.
---
 Python/bltinmodule.c | 2 +-
 Python/ceval.c       | 7 ++++++-
 Python/compile.c     | 6 +++---
 3 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c
index 8e4ca2e..f5ce749 100644
--- a/Python/bltinmodule.c
+++ b/Python/bltinmodule.c
@@ -497,7 +497,7 @@ builtin_eval(PyObject *self, PyObject *args)
 	}
 
 	if (PyCode_Check(cmd)) {
-		if (PyTuple_GET_SIZE(((PyCodeObject *)cmd)->co_freevars) > 0) {
+		if (PyCode_GetNumFree((PyCodeObject *)cmd) > 0) {
 			PyErr_SetString(PyExc_TypeError,
 		"code object passed to eval() may not contain free variables");
 			return NULL;
diff --git a/Python/ceval.c b/Python/ceval.c
index 29d7082..3e41b9a 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -2094,7 +2094,7 @@ eval_frame(PyFrameObject *f)
 			int nfree;
 			v = POP(); /* code object */
 			x = PyFunction_New(v, f->f_globals);
-			nfree = PyTuple_GET_SIZE(((PyCodeObject *)v)->co_freevars);
+			nfree = PyCode_GetNumFree((PyCodeObject *)v);
 			Py_DECREF(v);
 			/* XXX Maybe this should be a separate opcode? */
 			if (x != NULL && nfree > 0) {
@@ -3631,6 +3631,11 @@ exec_statement(PyFrameObject *f, PyObject *prog, PyObject *globals,
 	if (PyDict_GetItemString(globals, "__builtins__") == NULL)
 		PyDict_SetItemString(globals, "__builtins__", f->f_builtins);
 	if (PyCode_Check(prog)) {
+		if (PyCode_GetNumFree((PyCodeObject *)prog) > 0) {
+			PyErr_SetString(PyExc_TypeError,
+		"code object passed to exec may not contain free variables");
+			return -1;
+		}
 		v = PyEval_EvalCode((PyCodeObject *) prog, globals, locals);
 	}
 	else if (PyFile_Check(prog)) {
diff --git a/Python/compile.c b/Python/compile.c
index d76769c..4421284 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -2273,7 +2273,7 @@ com_and_test(struct compiling *c, node *n)
 static int
 com_make_closure(struct compiling *c, PyCodeObject *co)
 {
-	int i, free = PyTuple_GET_SIZE(co->co_freevars);
+	int i, free = PyCode_GetNumFree(co);
 	if (free == 0)
 		return 0;
 	for (i = 0; i < free; ++i) {
@@ -2333,7 +2333,7 @@ com_test(struct compiling *c, node *n)
 		com_push(c, 1);
 		if (closure) {
 			com_addoparg(c, MAKE_CLOSURE, ndefs);
-			com_pop(c, PyTuple_GET_SIZE(co->co_freevars));
+			com_pop(c, PyCode_GetNumFree(co));
 		} else
 			com_addoparg(c, MAKE_FUNCTION, ndefs);
 		Py_DECREF(co);
@@ -3590,7 +3590,7 @@ com_classdef(struct compiling *c, node *n)
 		com_push(c, 1);
 		if (closure) {
 			com_addoparg(c, MAKE_CLOSURE, 0);
-			com_pop(c, PyTuple_GET_SIZE(co->co_freevars));
+			com_pop(c, PyCode_GetNumFree(co));
 		} else
 			com_addoparg(c, MAKE_FUNCTION, 0);
 		com_addoparg(c, CALL_FUNCTION, 0);
-- 
cgit v0.12

