This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author bup
Recipients bup
Date 2018-07-23.03:57:23
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1532318245.8.0.56676864532.issue34192@psf.upfronthosting.co.za>
In-reply-to
Content
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)
History
Date User Action Args
2018-07-23 03:57:26bupsetrecipients: + bup
2018-07-23 03:57:25bupsetmessageid: <1532318245.8.0.56676864532.issue34192@psf.upfronthosting.co.za>
2018-07-23 03:57:25buplinkissue34192 messages
2018-07-23 03:57:23bupcreate