New submission from Dan Snider <mr.assume.a...@gmail.com>:
The following program crashes on 3.3.1, 3.4.2, 3.5.2, and 3.6.1 because despite having a non-empty co_cellvars slot due to the generator object, the NOFREE flag was set. 3.7 isn't immune to some bad behavior here, either. While I only have access to 3.7.03b right now, I noted the assertion at the bottom failing because it appears CodeType.__new__ is silently stripping the NOFREE flag out, which is why it's highlighted as well. Since the interpreter doesn't actually use FunctionType.__new__ it shouldn't hurt performance too much to add a check for when NOFREE is set that co_cellvars and co_freevars are indeed empty. Anyway, the code: from functools import reduce from itertools import repeat from operator import or_ from types import FunctionType, CodeType OPTIMIZED, NEWLOCALS, NOFREE = 1, 2, 64 FLAGS = [OPTIMIZED, NEWLOCALS, NOFREE] fields=('argcount kwonlyargcount nlocals stacksize flags code consts ' 'names varnames filename name firstlineno lnotab freevars cellvars').split() def edit_code(code, *args, **kws): """Construct a new code object using `code` as a template""" params = [] atrs = ('co_%s'%a for a in fields) kwds = map(kws.pop, fields, repeat(kws)) for arg, kwv, k in zip(args, kwds, atrs): if kwv is not kws: raise TypeError("edit_code() got multiple parameters for %r"%k) params.append(arg) for kwv, atr in zip(kwds, atrs): params.append(kwv if kwv is not kws else getattr(code, atr)) if kws: k, v = kws.popitem() raise TypeError("edit_code() got unexpected keyword argument %r"%k) return CodeType(*params) def get_co_flags(flags): if isinstance(flags, FunctionType): flags = flags.__code__.co_flags elif isinstance(flags, CodeType): flags = flags.co_flags return reduce(or_, (i for i in FLAGS if flags & i)) if __name__ == '__main__': co = get_co_flags.__code__ ns = get_co_flags.__globals__ flags = co.co_flags assert flags == OPTIMIZED|NEWLOCALS assert NOFREE == 64 a = FunctionType(edit_code(co, flags=flags), ns) b = FunctionType(edit_code(co, flags=flags|NOFREE), ns) # this assertion fails on 3.7.0b3 assert b.__code__.co_flags == OPTIMIZED|NEWLOCALS|NOFREE print('calling a...') a(get_co_flags) t = input("Blow up the universe? y/n : ") if t != 'n': b(get_co_flags) ---------- components: Interpreter Core messages: 322174 nosy: bup priority: normal severity: normal status: open title: FunctionType.__new__ can generate functions that immediately crash type: crash versions: Python 3.4, Python 3.5, Python 3.6, Python 3.7 _______________________________________ Python tracker <rep...@bugs.python.org> <https://bugs.python.org/issue34192> _______________________________________ _______________________________________________ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com