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.

func_smash.py 4.7 KiB

12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  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 = []
  41. for optarget, count in targets.iteritems():
  42. if count == 1:
  43. targs.append(optarget)
  44. else:
  45. targs.append("{0}x {1}".format(count, optarget))
  46. targs.sort()
  47. print op.rjust(20), "=> [{0}]".format(", ".join(targs))
  48. print "}"
  49. def print_function(func):
  50. co = func.__code__
  51. code = co.co_code
  52. n = len(code)
  53. i = 0
  54. while i < n:
  55. op = ord(code[i])
  56. i += 1
  57. print opcode.opname[op].rjust(20),
  58. if op >= opcode.HAVE_ARGUMENT:
  59. arg = _get_argument(co, code, i, op)
  60. i += 2
  61. print " ({0})".format(arg)
  62. else:
  63. print
  64. def _parse_func(func, chain):
  65. co = func.__code__
  66. code = co.co_code
  67. n = len(code)
  68. i = 0
  69. lastop = MARKOV_START
  70. while i < n:
  71. op = ord(code[i])
  72. i += 1
  73. if op >= opcode.HAVE_ARGUMENT:
  74. arg = _get_argument(co, code, i, op)
  75. i += 2
  76. else:
  77. arg = None
  78. _chain_append(chain, lastop, (op, arg))
  79. lastop = op
  80. _chain_append(chain, op, (MARKOV_END, None))
  81. def _get_argument(co, code, i, op):
  82. oparg = ord(code[i]) + ord(code[i + 1]) * 256
  83. if op in opcode.hasconst:
  84. return co.co_consts[oparg]
  85. elif op in opcode.haslocal:
  86. return co.co_varnames[oparg]
  87. elif op in opcode.hascompare:
  88. return opcode.cmp_op[oparg]
  89. raise NotImplementedError(op, opcode.opname[op])
  90. def _chain_append(chain, first, second):
  91. try:
  92. chain[first].append(second)
  93. except KeyError:
  94. chain[first] = [second]
  95. def _make_codes(chain):
  96. codes = []
  97. code = random.choice(chain[MARKOV_START])
  98. constants, varnames = [], []
  99. while 1:
  100. op, arg = code
  101. if op == MARKOV_END:
  102. break
  103. codes.append(op)
  104. if op >= opcode.HAVE_ARGUMENT:
  105. if op in opcode.hasconst:
  106. if arg not in constants:
  107. constants.append(arg)
  108. args = constants
  109. elif op in opcode.haslocal:
  110. if arg not in varnames:
  111. varnames.append(arg)
  112. args = varnames
  113. elif op in opcode.hascompare:
  114. args = opcode.cmp_op
  115. else:
  116. raise NotImplementedError(op, opcode.opname[op])
  117. codes.append(args.index(arg) % 256)
  118. codes.append(args.index(arg) // 256)
  119. code = random.choice(chain[op])
  120. return codes, tuple(constants), tuple(varnames)
  121. def _int_to_opname(op):
  122. if op == MARKOV_START:
  123. return "START"
  124. elif op == MARKOV_END:
  125. return "END"
  126. return opcode.opname[op]
  127. ############## FUNCTION CORPUS ################################################
  128. def f1(a):
  129. b = a + 9.0
  130. return b
  131. def f2(a):
  132. b = a - 7.0
  133. return b
  134. def f3(a):
  135. b = a * 5.0
  136. return b
  137. def f4(a):
  138. b = a / 3.0
  139. return b
  140. def f5(a):
  141. b = a ** 2.0
  142. return b
  143. def f6(a):
  144. b = a % 10.0
  145. return b
  146. corpus = [f1, f2, f3, f4, f5, f6]
  147. ############## DEMO ###########################################################
  148. if __name__ == "__main__":
  149. chain = make_chain(corpus)
  150. func = make_function(chain, "func")
  151. print "Using {0}-function corpus.".format(len(corpus))
  152. print "Smashed function disassembly:"
  153. print_function(func)
  154. print
  155. n = 12.0
  156. print "func(%s) =" % n, func(n)