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