M5GFX icon indicating copy to clipboard operation
M5GFX copied to clipboard

ESP-IDF v5.4: array-bounds errors in common.cpp

Open jaylikesbunda opened this issue 7 months ago • 7 comments

S:/Espressif/frameworks/esp-idf-v5.4.1/components/hal/esp32c6/include/hal/gpio_ll.h: In function 'void gpio_ll_matrix_out_default(gpio_dev_t*, uint32_t)':
S:/Espressif/frameworks/esp-idf-v5.4.1/components/hal/esp32c6/include/hal/gpio_ll.h:320:5: warning: missing initializer for member 'gpio_func_out_sel_cfg_reg_t::<unnamed struct>::out_inv_sel' [-Wmissing-field-initializers]
  320 |     };
      |     ^
S:/Espressif/frameworks/esp-idf-v5.4.1/components/hal/esp32c6/include/hal/gpio_ll.h:320:5: warning: missing initializer for member 'gpio_func_out_sel_cfg_reg_t::<unnamed struct>::oen_sel' [-Wmissing-field-initializers]
S:/Espressif/frameworks/esp-idf-v5.4.1/components/hal/esp32c6/include/hal/gpio_ll.h:320:5: warning: missing initializer for member 'gpio_func_out_sel_cfg_reg_t::<unnamed struct>::oen_inv_sel' [-Wmissing-field-initializers]
S:/Espressif/frameworks/esp-idf-v5.4.1/components/hal/esp32c6/include/hal/gpio_ll.h:320:5: warning: missing initializer for member 'gpio_func_out_sel_cfg_reg_t::<unnamed struct>::reserved_11' [-Wmissing-field-initializers]
S:/GhostESP2/Ghost_ESP/components/M5GFX/src/lgfx/v1/platforms/esp32/common.cpp: In function 'cpp::bitwizeshift::result<void, lgfx::v1::error_t> lgfx::v1::spi::init(int, int, int, int, int)':
S:/GhostESP2/Ghost_ESP/components/M5GFX/src/lgfx/v1/platforms/esp32/common.cpp:608:7: error: array subscript 0 is outside array bounds of 'volatile uint32_t [0]' [-Werror=array-bounds=]
  608 |       *reg(SPI_USER_REG(spi_port)) = SPI_USR_MOSI | SPI_USR_MISO | SPI_DOUTDIN;  // need SD card access (full duplex setting)
      |       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
cc1plus.exe: note: source object is likely at address zero
S:/GhostESP2/Ghost_ESP/components/M5GFX/src/lgfx/v1/platforms/esp32/common.cpp: In function 'void lgfx::v1::spi::beginTransaction(int, uint32_t, int)':
S:/GhostESP2/Ghost_ESP/components/M5GFX/src/lgfx/v1/platforms/esp32/common.cpp:693:7: error: array subscript 0 is outside array bounds of 'volatile uint32_t [0]' [-Werror=array-bounds=]
  693 |       *reg(SPI_USER_REG(spi_port)) = user;
      |       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
cc1plus.exe: note: source object is likely at address zero
S:/GhostESP2/Ghost_ESP/components/M5GFX/src/lgfx/v1/platforms/esp32/common.cpp:697:7: error: array subscript 0 is outside array bounds of 'volatile uint32_t [0]' [-Werror=array-bounds=]
  697 |       *reg(SPI_MISC_REG( spi_port)) = pin;
      |       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cc1plus.exe: note: source object is likely at address zero
S:/GhostESP2/Ghost_ESP/components/M5GFX/src/lgfx/v1/platforms/esp32/common.cpp:699:7: error: array subscript 0 is outside array bounds of 'volatile uint32_t [0]' [-Werror=array-bounds=]
  699 |       *reg(SPI_CLOCK_REG(spi_port)) = clkdiv;
      |       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cc1plus.exe: note: source object is likely at address zero
S:/GhostESP2/Ghost_ESP/components/M5GFX/src/lgfx/v1/platforms/esp32/common.cpp: In function 'void lgfx::v1::spi::writeBytes(int, const uint8_t*, size_t)':
S:/GhostESP2/Ghost_ESP/components/M5GFX/src/lgfx/v1/platforms/esp32/common.cpp:729:7: error: array subscript 0 is outside array bounds of 'volatile uint32_t [0]' [-Werror=array-bounds=]
  729 |       *reg(SPI_MOSI_DLEN_REG(spi_port)) = (len << 3) - 1;
      |       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cc1plus.exe: note: source object is likely at address zero
