Skip to main content

Python cross-version byte-code interpeter

Project description

TravisCI CircleCI Latest Version Supported Python Versions

x-python

This is a CPython bytecode interpreter written Python.

You can use this to:

  • Learn about how the internals of CPython works since this models that

  • Experiment with additional opcodes, or ways to change the run-time environment

  • Use as a sandboxed environment for trying pieces of execution

  • Have one Python program that runs multiple versions of Python bytecode.

  • Use in a dynamic fuzzer or in coholic execution for analysis

The ability to run Python bytecode as far back as 2.5 from Python 3.7 I find pretty neat. (Even more could easily be added).

Also, The sandboxed environment in a debugger I find interesting. Since there is a separate execution, and traceback stack, inside a debugger you can try things out in the middle of a debug session without effecting the real execution. On the other hand if a sequence of executions works out, it is possible to copy this (under certain circumstances) back into CPython’s execution stack.

Going the other way, I have hooked in trepan3k into this interpreter so you have a pdb/gdb like debugger also with the ability to step bytecode instructions.

I may also experiment with faster ways to support trace callbacks such as those used in a debugger. In particular I may add a BREAKPOINT instruction to support fast breakpoints and breakpointing on a particular instruction that doesn’t happen to be on a line boundary.

Although this is far in the future, suppose you to add a race detector? It might be easier to prototype it in Python here. (This assumes the interpreter supports threading well, I suspect it doesn’t)

Another unexplored avenue implied above is mixing interpretation and direct CPython execution. In fact, there are bugs so this happens right now, but it will be turned into a feature. Some functions or classes you may want to not run under a slow interpreter while others you do want to run under the interpreter.

Examples:

What to know instructions get run when you write some simple code? Try this:

$ xpython -vc "x, y = 2, 3; x **= y"
INFO:xpython.vm:L. 1   @  0: LOAD_CONST (2, 3)
INFO:xpython.vm:       @  2: UNPACK_SEQUENCE 2
INFO:xpython.vm:       @  4: STORE_NAME (2) x
INFO:xpython.vm:       @  6: STORE_NAME (3) y
INFO:xpython.vm:L. 1   @  8: LOAD_NAME x
INFO:xpython.vm:       @ 10: LOAD_NAME y
INFO:xpython.vm:       @ 12: INPLACE_POWER (2, 3)
INFO:xpython.vm:       @ 14: STORE_NAME (8) x
INFO:xpython.vm:       @ 16: LOAD_CONST None
INFO:xpython.vm:       @ 18: RETURN_VALUE (None)

Option -c is the same as Python’s flag (program passed in as string) and -v is also analogus Python’s flag. Here, it shows the bytecode instructions run.

Note that the disassembly above in the dynamic trace above gives a little more than what you’d see from a static disassembler from Python’s dis module. In particular, the STORE_NAME instructions show the value that is store, e.g. “2” at instruction offset 4 into name x. Similarly INPLACE_POWER shows the operands, 2 and 3, which is how the value 8 is derived as the operand of the next instruction, STORE_NAME.

Want more like the execution stack stack and block stack in addition? Add another v:

$ xpython -vvc "x, y = 2, 3; x **= y"

DEBUG:xpython.vm:make_frame: code=<code object <module> at 0x7f8018507db0, file "<string x, y = 2, 3; x **= y>", line 1>, callargs={}, f_globals=(<class 'dict'>, 140188140947488), f_locals=(<class 'NoneType'>, 93856967704000)
DEBUG:xpython.vm:<Frame at 0x7f80184c1e50: '<string x, y = 2, 3; x **= y>':1 @-1>
DEBUG:xpython.vm:  frame.stack: []
DEBUG:xpython.vm:  blocks     : []
INFO:xpython.vm:L. 1   @  0: LOAD_CONST (2, 3) <module> in <string x, y = 2, 3; x **= y>:1
DEBUG:xpython.vm:  frame.stack: [(2, 3)]
DEBUG:xpython.vm:  blocks     : []
INFO:xpython.vm:       @  2: UNPACK_SEQUENCE 2 <module> in <string x, y = 2, 3; x **= y>:1
DEBUG:xpython.vm:  frame.stack: [3, 2]
DEBUG:xpython.vm:  blocks     : []
INFO:xpython.vm:       @  4: STORE_NAME (2) x <module> in <string x, y = 2, 3; x **= y>:1
DEBUG:xpython.vm:  frame.stack: [3]
DEBUG:xpython.vm:  blocks     : []
INFO:xpython.vm:       @  6: STORE_NAME (3) y <module> in <string x, y = 2, 3; x **= y>:1
DEBUG:xpython.vm:  frame.stack: []
DEBUG:xpython.vm:  blocks     : []
INFO:xpython.vm:L. 1   @  8: LOAD_NAME x <module> in <string x, y = 2, 3; x **= y>:1
DEBUG:xpython.vm:  frame.stack: [2]
DEBUG:xpython.vm:  blocks     : []
INFO:xpython.vm:       @ 10: LOAD_NAME y <module> in <string x, y = 2, 3; x **= y>:1
DEBUG:xpython.vm:  frame.stack: [2, 3]
DEBUG:xpython.vm:  blocks     : []
INFO:xpython.vm:       @ 12: INPLACE_POWER (2, 3)  <module> in <string x, y = 2, 3; x **= y>:1
DEBUG:xpython.vm:  frame.stack: [8]
DEBUG:xpython.vm:  blocks     : []
INFO:xpython.vm:       @ 14: STORE_NAME (8) x <module> in <string x, y = 2, 3; x **= y>:1
DEBUG:xpython.vm:  frame.stack: []
DEBUG:xpython.vm:  blocks     : []
INFO:xpython.vm:       @ 16: LOAD_CONST None <module> in <string x, y = 2, 3; x **= y>:1
DEBUG:xpython.vm:  frame.stack: [None]
DEBUG:xpython.vm:  blocks     : []
INFO:xpython.vm:       @ 18: RETURN_VALUE (None)  <module> in <string x, y = 2, 3; x **= y>:1

