Checking Suspicious Functions

Moshe Zadka moshez at
Sun Feb 27 12:20:52 CET 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:

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:
			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
		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():
	def bar():
		return 1

	def baz():
		if a:
			return 1

	def qux():
		return 1

	for f in (foo, bar, baz, qux):
		if bad_return(f):
			print f.func_name, "is shaky"
			print f.func_name, "seems alright"
--- cut here -----
Moshe Zadka <mzadka at>. 
INTERNET: Learn what you know.
Share what you don't.

More information about the Python-list mailing list