S:/GhostESP2/Ghost_ESP/components/M5GFX/src/lgfx/v1/platforms/esp32/common.cpp: In function 'void lgfx::v1::spi::readBytes(int, uint8_t*, size_t)':
S:/GhostESP2/Ghost_ESP/components/M5GFX/src/lgfx/v1/platforms/esp32/common.cpp:740:7: error: array subscript 0 is outside array bounds of 'volatile uint32_t [0]' [-Werror=array-bounds=]
  740 |       *reg(SPI_MOSI_DLEN_REG(spi_port)) = (len << 3) - 1;
      |       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cc1plus.exe: note: source object is likely at address zero

jaylikesbunda avatar May 17 '25 00:05 jaylikesbunda

SoC ?

lovyan03 avatar May 17 '25 00:05 lovyan03

SoC ?

seems to be mainly c5 and c6

jaylikesbunda avatar May 17 '25 01:05 jaylikesbunda

Hello, @jaylikesbunda I just update release v0.2.9.

Perhaps this issue has been solved.

lovyan03 avatar May 28 '25 08:05 lovyan03

unfortunately not, this is trying with the c5

In file included from S:/GhostESP2/Ghost_ESP/components/M5GFX/src/lgfx/v1/platforms/common.hpp:22,
                 from S:/GhostESP2/Ghost_ESP/components/M5GFX/src/lgfx/v1/lgfx_fonts.cpp:3:
S:/GhostESP2/Ghost_ESP/components/M5GFX/src/lgfx/v1/platforms/esp32/common.hpp: In function 'volatile uint32_t* lgfx::v1::get_gpio_hi_reg(int_fast8_t)':
S:/GhostESP2/Ghost_ESP/components/M5GFX/src/lgfx/v1/platforms/esp32/common.hpp:144:89: error: conditional expression between distinct pointer types 'volatile uint32_t*' {aka 'volatile long unsigned int*'} and 'volatile gpio_out_w1ts_reg_t*' lacks a cast
  144 |   static inline volatile uint32_t* get_gpio_hi_reg(int_fast8_t pin) { return (pin & 32) ? &GPIO.out1_w1ts.val : &GPIO.out_w1ts; }
      |                                                                              ~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
S:/GhostESP2/Ghost_ESP/components/M5GFX/src/lgfx/v1/platforms/esp32/common.hpp:144:89: error: invalid conversion from 'volatile void*' to 'volatile uint32_t*' {aka 'volatile long unsigned int*'} [-fpermissive]
  144 |   static inline volatile uint32_t* get_gpio_hi_reg(int_fast8_t pin) { return (pin & 32) ? &GPIO.out1_w1ts.val : &GPIO.out_w1ts; }
      |                                                                              ~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      |                                                                                         |
      |                                                                                         volatile void*
S:/GhostESP2/Ghost_ESP/components/M5GFX/src/lgfx/v1/platforms/esp32/common.hpp: In function 'volatile uint32_t* lgfx::v1::get_gpio_lo_reg(int_fast8_t)':
S:/GhostESP2/Ghost_ESP/components/M5GFX/src/lgfx/v1/platforms/esp32/common.hpp:146:89: error: conditional expression between distinct pointer types 'volatile uint32_t*' {aka 'volatile long unsigned int*'} and 'volatile gpio_out_w1tc_reg_t*' lacks a cast
  146 |   static inline volatile uint32_t* get_gpio_lo_reg(int_fast8_t pin) { return (pin & 32) ? &GPIO.out1_w1tc.val : &GPIO.out_w1tc; }
      |                                                                              ~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
S:/GhostESP2/Ghost_ESP/components/M5GFX/src/lgfx/v1/platforms/esp32/common.hpp:146:89: error: invalid conversion from 'volatile void*' to 'volatile uint32_t*' {aka 'volatile long unsigned int*'} [-fpermissive]
  146 |   static inline volatile uint32_t* get_gpio_lo_reg(int_fast8_t pin) { return (pin & 32) ? &GPIO.out1_w1tc.val : &GPIO.out_w1tc; }
      |                                                                              ~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      |                                                                                         |
      |                                                                                         volatile void*
S:/GhostESP2/Ghost_ESP/components/M5GFX/src/lgfx/v1/platforms/esp32/common.hpp: In function 'bool lgfx::v1::gpio_in(int_fast8_t)':
S:/GhostESP2/Ghost_ESP/components/M5GFX/src/lgfx/v1/platforms/esp32/common.hpp:148:79: error: 'volatile union gpio_in1_reg_t' has no member named 'data'
  148 |   static inline bool gpio_in(int_fast8_t pin) { return ((pin & 32) ? GPIO.in1.data : GPIO.in) & (1 << (pin & 31)); }
      |

jaylikesbunda avatar May 29 '25 02:05 jaylikesbunda

I don't understand M5Stack products that use ESP32C5. What is the hardware configuration?

lovyan03 avatar May 29 '25 02:05 lovyan03