Want to see this colorized in a terminal? Use this via trepan-xpy -x: trepan-xpy-example

Suppose you have Python 2.5 bytecode (or some other bytecode) for this, but you are running Python 3.7?

$ xpython -v test/examples/assign-2.5.pyc
INFO:xpython.vm:L. 1   @  0: LOAD_CONST (2, 3)
INFO:xpython.vm:       @  3: UNPACK_SEQUENCE 2
INFO:xpython.vm:       @  6: STORE_NAME (2) x
INFO:xpython.vm:       @  9: STORE_NAME (3) y
INFO:xpython.vm:L. 2   @ 12: LOAD_NAME x
INFO:xpython.vm:       @ 15: LOAD_NAME y
INFO:xpython.vm:       @ 18: INPLACE_POWER (2, 3)
INFO:xpython.vm:       @ 19: STORE_NAME (8) x
INFO:xpython.vm:       @ 22: LOAD_CONST None
INFO:xpython.vm:       @ 25: RETURN_VALUE (None)

Not much has changed here, other then the fact that that in after 3.6 instructions are two bytes instead of 1- or 3-byte instructions.

The above examples show straight-line code, so you see all of the instructions. But don’t confuse this with a disassembler like pydisasm from xdis. The below example, with conditional branching example makes this more clear:

$ xpython -vc "x = 6 if __name__ != '__main__' else 10"
INFO:xpython.vm:L. 1   @  0: LOAD_NAME __name__
INFO:xpython.vm:       @  2: LOAD_CONST __main__
INFO:xpython.vm:       @  4: COMPARE_OP ('__main__', '__main__') !=
INFO:xpython.vm:       @  6: POP_JUMP_IF_FALSE 12
                                               ^^ Note jump below
INFO:xpython.vm:       @ 12: LOAD_CONST 10
INFO:xpython.vm:       @ 14: STORE_NAME (10) x
INFO:xpython.vm:       @ 16: LOAD_CONST None
INFO:xpython.vm:       @ 18: RETURN_VALUE (None)

Want even more status and control? See trepan-xpy.

Status:

Currently bytecode from Python versions 3.7 - 3.2, and 2.7 - 2.5 are supported. Extending to 3.8 and beyond is on hold until there is more interest, I get help, I need or there is or funding,

Whereas Byterun is loose in accepting bytecode opcodes that is invalid for particular Python but may be valid for another; x-python is more stringent. This has some pros but mostly cons. On the plus side Byterun might run certain Python 3.4 bytecode because the opcode sets are similar. However starting with Python 3.5 and beyond the likelihood happening becomes vanishingly small. And while the underlying opcode names may be the same, the semantics of the operation may change subtely. See for example https://github.com/nedbat/byterun/issues/34.

Byterun needs the kind of overhaul we have here to be able to scale to support bytecode for more Pythons, and to be able to run bytecode across different versions of Python. Specifically, you can’t rely on Python’s dis module if you expect to expect to run a bytecode other than the bytecode that the interpreter is running, or run newer “wordcode” bytecode on a “byte”-oriented byteocde, or vica versa.

In contrast, x-python there is a clear distinction between the version being interpreted and the version of Python that is running. There is tighter control of opcodes and an opcode’s implementation is kept for each Python version. So we’ll warn early when something is invalid. You can run bytecode back to Python 2.5 using Python 3.7 (largely), which is amazing give that 3.7’s native byte code is 2 bytes per instruction while 2.5’s is 1 or 3 bytes per instruction.

