From 074fb8824a84d6eb4be889bef5765ae0fa06f786 Mon Sep 17 00:00:00 2001 From: makermelissa-piclaw Date: Sat, 23 May 2026 16:58:50 -0700 Subject: [PATCH] dotclockframebuffer: fix gpio_data range validation The upper-bound expression used `max_bit * 8` instead of `gpio_data_len * 8`. With `gpio_data_len = 1` (the common case), `max_bit` is 7 and the shift becomes `(1 << 56) - 1`, which is undefined behavior on a 32-bit `mp_int_t`. In practice the upper bound wraps to 1, so any `gpio_data` value > 1 raises `ValueError: gpio_data must be 0..1` even though a full byte is legitimate. This blocks initializing displays through `dotclockframebuffer.ioexpander_send_init_sequence(...)` when the init sequence contains real one-byte register writes; e.g. the Adafruit Qualia ESP32-S3 + 4" 480x480 round TFT crashes during display init. The fix is to use `gpio_data_len` (which is already the field width in bytes) directly. For `gpio_data_len = 1` this gives the correct `(1 << 8) - 1 = 255` upper bound. --- shared-bindings/dotclockframebuffer/__init__.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-bindings/dotclockframebuffer/__init__.c b/shared-bindings/dotclockframebuffer/__init__.c index b8dbf8c1897b8..700cd06717815 100644 --- a/shared-bindings/dotclockframebuffer/__init__.c +++ b/shared-bindings/dotclockframebuffer/__init__.c @@ -104,7 +104,7 @@ static mp_obj_t ioexpander_send_init_sequence(size_t n_args, const mp_obj_t *pos mp_arg_validate_int_range(cs_bit, 0, max_bit, MP_QSTR_cs_bit); mp_arg_validate_int_range(mosi_bit, 0, max_bit, MP_QSTR_mosi_bit); mp_arg_validate_int_range(clk_bit, 0, max_bit, MP_QSTR_clk_bit); - mp_arg_validate_int_range(gpio_data, 0, (1 << (max_bit * 8)) - 1, MP_QSTR_gpio_data); + mp_arg_validate_int_range(gpio_data, 0, (1 << (gpio_data_len * 8)) - 1, MP_QSTR_gpio_data); mp_int_t reset_mask = 0; if (args[ARG_reset_bit].u_obj != MP_ROM_NONE) { mp_int_t reset_bit = mp_arg_validate_int_range(mp_arg_validate_type_int(args[ARG_reset_bit].u_obj, MP_QSTR_reset_bit), 0, max_bit, MP_QSTR_reset_bit);