Generates random Python functions using Markov chains
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

119 lines
3.2 KiB

  1. import dis
  2. import opcode
  3. import random
  4. import types
  5. ############## CODE ###########################################################
  6. MARKOV_START = -1
  7. MARKOV_END = -2
  8. def make_chain(funcs):
  9. chain = {}
  10. for func in funcs:
  11. co = func.__code__
  12. code = co.co_code
  13. n = len(code)
  14. i = 0
  15. lastop = MARKOV_START
  16. while i < n:
  17. op = ord(code[i])
  18. i += 1
  19. if op >= opcode.HAVE_ARGUMENT:
  20. oparg = ord(code[i]) + ord(code[i + 1]) * 256
  21. i += 2
  22. if op in opcode.hasconst:
  23. arg = co.co_consts[oparg]
  24. elif op in opcode.haslocal:
  25. arg = co.co_varnames[oparg]
  26. else:
  27. raise NotImplementedError(op, opcode.opname[op])
  28. else:
  29. arg = None
  30. _chain_append(chain, lastop, (op, arg))
  31. lastop = op
  32. _chain_append(chain, op, MARKOV_END)
  33. return chain
  34. def make_function(chain, name, argcount=1):
  35. codes, constants, varnames = _make_codes(chain)
  36. nlocals = len(varnames) + argcount
  37. stacksize = 1024 # High limit?
  38. flags = 0 # Denotes funcs with *args and/or **kwargs; nothing for now
  39. codestring = "".join([chr(code) for code in codes])
  40. names = ()
  41. filename = "<smash>"
  42. firstlineno = 1
  43. lnotab = ""
  44. code = types.CodeType(argcount, nlocals, stacksize, flags, codestring,
  45. constants, names, varnames, filename, name,
  46. firstlineno, lnotab)
  47. func = types.FunctionType(code, globals(), name)
  48. return func
  49. def _chain_append(chain, first, second):
  50. try:
  51. chain[first].append(second)
  52. except KeyError:
  53. chain[first] = [second]
  54. def _make_codes(chain):
  55. codes = []
  56. code = random.choice(chain[MARKOV_START])
  57. constants, varnames = [], []
  58. while 1:
  59. if code == MARKOV_END:
  60. break
  61. op, arg = code
  62. codes.append(op)
  63. if op >= opcode.HAVE_ARGUMENT:
  64. if op in opcode.hasconst:
  65. args = constants
  66. elif op in opcode.haslocal:
  67. args = varnames
  68. else:
  69. raise NotImplementedError(op, opcode.opname[op])
  70. if arg not in args:
  71. args.append(arg)
  72. codes.append(args.index(arg))
  73. codes.append(0)
  74. code = random.choice(chain[op])
  75. return codes, tuple(constants), tuple(varnames)
  76. ############## FUNCTION CORPUS ################################################
  77. def f1(a):
  78. b = a + 7.0
  79. return b
  80. def f2(a):
  81. b = a - 5.0
  82. return b
  83. def f3(a):
  84. b = a * 3.0
  85. return b
  86. def f4(a):
  87. b = a / 2.0
  88. return b
  89. corpus = [f1, f2, f3, f4]
  90. ############## DEMO ###########################################################
  91. if __name__ == "__main__":
  92. print "USING FUNCTION CORPUS:", [func.__name__ for func in corpus]
  93. chain = make_chain(corpus)
  94. print "OPCODE MARKOV CHAIN:", chain
  95. print
  96. func = make_function(chain, "func")
  97. print "SMASHED FUNCTION CODE:", [ord(c) for c in func.__code__.co_code]
  98. print "FUNCTION DISASSEMBLY:"
  99. dis.dis(func)
  100. print
  101. n = 12.0
  102. print "func(%s) =" % n, func(n)