MicroPython assumes valid prelude and bytecode in .mpy files
We're running MicroPython as a task in an embedded product, and feel it's relatively safe to run Python code in this sandboxed environment. It accesses the file system in a restricted context, and Python code shouldn't be able to access data outside of the MicroPython heap and data structures embedded in the firmware.
We're looking at supporting .mpy files in this environment. It seems safe to allow .mpy files created on the device and stored such that the user cannot modify the contents. We'd also like to support use of mpy-cross to compile files that require a larger heap.
But we're concerned that users could modify the .mpy file in ways that would (for example) allow for reading any memory address or overwriting areas of RAM outside of the MicroPython heap or its task's stack.
I've been looking at file contents outside of the actual bytecode to begin with, and would like to implement some sanity checks on some values. For example, n_def_pos_args must be <= n_pos_args. And it looks like n_state should be at least n_pos_args + n_kwonly_args + 1.
Is it possible to calculate a value for n_exc_stack by doing a validation pass on the bytecode? Or even a sanity check on the three _args settings (ensure the bytecode doesn't reference an arg index beyond what's configured)? Are there other checks we could perform?
I feel that it's better to add this burden to the import phase and reject invalid .mpy files instead of adding range checks to the vm.
We plan to implement these behind a MICROPY_ configuration macro and eventually submit a PR. Open to recommendations on a name for that macro.
Suggestions for documentation improvements
- MicroPython .mpy files page:
First paragraph. You should mention that boot.mpy and main.mpy are not recognised by the runtime interpreter. If you want a main.mpy a simple workaround is to rename it to, say, app.mpy and have a one line main.py that imports it.
Second paragraph. There is no mention of where to get the cross compiler. The normal way is to set up a MicroPython build environment on your computer. However, there is a simpler way if you are not interested in frozen bytecode, namely, use one of the pre-built distributions on PyPI.
2.MicroPython libraries > sys page:
There is no mention of the sys.implementation.mpy field. A cross reference to the encoding of this field on the MicroPython .mpy files page would be useful.
- Quick reference for the ESP32 page:
The summary of the esp32 module omits several methods including wake_on_ext0() and wake on ext1().
- eps32 - functionality specific to the ESP32 page:
It is not immediately obvious how to use the wake methods together with deepsleep. A simple example would reveal all.
from machine import deepsleep, Pin
import esp32
pd = Pin(14, Pin.IN)
btn1 = Pin(33, Pin.IN, Pin.PULL_UP)
esp32.wake_on_ext0(pin = pd, level = esp32.WAKEUP_ANY_HIGH)
esp32_wake_on_ext1(pins = (btn1, ), level = esp32.WAKEUP_ALL_LOW)
deepsleep(300000)
The above example puts the device into deep sleep. It will wake up if either GPIO 14 goes high or if GPIO 33 goes low or after 5 minutes has elapsed.
Presumably the same applies to machine.lightsleep?
- Maximising MicroPython speed page:
Is use of the native and viper code emitters limited to functions or can the decorators apply to classes or indeed entire files?
Does use of the native or viper code emitters disrupt the Ctrl-C keyboard interrupt?
- General information about the ESP32 port page:
Would it be possible to provide more information about this port such as
- internal RAM usage and heap size
- default CPU clock frequency
- default internal SPIFlash clock frequency
- default external SPIRAM and SPIFlash clock frequency
- exactly what runs on each of the two cores
- how are MicroPython threads implemented