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.

175 lines
4.5 KiB

  1. import opcode
  2. import random
  3. import types
  4. ############## CODE ###########################################################
  5. MARKOV_START = -1
  6. MARKOV_END = -2
  7. def make_chain(funcs):
  8. chain = {}
  9. for func in funcs:
  10. _parse_func(func, chain)
  11. return chain
  12. def make_function(chain, name, argcount=1):
  13. codes, constants, varnames = _make_codes(chain)
  14. nlocals = len(varnames) + argcount
  15. stacksize = 1024 # High limit?
  16. flags = 0 # Denotes funcs with *args and/or **kwargs; nothing for now
  17. codestring = "".join([chr(code) for code in codes])
  18. names = ()
  19. filename = "<smash>"
  20. firstlineno = 1
  21. lnotab = ""
  22. code = types.CodeType(argcount, nlocals, stacksize, flags, codestring,
  23. constants, names, varnames, filename, name,
  24. firstlineno, lnotab)
  25. func = types.FunctionType(code, globals(), name)
  26. return func
  27. def print_chain(chain):
  28. print "{"
  29. for key in sorted(chain.keys()):
  30. op = _int_to_opname(key)
  31. targets = {}
  32. for op2 in chain[key]:
  33. target = _int_to_opname(op2[0])
  34. if op2[0] >= opcode.HAVE_ARGUMENT:
  35. target = "{0}({1})".format(target, op2[1])
  36. try:
  37. targets[target] += 1
  38. except KeyError:
  39. targets[target] = 1
  40. targs = [t if targets[t] == 1 else "{0}x {1}".format(targets[t], t) for t in targets]
  41. targs.sort()
  42. tstring = ", ".join(targs)
  43. print op.rjust(20), "=> [{0}]".format(tstring)
  44. print "}"
  45. def print_function(func):
  46. co = func.__code__
  47. code = co.co_code
  48. n = len(code)
  49. i = 0
  50. while i < n:
  51. op = ord(code[i])
  52. i += 1
  53. print " " * 8 + opcode.opname[op].ljust(18),
  54. if op >= opcode.HAVE_ARGUMENT:
  55. arg = _get_argument(co, code, i, op)
  56. i += 2
  57. print arg
  58. else:
  59. print
  60. def _parse_func(func, chain):
  61. co = func.__code__
  62. code = co.co_code
  63. n = len(code)
  64. i = 0
  65. lastop = MARKOV_START
  66. while i < n:
  67. op = ord(code[i])
  68. i += 1
  69. if op >= opcode.HAVE_ARGUMENT:
  70. arg = _get_argument(co, code, i, op)
  71. i += 2
  72. else:
  73. arg = None
  74. _chain_append(chain, lastop, (op, arg))
  75. lastop = op
  76. _chain_append(chain, op, (MARKOV_END, None))
  77. def _get_argument(co, code, i, op):
  78. oparg = ord(code[i]) + ord(code[i + 1]) * 256
  79. if op in opcode.hasconst:
  80. return co.co_consts[oparg]
  81. elif op in opcode.haslocal:
  82. return co.co_varnames[oparg]
  83. elif op in opcode.hascompare:
  84. return opcode.cmp_op[oparg]
  85. raise NotImplementedError(op, opcode.opname[op])
  86. def _chain_append(chain, first, second):
  87. try:
  88. chain[first].append(second)
  89. except KeyError:
  90. chain[first] = [second]
  91. def _make_codes(chain):
  92. codes = []
  93. code = random.choice(chain[MARKOV_START])
  94. constants, varnames = [], []
  95. while 1:
  96. op, arg = code
  97. if op == MARKOV_END:
  98. break
  99. codes.append(op)
  100. if op >= opcode.HAVE_ARGUMENT:
  101. if op in opcode.hasconst:
  102. if arg not in constants:
  103. constants.append(arg)
  104. args = constants
  105. elif op in opcode.haslocal:
  106. if arg not in varnames:
  107. varnames.append(arg)
  108. args = varnames
  109. elif op in opcode.hascompare:
  110. args = opcode.cmp_op
  111. else:
  112. raise NotImplementedError(op, opcode.opname[op])
  113. codes.append(args.index(arg))
  114. codes.append(0)
  115. code = random.choice(chain[op])
  116. return codes, tuple(constants), tuple(varnames)
  117. def _int_to_opname(op):
  118. if op == MARKOV_START:
  119. return "START"
  120. elif op == MARKOV_END:
  121. return "END"
  122. return opcode.opname[op]
  123. ############## FUNCTION CORPUS ################################################
  124. def f1(a):
  125. b = a + 9.0
  126. return b
  127. def f2(a):
  128. b = a - 7.0
  129. return b
  130. def f3(a):
  131. b = a * 5.0
  132. return b
  133. def f4(a):
  134. b = a / 3.0
  135. return b
  136. def f5(a):
  137. b = a ** 2.0
  138. return b
  139. def f6(a):
  140. b = a % 10.0
  141. return b
  142. corpus = [f1, f2, f3, f4, f5, f6]
  143. ############## DEMO ###########################################################
  144. if __name__ == "__main__":
  145. chain = make_chain(corpus)
  146. func = make_function(chain, "func")
  147. print "Using {0}-function corpus.".format(len(corpus))
  148. print "Smashed function disassembly:"
  149. print_function(func)
  150. print
  151. n = 12.0
  152. print "func(%s) =" % n, func(n)