espressif / ESP8266_RTOS_SDK

Latest ESP8266 SDK based on FreeRTOS, esp-idf style.
http://bbs.espressif.com
Apache License 2.0
3.31k stars 1.56k forks source link

Application doesn't work with assertion level set to "disabled" (GIT8266O-839) #1262

Open klew opened 10 months ago

klew commented 10 months ago

Environment

Problem Description

Application doesn't work as expected when assertion level is set to "disabled" in menuconfig.

Expected Behavior

It should be possible to disable assertions and to have working application.

Actual Behavior

When assertion level is set to "disabled" in menuconfig, first we get linking error, which can be solved by using workaround from https://github.com/espressif/ESP8266_RTOS_SDK/issues/1260#issuecomment-1818806487

After fixing the linking problem, application build and flash successfully, however it doesn't work as expected. There are only logs visible from bootloader and then app hangs. I tried with "hello_world" example which prints on cosole and restart module evey 10 s. With assetions disabled there is no single log output and there is no restart visible at all.

Steps to repropduce

  1. Go to hello_world example
  2. Set assertion level to "disabled" in menuconfig
  3. Compile and flash

Code to reproduce this issue

hello_world example

Debug Logs

Only below log is printed. Nothign in printed from application itself. There is no ESP reset visible at all (there should be repeated bootloader log every ~10 s in hello_world example).

ets Jan  8 2013,rst cause:1, boot mode:(3,7)

load 0x40100000, len 7544, room 16 
tail 8
chksum 0xee
load 0x3ffe8408, len 24, room 0 
tail 8
chksum 0x67
load 0x3ffe8420, len 3472, room 0 
tail 0
chksum 0x5d
csum 0x5d
I (48) boot: ESP-IDF v3.4-87-g3b15c065-dirty 2nd stage bootloader
I (48) boot: compile time 11:49:54
I (51) qio_mode: Enabling default flash chip QIO
I (57) boot: SPI Speed      : 40MHz
I (63) boot: SPI Mode       : QIO
I (70) boot: SPI Flash Size : 2MB
I (76) boot: Partition Table:
I (81) boot: ## Label            Usage          Type ST Offset   Length
I (92) boot:  0 nvs              WiFi data        01 02 00009000 00006000
I (104) boot:  1 phy_init         RF data          01 01 0000f000 00001000
I (116) boot:  2 factory          factory app      00 00 00010000 000f0000
I (127) boot: End of partition table
I (134) esp_image: segment 0: paddr=0x00010010 vaddr=0x40210010 size=0x0fff0 ( 65520) map
0x40210010: _stext at ??:?

I (169) esp_image: segment 1: paddr=0x00020008 vaddr=0x40220000 size=0x02c00 ( 11264) map
I (173) esp_image: segment 2: paddr=0x00022c10 vaddr=0x3ffe8000 size=0x00370 (   880) load
I (180) esp_image: segment 3: paddr=0x00022f88 vaddr=0x40100000 size=0x00080 (   128) load
I (194) esp_image: segment 4: paddr=0x00023010 vaddr=0x40100080 size=0x03e44 ( 15940) load
I (212) boot: Loaded app from partition at offset 0x10000
Thalhammer commented 5 months ago

So I did some digging on this and the reason why the app isn't initialized (and the image is so small) is that there are a bunch of places where important code is placed inside an assert. Enabling NDEBUG turns those into noops and stuff obviously goes down the drain from there. I did a quick grep/scan of the codebase and those are the instances I could find where this presents an issue:

