Checking Suspicious Functions
Moshe Zadka
moshez at math.huji.ac.il
Sun Feb 27 06:20:52 EST 2000
After Tim and mine discusion, I thought writing code for a change would be
nice. Here's a rough draft of my "checking whether a function can return a
value from one place and return None from another" code:
--- suspect.py
import dis # for HAVE_ARGUMENT, and opname
# currently we're to dumb to understand this is valid:
# if x:
# return 1
# else:
# return 0
for i in range(len(dis.opname)):
if dis.opname[i]=='LOAD_CONST':
load_const = i
if dis.opname[i]=='RETURN_VALUE':
return_value = i
load_const, return_value
none_place = 0 # None is always the first suspect
def basic_dis(code):
ret = []
n = len(code)
i = 0
while i < n:
b = ord(code[i])
if b < dis.HAVE_ARGUMENT:
ret.append((b,))
else:
argument = ord(code[i+1])+256*ord(code[i+2])
ret.append((b, argument))
i = i+2
i = i+1
return ret
def get_suspects(ops):
suspects = []
for i in range(len(ops)):
# if Python's compiler has a bug, this will output nonsense
if ops[i] == (return_value,):
suspects.append((i, ops[i-1]))
# if there are two returns at the end, the last one if Python's
# fault: it should be smart enough to optimize it away:
if len(suspects)>=2 and suspects[-1][0]==suspects[-2][0]+2:
del suspects[-1]
return map(lambda x: x[1], suspects)
def check_suspects(suspects):
if not suspects:
return 1
first, rest = suspects[0], suspects[1:]
if first == (load_const, 0):
for el in rest:
if el != (load_const, 0):
return 0
return 1
else:
for el in rest:
if el == (load_const, 0):
return 0
return 1
def bad_return(func):
code = func.func_code.co_code
ops = basic_dis(code)
suspects = get_suspects(ops)
if check_suspects(suspects):
return 0
return 1
if __name__=='__main__':
def foo():
pass
def bar():
return 1
def baz():
if a:
return 1
def qux():
return 1
return
for f in (foo, bar, baz, qux):
if bad_return(f):
print f.func_name, "is shaky"
else:
print f.func_name, "seems alright"
--- cut here -----
--
Moshe Zadka <mzadka at geocities.com>.
INTERNET: Learn what you know.
Share what you don't.
More information about the Python-list
mailing list