[Python-bugs-list] Exec statement inconsistency (PR#176)

vadimch@yahoo.com vadimch@yahoo.com
Sun, 9 Jan 2000 22:01:54 -0500 (EST)


Full_Name: Vadim Chugunov
Version: 1.5.2
OS: NT
Submission from: evrtwa1-ar3-233-065.dsl.gtei.net (4.3.233.65)


Consider this code:
    x = 1
    exec "x=x+1"
    print x
The result is 2. On the other hand,
    def f():
        x=x+1
    exec f.func_code
results in NameError: x
Exec on files is broken as well.

As far as I can see, the problem is that:
a) PyFrame_New() ignores the locals passed in if the code object has the
CO_NEWLOCALS flag set.
b) exec_statement() does not call PyFrame_LocalsToFast() unless a string is
being executed.

Here's what I think the fix should be:
===================================================================
RCS file: /projects/cvsroot/python/dist/src/Objects/frameobject.c,v
retrieving revision 2.36
diff -c -r2.36 frameobject.c
*** frameobject.c	1998/10/19 14:20:20	2.36
--- frameobject.c	2000/01/09 12:14:27
***************
*** 219,239 ****
  	f->f_code = code;
  	Py_INCREF(globals);
  	f->f_globals = globals;
! 	if (code->co_flags & CO_NEWLOCALS) {
! 		if (code->co_flags & CO_OPTIMIZED)
! 			locals = NULL; /* Let fast_2_locals handle it */
! 		else {
! 			locals = PyDict_New();
! 			if (locals == NULL) {
! 				Py_DECREF(f);
! 				return NULL;
! 			}
! 		}
  	}
  	else {
! 		if (locals == NULL)
  			locals = globals;
! 		Py_INCREF(locals);
  	}
  	f->f_locals = locals;
  	f->f_trace = NULL;
--- 219,243 ----
  	f->f_code = code;
  	Py_INCREF(globals);
  	f->f_globals = globals;
! 	if (locals!=NULL) {
! 		Py_INCREF(locals);
  	}
  	else {
! 		if (code->co_flags & CO_NEWLOCALS) {
! 			if (code->co_flags & CO_OPTIMIZED)
! 				locals = NULL; /* Let fast_2_locals handle it */
! 			else {
! 				locals = PyDict_New();
! 				if (locals == NULL) {
! 					Py_DECREF(f);
! 					return NULL;
! 				}
! 			}
! 		}
! 		else {
  			locals = globals;
! 			Py_INCREF(locals);
! 		}
  	}
  	f->f_locals = locals;
  	f->f_trace = NULL;
***************
*** 251,256 ****
--- 255,263 ----
  		f->f_localsplus[extras] = NULL;
  
  	f->f_valuestack = f->f_localsplus + f->f_nlocals;
+ 
+ 	if (f->f_locals != NULL)
+ 		PyFrame_LocalsToFast(f,0);
  
  	return f;
  }


===================================================================
RCS file: /projects/cvsroot/python/dist/src/Python/ceval.c,v
retrieving revision 2.165
diff -c -r2.165 ceval.c
*** ceval.c	1999/11/15 19:29:33	2.165
--- ceval.c	2000/01/10 02:47:25
***************
*** 2782,2787 ****
--- 2782,2789 ----
  		if (v == NULL)
  			return -1;
  		Py_DECREF(v);
+ 		if (plain)
+ 			PyFrame_LocalsToFast(f, 0);
  		return 0;
  	}
  	if (PyFile_Check(prog)) {
***************
*** 2790,2795 ****
--- 2792,2799 ----
  		if (PyRun_File(fp, name, Py_file_input,
  			       globals, locals) == NULL)
  			return -1;
+ 		if (plain)
+ 			PyFrame_LocalsToFast(f, 0);
  		return 0;
  	}
  	s = PyString_AsString(prog);


===================================================================
I confirm that, to the best of my knowledge and belief, this
contribution is free of any claims of third parties under
copyright, patent or other rights or interests ("claims").  To
the extent that I have any such claims, I hereby grant to CNRI a
nonexclusive, irrevocable, royalty-free, worldwide license to
reproduce, distribute, perform and/or display publicly, prepare
derivative versions, and otherwise use this contribution as part
of the Python software and its related documentation, or any
derivative versions thereof, at no cost to CNRI or its licensed
users, and to authorize others to do so.

I acknowledge that CNRI may, at its sole discretion, decide
whether or not to incorporate this contribution in the Python
software and its related documentation.  I further grant CNRI
permission to use my name and other identifying information
provided to CNRI by me for use in connection with the Python
software and its related documentation.