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.

125 lines
3.5 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. 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)