Issue Title

Compilation error due to out-of-bounds array access in Bus_SPI.cpp with ESP-IDF v5.4.1 on M5Tab5 (ESP32P4)

Description

When compiling M5GFX with ESP-IDF v5.4.1 for the M5Tab5 device (which uses ESP32P4), I encountered the following compilation errors:

X/Tab5P4Demo/components/M5GFX/src/lgfx/v1/platforms/esp32/Bus_SPI.cpp: In member function 'virtual void lgfx::v1::Bus_SPI::endRead()':
X/Tab5P4Demo/components/M5GFX/src/lgfx/v1/platforms/esp32/Bus_SPI.cpp:884:5: error: array subscript 0 is outside array bounds of 'volatile uint32_t [0]' [-Werror=array-bounds=]
884 | *reg(SPI_PIN_REG(_spi_port)) = pin;
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
cc1plus: note: source object is likely at address zero
X/Tab5P4Demo/components/M5GFX/src/lgfx/v1/platforms/esp32/Bus_SPI.cpp: In member function 'virtual void lgfx::v1::Bus_SPI::beginRead()':
X/Tab5P4Demo/components/M5GFX/src/lgfx/v1/platforms/esp32/Bus_SPI.cpp:873:5: error: array subscript 0 is outside array bounds of 'volatile uint32_t [0]' [-Werror=array-bounds=]
873 | *reg(SPI_PIN_REG(_spi_port)) = pin;
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
cc1plus: note: source object is likely at address zero
cc1plus: some warnings being treated as errors

This is caused by the macro SPI_PIN_REG(_spi_port) returning an invalid address or an empty array for _spi_port values < 2, resulting in illegal array subscripting that GCC catches as an error (-Werror=array-bounds). By the way, I use the file "sdkconfig" in Tab5UserDemo.

Cause

The issue arises because the base register definition and reg() macro in Bus_SPI.cpp only expect SPI ports >= 2. leading to illegal accesses.

Workaround / Fix

I modified the beginRead() and endRead() functions to check if _spi_port is 2 or greater, and only then access the SPI_PIN_REG and SPI_CLOCK_REG registers:

/*REG_SPI_BASE in soc.h ⬇️*/
#define REG_SPI_BASE(i)                         (((i)>=2) ? (DR_REG_SPI2_BASE + (i-2) * 0x1000) : (0))    // GPSPI2 and GPSPI3
// ============
/*Bus_SPI.cpp*/
void Bus_SPI::beginRead(void)
{
  uint32_t pin = (_cfg.spi_mode & 2) ? SPI_CK_IDLE_EDGE : 0;
  uint32_t user = ((_cfg.spi_mode == 1 || _cfg.spi_mode == 2) ? SPI_CK_OUT_EDGE | SPI_USR_MISO : SPI_USR_MISO)
                      | (_cfg.spi_3wire ? SPI_SIO : 0);
  dc_control(true);
  *_spi_user_reg = user;

  // Add condition to prevent invalid register access for spi_port >= 2
  if (_spi_port >= 2) {
    *reg(SPI_PIN_REG(_spi_port)) = pin;
    *reg(SPI_CLOCK_REG(_spi_port)) = _clkdiv_read;
  }
#if defined ( SPI_UPDATE )
  *_spi_cmd_reg = SPI_UPDATE;
#endif
}

void Bus_SPI::endRead(void)
{
  uint32_t pin = (_cfg.spi_mode & 2) ? SPI_CK_IDLE_EDGE : 0;
  *_spi_user_reg = _user_reg;

  if (_spi_port >= 2) {
    *reg(SPI_PIN_REG(_spi_port)) = pin;
    *reg(SPI_CLOCK_REG(_spi_port)) = _clkdiv_write;
  }
#if defined ( SPI_UPDATE )
  *_spi_cmd_reg = SPI_UPDATE;
#endif
}

With this change, the illegal memory access is avoided and the code compiles successfully.

Request

Could the maintainers consider adding this conditional check or a more robust way to handle SPI ports on ESP32P4 to the official M5GFX codebase? This will improve compatibility with ESP-IDF v5.4.1 and ESP32P4 hardware.


@lovyan03 Please let me know if you need any further details or testing results from my side. Thank you very much for your attention and support.

nanshenwei avatar Jun 09 '25 02:06 nanshenwei

@nanshenwei Thank you for the detailed information ! A mechanism to avoid the problem has been implemented in the develop branch, so please try it out. Although I think the idea of ​​avoiding a setting value of less than 2 by using an if statement condition is great, careful consideration is needed as it is unclear whether 2 will be sufficient for future ESP32 series.

lovyan03 avatar Jun 09 '25 11:06 lovyan03