Frame hacking

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • George Sakkis

    #1

    Frame hacking

    I wonder if the following is possible:

    def inject_n_call(f unc, **kwds):
    '''Call func by first updating its locals with kwds.'''

    def f():
    return x*y
    >>inject_n_call (f, x=3, y=4)
    12

    I've been playing with sys.settrace, updating frame.f_locals in the
    trace function, but it doesn't seem to work. Any other ideas ?

    George

  • Gabriel Genellina

    #2
    Re: Frame hacking

    On 12 dic, 17:46, "George Sakkis" <george.sak...@ gmail.comwrote:
    I wonder if the following is possible:
    >
    def inject_n_call(f unc, **kwds):
    '''Call func by first updating its locals with kwds.'''
    >
    def f():
    return x*y
    >
    >>eval(f.func_c ode, dict(x=3,y=4))
    12

    Comment

    • George Sakkis

      #3
      Re: Frame hacking

      Gabriel Genellina wrote:
      On 12 dic, 17:46, "George Sakkis" <george.sak...@ gmail.comwrote:
      >
      I wonder if the following is possible:

      def inject_n_call(f unc, **kwds):
      '''Call func by first updating its locals with kwds.'''

      def f():
      return x*y
      >
      >eval(f.func_co de, dict(x=3,y=4))
      12
      Sweet! I think I just reinvented what eval does in this case by
      fiddling with sys.settrace and frame.f_globals . Glad to trash my
      20-line function for an one-liner :)

      Regards,
      George

      Comment

      • George Sakkis

        #4
        Re: Frame hacking

        George Sakkis wrote:
        Gabriel Genellina wrote:
        On 12 dic, 17:46, "George Sakkis" <george.sak...@ gmail.comwrote:
        I wonder if the following is possible:
        >
        def inject_n_call(f unc, **kwds):
        '''Call func by first updating its locals with kwds.'''
        >
        def f():
        return x*y
        >
        >>eval(f.func_c ode, dict(x=3,y=4))
        12
        >
        Sweet! I think I just reinvented what eval does in this case by
        fiddling with sys.settrace and frame.f_globals . Glad to trash my
        20-line function for an one-liner :)
        Actually I thought about this and it would be more convenient in my
        case if I could change the "signature" of f to "def f(x,y)" so that I
        can pass positional arguments instead of a keywords (don't ask why).
        I've tried creating a new code object by tweaking co_varnames,
        co_argcount, co_nlocals and making a new function out of it but it
        doesn't work.. does co_code have to be changed as well, and if so, how?

        George

        Comment

        • fumanchu

          #5
          Re: Frame hacking

          George Sakkis wrote:
          Actually I thought about this and it would be more convenient in my
          case if I could change the "signature" of f to "def f(x,y)" so that I
          can pass positional arguments instead of a keywords (don't ask why).
          I've tried creating a new code object by tweaking co_varnames,
          co_argcount, co_nlocals and making a new function out of it but it
          doesn't work.. does co_code have to be changed as well, and if so, how?
          Yes; since x and y then become locals and are looked up using LOAD_FAST
          instead of LOAD_GLOBAL. Easiest approach: write the new function
          yourself and pass it to dis.dis() and expreiment with the differences
          in bytecode.

          Here are some helpers I use for bytecode hacking (from the top of


          from opcode import cmp_op, opname, opmap, HAVE_ARGUMENT
          from types import CodeType, FunctionType, MethodType

          from compiler.consts import *
          CO_NOFREE = 0x0040


          def named_opcodes(b its):
          """Change initial numeric opcode bits to their named
          equivalents."""
          bitnums = []
          bits = iter(bits)
          for x in bits:
          bitnums.append( opname[x])
          if x >= HAVE_ARGUMENT:
          try:
          bitnums.append( bits.next())
          bitnums.append( bits.next())
          except StopIteration:
          break
          return bitnums

          def numeric_opcodes (bits):
          """Change named opcode bits to their numeric equivalents."""
          bitnums = []
          for x in bits:
          if isinstance(x, basestring):
          x = opmap[x]
          bitnums.append( x)
          return bitnums

          _deref_bytecode = numeric_opcodes (['LOAD_DEREF', 0, 0, 'RETURN_VALUE'])
          # CodeType(argcou nt, nlocals, stacksize, flags, codestring, constants,
          # names, varnames, filename, name, firstlineno,
          # lnotab[, freevars[, cellvars]])
          _derefblock = CodeType(0, 0, 1, 3, ''.join(map(chr , _deref_bytecode )),
          (None,), ('cell',), (), '', '', 2, '',
          ('cell',))
          def deref_cell(cell ):
          """Return the value of 'cell' (an object from a func_closure)." ""
          # FunctionType(co de, globals[, name[, argdefs[, closure]]])
          return FunctionType(_d erefblock, {}, "", (), (cell,))()


          Robert Brewer
          System Architect
          Amor Ministries
          fumanchu@amor.o rg

          Comment

          Working...