// components/esp8266/source/startup.c:72:    assert(base_gpio_init() == 0);
// components/esp8266/source/startup.c:75:        assert(esp_mac_init() == ESP_OK);
// components/esp8266/source/startup.c:86:    assert(esp_pthread_init() == 0);
// components/esp8266/source/startup.c:163:    assert(__esp_os_init() == 0);
// components/esp8266/source/startup.c:166:    assert(esp_newlib_init() == 0);
// components/esp8266/source/startup.c:168:    assert(xTaskCreate(user_init_entry, "uiT", ESP_TASK_MAIN_STACK, NULL, ESP_TASK_MAIN_PRIO, NULL) == pdPASS);
// components/wifi_provisioning/src/manager.c:38:#define ACQUIRE_LOCK(mux)     assert(xSemaphoreTake(mux, portMAX_DELAY) == pdTRUE)
// components/wifi_provisioning/src/manager.c:39:#define RELEASE_LOCK(mux)     assert(xSemaphoreGive(mux) == pdTRUE)
// components/wifi_provisioning/src/manager.c:624:        assert(xTaskCreate(prov_stop_task, "prov_stop_task", 4096, (void *)1,
// components/bootloader_support/src/bootloader_sha.c:36:    assert(mbedtls_sha256_starts_ret(ctx, false) == 0);
// components/bootloader_support/src/bootloader_sha.c:44:    assert(mbedtls_sha256_update_ret(ctx, data, data_len) == 0);
// components/bootloader_support/src/bootloader_sha.c:52:        assert(mbedtls_sha256_finish_ret(ctx, digest) == 0);
// components/bootloader_support/src/bootloader_sha.c:194:    assert(mbedtls_sha256_starts_ret(ctx, false) == 0);
// components/bootloader_support/src/bootloader_sha.c:202:    assert(mbedtls_sha256_update_ret(ctx, data, data_len) == 0);
// components/bootloader_support/src/bootloader_sha.c:210:        assert(mbedtls_sha256_finish_ret(ctx, digest) == 0);
// components/esp_ringbuf/ringbuf.c:1066:        configASSERT(xSemaphoreGive(pxRingbuffer->xItemsBufferedSemaphore) == pdTRUE);
// components/esp_ringbuf/ringbuf.c:1092:        configASSERT(xSemaphoreGive(pxRingbuffer->xItemsBufferedSemaphore) == pdTRUE);
// components/esp_ringbuf/ringbuf.c:1160:        configASSERT(xSemaphoreGive(pxRingbuffer->xFreeSpaceSemaphore) == pdTRUE);
// components/esp_ringbuf/ringbuf.c:1179:        configASSERT(xSemaphoreGive(pxRingbuffer->xFreeSpaceSemaphore) == pdTRUE);

However: These are only the ones I could find on a basic scan, have no idea if this list is complete. The most relevant for this issue are the ones in startup.c. The ones in wifi_provisioning are only relevant if you use it, same applies to the ones in bootloader_sha (which will break secure boot). The last ones in ringbuf.c break esp_ringbuf, but I am unsure where thats used.

I went ahead and fixed all of those (patch) and once thats done everything works correctly when NDEBUG is enabled (you also don't need the ld change anymore because now the image is big enough not to trigger that error). I then compiled my app twice, once with NDEBUG, once with silent asserts.

No NDEBUG
Memory region         Used Size  Region Size  %age Used
     iram0_0_seg:       26148 B        48 KB     53.20%
     iram0_2_seg:      420640 B     491504 B     85.58%
     dram0_0_seg:       10840 B        96 KB     11.03%
    rtc_data_seg:          0 GB        512 B      0.00%

NDEBUG
Memory region         Used Size  Region Size  %age Used
     iram0_0_seg:       26148 B        48 KB     53.20%
     iram0_2_seg:      390180 B     491504 B     79.38%
     dram0_0_seg:       10840 B        96 KB     11.03%
    rtc_data_seg:          0 GB        512 B      0.00%

Enabling NDEBUG shrunk the image by about 7% (30k), which is about what I'd expect. However you are now at the risk of hitting some assert bug that I didn't find. So unless you've run out of other stuff you can disable to reduce that size I wouldn't touch NDEBUG, even with my patch applied. If you do, make sure you retest all functions of your app to make sure it still works correctly.

I hope this helps anyone.