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