From fece0fb43210200c2db7ca603500850534733d45 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 20 Jul 2021 17:08:22 -0700 Subject: [PATCH] Fix crash when UART construct fails After the script stops with the exception thrown the final gc_sweep will call any finalizers and they usually call deinit. deinit on invalid objects can wreak havoc by changing random memory or (hopefully) crashing. This fixes ensures the object is deinited until initialization succeeds and the object is valid. Do the same fix for I2C and SPI too. Fixes #4700 and fixes #5005 --- locale/circuitpython.pot | 17 +++++++++++------ ports/atmel-samd/common-hal/busio/I2C.c | 3 +++ ports/atmel-samd/common-hal/busio/SPI.c | 3 +++ ports/atmel-samd/common-hal/busio/UART.c | 8 ++++++++ 4 files changed, 25 insertions(+), 6 deletions(-) diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 3a0212d7fb..e96c00502c 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -143,6 +143,10 @@ msgstr "" msgid "%q must be between %d and %d" msgstr "" +#: ports/atmel-samd/common-hal/busio/UART.c +msgid "%q must be power of 2" +msgstr "" + #: py/argcheck.c msgid "%q must of type %q" msgstr "" @@ -389,6 +393,7 @@ msgstr "" msgid "All event channels in use" msgstr "" +#: ports/raspberrypi/common-hal/pulseio/PulseIn.c #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c msgid "All state machines in use" msgstr "" @@ -973,7 +978,7 @@ msgstr "" msgid "Expected an alarm" msgstr "" -#: shared-module/_pixelbuf/PixelBuf.c +#: shared-module/adafruit_pixelbuf/PixelBuf.c #, c-format msgid "Expected tuple of length %d, got %d" msgstr "" @@ -1295,7 +1300,7 @@ msgstr "" msgid "Invalid buffer size" msgstr "" -#: shared-bindings/_pixelbuf/PixelBuf.c +#: shared-bindings/adafruit_pixelbuf/PixelBuf.c msgid "Invalid byteorder string" msgstr "" @@ -1501,7 +1506,7 @@ msgstr "" msgid "Missing first_set_pin. Instruction %d sets pin(s)" msgstr "" -#: shared-bindings/displayio/Group.c +#: shared-bindings/busio/UART.c shared-bindings/displayio/Group.c msgid "Must be a %q subclass." msgstr "" @@ -2348,7 +2353,7 @@ msgstr "" msgid "Unknown system firmware error: %04x" msgstr "" -#: shared-bindings/_pixelbuf/PixelBuf.c +#: shared-bindings/adafruit_pixelbuf/PixelBuf.c #, c-format msgid "Unmatched number of items on RHS (expected %d, got %d)." msgstr "" @@ -2631,7 +2636,7 @@ msgstr "" msgid "buttons must be digitalio.DigitalInOut" msgstr "" -#: shared-bindings/_pixelbuf/PixelBuf.c +#: shared-bindings/adafruit_pixelbuf/PixelBuf.c msgid "byteorder is not a string" msgstr "" @@ -2681,7 +2686,7 @@ msgid "can't cancel self" msgstr "" #: py/obj.c py/objint.c shared-bindings/i2cperipheral/I2CPeripheral.c -#: shared-module/_pixelbuf/PixelBuf.c +#: shared-module/adafruit_pixelbuf/PixelBuf.c msgid "can't convert %q to %q" msgstr "" diff --git a/ports/atmel-samd/common-hal/busio/I2C.c b/ports/atmel-samd/common-hal/busio/I2C.c index f7b8807976..d5a8f36f6a 100644 --- a/ports/atmel-samd/common-hal/busio/I2C.c +++ b/ports/atmel-samd/common-hal/busio/I2C.c @@ -71,6 +71,9 @@ void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, const mcu_pin_obj_t *scl, const mcu_pin_obj_t *sda, uint32_t frequency, uint32_t timeout) { uint8_t sercom_index; uint32_t sda_pinmux, scl_pinmux; + + // Ensure the object starts in its deinit state. + self->sda_pin = NO_PIN; Sercom *sercom = samd_i2c_get_sercom(scl, sda, &sercom_index, &sda_pinmux, &scl_pinmux); if (sercom == NULL) { mp_raise_ValueError(translate("Invalid pins")); diff --git a/ports/atmel-samd/common-hal/busio/SPI.c b/ports/atmel-samd/common-hal/busio/SPI.c index 48ca8f843d..884c3e0414 100644 --- a/ports/atmel-samd/common-hal/busio/SPI.c +++ b/ports/atmel-samd/common-hal/busio/SPI.c @@ -92,6 +92,9 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, uint8_t miso_pad = 0; uint8_t dopo = 255; + // Ensure the object starts in its deinit state. + self->clock_pin = NO_PIN; + // Special case for SAMR21 boards. (feather_radiofruit_zigbee) #if defined(PIN_PC19F_SERCOM4_PAD0) if (miso == &pin_PC19) { diff --git a/ports/atmel-samd/common-hal/busio/UART.c b/ports/atmel-samd/common-hal/busio/UART.c index 5aa13d076d..c33bf6f440 100644 --- a/ports/atmel-samd/common-hal/busio/UART.c +++ b/ports/atmel-samd/common-hal/busio/UART.c @@ -71,6 +71,10 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self, uint32_t tx_pinmux = 0; uint8_t tx_pad = 255; // Unset pad + // Set state so the object is deinited to start. + self->rx_pin = NO_PIN; + self->tx_pin = NO_PIN; + if ((rts != NULL) || (cts != NULL) || (rs485_dir != NULL) || (rs485_invert)) { mp_raise_ValueError(translate("RTS/CTS/RS485 Not yet supported on this device")); } @@ -85,6 +89,10 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self, mp_raise_ValueError(translate("tx and rx cannot both be None")); } + if (have_rx && receiver_buffer_size > 0 && (receiver_buffer_size & (receiver_buffer_size - 1)) != 0) { + mp_raise_ValueError_varg(translate("%q must be power of 2"), MP_QSTR_receiver_buffer_size); + } + self->baudrate = baudrate; self->character_bits = bits; self->timeout_ms = timeout * 1000;