The “largely” part is because the interpreter has always made use of Python builtins and libraries, and for the most part these haven’t changed very much. Often, since many of the underlying builtins are the same, the interpreter can (and does) make use interpreter internals. For example, built-in functions like range() are supported this way.

So interpreting bytecode from a newer Python release than the release the Pyton interpreter is using, is often doable too. Even though Python 2.7 doesn’t support keyword-only arguments or format strings, it can still interpret bytecode created from using these constructs.

That’s possible here because these specific features are more syntactic sugar rather than extensions to the runtime. For example, format strings basically map down to using the format() function which is available on 2.7.

New features like asynchronous I/O and concurrency primatives are not in the older versions and need to be simulated. However that too is a possibility if there is interest or support.

You can run many of the tests that Python uses to test itself, (and I do!) and those work. Right now this program works best on Python up to 3.4 when life in Python was much simpler. It runs over 300 in Python’s test suite for itself without problems. For Python 3.6 the number drops down to about 237; Python 3.7 is worse still.

History

This is a fork of Byterun. which is a pure-Python implementation of a Python bytecode execution virtual machine. Net Batchelder started it (based on work from Paul Swartz) to get a better understanding of bytecodes so he could fix branch coverage bugs in coverage.py.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

x-python-1.3.1.tar.gz (124.7 kB view details)

Uploaded Source

Built Distributions

x_python-1.3.1-py3.7.egg (166.5 kB view details)

Uploaded Egg

x_python-1.3.1-py3.6.egg (166.4 kB view details)

Uploaded Egg

x_python-1.3.1-py3.5.egg (168.8 kB view details)

Uploaded Egg

x_python-1.3.1-py3.4.egg (169.3 kB view details)

Uploaded Egg

x_python-1.3.1-py3.3.egg (171.4 kB view details)

Uploaded Egg

x_python-1.3.1-py3.2.egg (167.9 kB view details)

Uploaded Egg

x_python-1.3.1-py3-none-any.whl (79.1 kB view details)

Uploaded Python 3

x_python-1.3.1-py2-none-any.whl (79.1 kB view details)

Uploaded Python 2

File details

Details for the file x-python-1.3.1.tar.gz.

File metadata

  • Download URL: x-python-1.3.1.tar.gz
  • Upload date:
  • Size: 124.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.1.1 pkginfo/1.5.0.1 requests/2.23.0 setuptools/41.2.0 requests-toolbelt/0.9.1 tqdm/4.43.0 CPython/3.7.7

File hashes

Hashes for x-python-1.3.1.tar.gz
Algorithm Hash digest
SHA256 878731ea0cd27940816085480ce09a460ab646b4632ef3766adf0b274dd40d6b
MD5 4d443fe1329bd902cee7e2c9b498e7b6
BLAKE2b-256 c4f04e1b66510b2ee6dbba0ceca8febea9efb4159eaea6efa3628d87c8e849f9

See more details on using hashes here.

File details

Details for the file x_python-1.3.1-py3.7.egg.

File metadata

  • Download URL: x_python-1.3.1-py3.7.egg
  • Upload date:
  • Size: 166.5 kB
  • Tags: Egg
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.1.1 pkginfo/1.5.0.1 requests/2.23.0 setuptools/41.2.0 requests-toolbelt/0.9.1 tqdm/4.43.0 CPython/3.7.7

File hashes

Hashes for x_python-1.3.1-py3.7.egg
Algorithm Hash digest
SHA256 5a81ab9f31464f9b646c944a25f12539644780e397fb29fa61235970d63b6b99
MD5 69d1ee5ccc8d1453c8c2a8ccbcf56b14
BLAKE2b-256 e7fb082b88fea9a9859cf415ddd7f81dbd01881da19eea5de525f8f28de152e7

See more details on using hashes here.

File details

Details for the file x_python-1.3.1-py3.6.egg.

File metadata

  • Download URL: x_python-1.3.1-py3.6.egg
  • Upload date:
  • Size: 166.4 kB
  • Tags: Egg
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.1.1 pkginfo/1.5.0.1 requests/2.23.0 setuptools/41.2.0 requests-toolbelt/0.9.1 tqdm/4.43.0 CPython/3.7.7

File hashes

Hashes for x_python-1.3.1-py3.6.egg
Algorithm Hash digest
SHA256 9babd2c2e0ae3766fd6a229ddc4570dd236b87c22378fde846d0026b607dff04
MD5 07a225a2bfd43e423c5a4cfffbbd3ec5
BLAKE2b-256 09c22b01b92b746a46de29f98a314eb587d466c631c0623907cca7e9eefc7357

See more details on using hashes here.

File details

Details for the file x_python-1.3.1-py3.5.egg.

File metadata

  • Download URL: x_python-1.3.1-py3.5.egg
  • Upload date:
  • Size: 168.8 kB
  • Tags: Egg
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.1.1 pkginfo/1.5.0.1 requests/2.23.0 setuptools/41.2.0 requests-toolbelt/0.9.1 tqdm/4.43.0 CPython/3.7.7

