summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorDamien George <damien.p.george@gmail.com>2014-04-12 18:20:40 +0100
committerDamien George <damien.p.george@gmail.com>2014-04-12 18:20:40 +0100
commit6ce427755112c28f8a7efab65d329205d833f623 (patch)
tree47b3b292e4472cc15996b745202dd98133e89feb
parentc2803db010ab575e9387e4eaf2f8090b083b3c5f (diff)
downloadmicropython-6ce427755112c28f8a7efab65d329205d833f623.tar.gz
micropython-6ce427755112c28f8a7efab65d329205d833f623.zip
py: Make all LOAD_FAST ops check for unbound local.
This is necessary to catch all cases where locals are referenced before assignment. We still keep the _0, _1, _2 versions of LOAD_FAST to help reduced the byte code size in RAM. Addresses issue #457.
-rw-r--r--py/bc0.h1
-rw-r--r--py/emitbc.c16
-rw-r--r--py/emitpass1.c4
-rw-r--r--py/showbc.c5
-rw-r--r--py/vm.c24
-rw-r--r--tests/basics/unboundlocal.py19
6 files changed, 35 insertions, 34 deletions
diff --git a/py/bc0.h b/py/bc0.h
index e6a0e21241..7d6e52b72c 100644
--- a/py/bc0.h
+++ b/py/bc0.h
@@ -17,7 +17,6 @@
#define MP_BC_LOAD_FAST_1 (0x21)
#define MP_BC_LOAD_FAST_2 (0x22)
#define MP_BC_LOAD_FAST_N (0x23) // uint
-#define MP_BC_LOAD_FAST_CHECKED (0x24) // uint
#define MP_BC_LOAD_DEREF (0x25) // uint
#define MP_BC_LOAD_NAME (0x26) // qstr
#define MP_BC_LOAD_GLOBAL (0x27) // qstr
diff --git a/py/emitbc.c b/py/emitbc.c
index a1179a6954..d1d59ef4a5 100644
--- a/py/emitbc.c
+++ b/py/emitbc.c
@@ -413,17 +413,11 @@ STATIC void emit_bc_load_null(emit_t *emit) {
STATIC void emit_bc_load_fast(emit_t *emit, qstr qstr, uint id_flags, int local_num) {
assert(local_num >= 0);
emit_bc_pre(emit, 1);
- if (id_flags & ID_FLAG_IS_DELETED) {
- // This local may be deleted, so need to do a checked load.
- emit_write_byte_code_byte_uint(emit, MP_BC_LOAD_FAST_CHECKED, local_num);
- } else {
- // This local is never deleted, so can do a fast, uncheched load.
- switch (local_num) {
- case 0: emit_write_byte_code_byte(emit, MP_BC_LOAD_FAST_0); break;
- case 1: emit_write_byte_code_byte(emit, MP_BC_LOAD_FAST_1); break;
- case 2: emit_write_byte_code_byte(emit, MP_BC_LOAD_FAST_2); break;
- default: emit_write_byte_code_byte_uint(emit, MP_BC_LOAD_FAST_N, local_num); break;
- }
+ switch (local_num) {
+ case 0: emit_write_byte_code_byte(emit, MP_BC_LOAD_FAST_0); break;
+ case 1: emit_write_byte_code_byte(emit, MP_BC_LOAD_FAST_1); break;
+ case 2: emit_write_byte_code_byte(emit, MP_BC_LOAD_FAST_2); break;
+ default: emit_write_byte_code_byte_uint(emit, MP_BC_LOAD_FAST_N, local_num); break;
}
}
diff --git a/py/emitpass1.c b/py/emitpass1.c
index 301c04ebea..ad86588e20 100644
--- a/py/emitpass1.c
+++ b/py/emitpass1.c
@@ -96,7 +96,9 @@ STATIC void emit_pass1_store_id(emit_t *emit, qstr qstr) {
STATIC void emit_pass1_delete_id(emit_t *emit, qstr qstr) {
id_info_t *id = get_id_for_modification(emit->scope, qstr);
- id->flags |= ID_FLAG_IS_DELETED;
+ // this flag is unused
+ //id->flags |= ID_FLAG_IS_DELETED;
+ (void)id; // suppress compiler warning
}
const emit_method_table_t emit_pass1_method_table = {
diff --git a/py/showbc.c b/py/showbc.c
index c3342ca841..615d1fe0de 100644
--- a/py/showbc.c
+++ b/py/showbc.c
@@ -132,11 +132,6 @@ void mp_byte_code_print(const byte *ip, int len) {
printf("LOAD_FAST_N " UINT_FMT, unum);
break;
- case MP_BC_LOAD_FAST_CHECKED:
- DECODE_UINT;
- printf("LOAD_FAST_CHECKED " UINT_FMT, unum);
- break;
-
case MP_BC_LOAD_DEREF:
DECODE_UINT;
printf("LOAD_DEREF " UINT_FMT, unum);
diff --git a/py/vm.c b/py/vm.c
index 1ea0c5eaa1..f62cb2d7b1 100644
--- a/py/vm.c
+++ b/py/vm.c
@@ -252,25 +252,21 @@ dispatch_loop:
break;
case MP_BC_LOAD_FAST_0:
- PUSH(fastn[0]);
- break;
+ obj1 = fastn[0];
+ goto load_check;
case MP_BC_LOAD_FAST_1:
- PUSH(fastn[-1]);
- break;
+ obj1 = fastn[-1];
+ goto load_check;
case MP_BC_LOAD_FAST_2:
- PUSH(fastn[-2]);
- break;
+ obj1 = fastn[-2];
+ goto load_check;
case MP_BC_LOAD_FAST_N:
DECODE_UINT;
- PUSH(fastn[-unum]);
- break;
-
- case MP_BC_LOAD_FAST_CHECKED:
- DECODE_UINT;
obj1 = fastn[-unum];
+ load_check:
if (obj1 == MP_OBJ_NULL) {
local_name_error:
nlr_raise(mp_obj_new_exception_msg(&mp_type_NameError, "local variable referenced before assignment"));
@@ -281,11 +277,7 @@ dispatch_loop:
case MP_BC_LOAD_DEREF:
DECODE_UINT;
obj1 = mp_obj_cell_get(fastn[-unum]);
- if (obj1 == MP_OBJ_NULL) {
- goto local_name_error;
- }
- PUSH(obj1);
- break;
+ goto load_check;
case MP_BC_LOAD_NAME:
DECODE_QSTR;
diff --git a/tests/basics/unboundlocal.py b/tests/basics/unboundlocal.py
new file mode 100644
index 0000000000..5573da1665
--- /dev/null
+++ b/tests/basics/unboundlocal.py
@@ -0,0 +1,19 @@
+# locals referenced before assignment
+
+def f1():
+ print(x)
+ x = 1
+
+def f2():
+ for i in range(0):
+ print(i)
+ print(i)
+
+def check(f):
+ try:
+ f()
+ except NameError:
+ print("NameError")
+
+check(f1)
+check(f2)