File hashes

Hashes for x_python-1.3.1-py3.5.egg
Algorithm Hash digest
SHA256 bc8ed6d0aa524b4eb3fa49a47f7f814014cf1e701a334c28630588134c43206a
MD5 2befb7a91302378226de0a5e510435a9
BLAKE2b-256 fdf52f016bda921ecb47c948a4e15fc3db366597dc7fe888549fc37d140a6d0f

See more details on using hashes here.

File details

Details for the file x_python-1.3.1-py3.4.egg.

File metadata

  • Download URL: x_python-1.3.1-py3.4.egg
  • Upload date:
  • Size: 169.3 kB
  • Tags: Egg
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.1.1 pkginfo/1.5.0.1 requests/2.23.0 setuptools/41.2.0 requests-toolbelt/0.9.1 tqdm/4.43.0 CPython/3.7.7

File hashes

Hashes for x_python-1.3.1-py3.4.egg
Algorithm Hash digest
SHA256 77c3d4855895f0c75f09df5c331c7ac59e87888a4a18fc3245a77d66e6e3f551
MD5 4bb6c2c229df93dc61ba21e7fd343f99
BLAKE2b-256 ce8a7b7ca53397a6df05f99db43350180dcfd0a0ffdee5bb7624f6d634e7918d

See more details on using hashes here.

File details

Details for the file x_python-1.3.1-py3.3.egg.

File metadata

  • Download URL: x_python-1.3.1-py3.3.egg
  • Upload date:
  • Size: 171.4 kB
  • Tags: Egg
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.1.1 pkginfo/1.5.0.1 requests/2.23.0 setuptools/41.2.0 requests-toolbelt/0.9.1 tqdm/4.43.0 CPython/3.7.7

File hashes

Hashes for x_python-1.3.1-py3.3.egg
Algorithm Hash digest
SHA256 31f11db427920cf4e96f58c304236ae2e918361db4ec39864536ca8fcf2e28f6
MD5 e8f11285f3bff3667aebbcce97d140dd
BLAKE2b-256 4264b9be415aab7fc07f7a6ab6ded6d87d55ed8fa31a5d4bb1af19675f075eb6

See more details on using hashes here.

File details

Details for the file x_python-1.3.1-py3.2.egg.

File metadata

  • Download URL: x_python-1.3.1-py3.2.egg
  • Upload date:
  • Size: 167.9 kB
  • Tags: Egg
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.1.1 pkginfo/1.5.0.1 requests/2.23.0 setuptools/41.2.0 requests-toolbelt/0.9.1 tqdm/4.43.0 CPython/3.7.7

File hashes

Hashes for x_python-1.3.1-py3.2.egg
Algorithm Hash digest
SHA256 daf57e526e5c01c41259d47c0683e3c1275795f6a86da0457cec211024a4d47d
MD5 a84d9ce8a3865560f4d787405b42e951
BLAKE2b-256 12bb04154b3db056eaf46d6f9f415ac6e0d0012eca46dc51b859504f9e812966

See more details on using hashes here.

File details

Details for the file x_python-1.3.1-py3-none-any.whl.

File metadata

  • Download URL: x_python-1.3.1-py3-none-any.whl
  • Upload date:
  • Size: 79.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.1.1 pkginfo/1.5.0.1 requests/2.23.0 setuptools/41.2.0 requests-toolbelt/0.9.1 tqdm/4.43.0 CPython/3.7.7

File hashes

Hashes for x_python-1.3.1-py3-none-any.whl
Algorithm Hash digest
SHA256 f2e44342b30c62a07306f081277960d4d70ef7d8e1337f71c4f2556046b8d052
MD5 9c894035b3807a17f9193f803947a1df
BLAKE2b-256 8383a6eb11b0944ad1e324a1826659e43e54515c347784d2809bb72373f513c7

See more details on using hashes here.

File details

Details for the file x_python-1.3.1-py2-none-any.whl.

File metadata

  • Download URL: x_python-1.3.1-py2-none-any.whl
  • Upload date:
  • Size: 79.1 kB
  • Tags: Python 2
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.1.1 pkginfo/1.5.0.1 requests/2.23.0 setuptools/41.2.0 requests-toolbelt/0.9.1 tqdm/4.43.0 CPython/3.7.7

File hashes

Hashes for x_python-1.3.1-py2-none-any.whl
Algorithm Hash digest
SHA256 721e053e4f52dad7b3de42ae4f739a3a49a358bb00156d9950dc14f0dd2d24c5
MD5 417c158d6b8b1416e248765fd51f6dc5
BLAKE2b-256 d89f698b6093df0fa3073f3523c962b0b543bb94593beb4bf64d566c07e59349

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page