PlatformIO cannot handle exceptions with ESP8266

I would like to use exceptions handling in my code. Please, do not try to clarify me, how it is not proper way of error states handling with low performance devices. The same code, that works fine in Arduino IDE does not works with PlatformIO even though I tried hard to use the same libraries.

Somebody some ideas?

See the code example:

#include <Arduino.h>
#include <iostream>
#include <exception>

using namespace std; 

void func(void) {
    throw runtime_error("exception thrown.");
}

void setup() { 
    Serial.begin(115200);
    delay(200);
  
    cout << "Program started." << endl;
    try {
        func();
    } catch (const exception& e) {
        cout << "exception caught: " << e.what() << endl;
    }
    Serial.println("Program continues");
}

void loop() {
    while(true) {
        yield();
    }
}

The result of code running in Arduino:

11:50:43.980 → Program started.
11:50:44.034 → exception caught: exception thrown.
11:50:44.034 → Program continues

The result of the same code compiled and started in PlatformIO (VS Code):

Program started.

User exception (panic/abort/assert)
--------------- CUT HERE FOR EXCEPTION DECODER ---------------

Abort called

stack>>>

ctx: cont
sp: 3ffffe60 end: 3fffffc0 offset: 0000
3ffffe60: 00000000 00000000 00000000 00000000
3ffffe70: 000000fe 00000000 00000000 00000000
3ffffe80: 00000000 00000000 00000000 b8b1aabc
3ffffe90: 3fff0230 3fff1aac 00000000 3ffeee40
3ffffea0: 3ffeedd8 3ffef348 3fff1adc 40201f12
3ffffeb0: 00000000 00000000 00000000 40201f24
3ffffec0: 00000000 3fffff5c 00000000 402018e9
3ffffed0: 3fffff54 00000000 00000000 00000000
3ffffee0: 00000000 00000000 00000000 40212d30
3ffffef0: 00000000 3ffeee40 3ffeedd8 40212d41
3fffff00: 3fff1adc 3fff1aac 3fff1adc 40213534
3fffff10: 00000000 00000000 3fff1adc 402018f4
3fffff20: 40000000 00000000 00000000 00000000
3fffff30: 00000000 00000000 00000000 40212d30
3fffff40: 3ffeedd8 3ffeee40 3ffeedd8 40212d41
3fffff50: 3fff1adc 40213468 3fff1adc 402134df
3fffff60: f3f2f101 3ffef348 3fff1afc 40201060
3fffff70: 3fff1b18 3ffef348 3ffefe38 402147fe
3fffff80: 3fffdad0 3ffef348 3ffeedd8 402010e2
3fffff90: feefeffe feefeffe feefeffe feefeffe
3fffffa0: 3fffdad0 00000000 3ffeee00 40201b20
3fffffb0: feefeffe feefeffe 3ffe85b4 40100c11
<<<stack<<<

--------------- CUT HERE FOR EXCEPTION DECODER ---------------

ets Jan 8 2013,rst cause:2, boot mode:(3,6)

load 0x4010f000, len 3584, room 16
tail 0
chksum 0xb0
csum 0xb0
v2843a5ac
~ld
Program started.

… all repeats again and again…

My platformio.ini file:

[env:d1_develop]
platform = espressif8266
board = d1_mini_lite
framework = arduino
upload_speed = 921600
monitor_speed = 115200
build_flags = -std=c++11 -fexceptions
build_unflags = -fno-exceptions

Arduino configuration:


PlatformIO configuration:

Verbose mode can be enabled via -v, --verbose option
CONFIGURATION: Redirecting...
PLATFORM: Espressif 8266 (2.6.2+sha.d7b1989) > WeMos D1 mini Lite
HARDWARE: ESP8266 80MHz, 80KB RAM, 1MB Flash
PACKAGES:

  • framework-arduinoespressif8266 3.20704.0 (2.7.4)
  • tool-esptool 1.413.0 (4.13)
  • tool-esptoolpy 1.20800.0 (2.8.0)
  • tool-mklittlefs 1.203.200522 (2.3)
  • tool-mkspiffs 1.200.0 (2.0)
  • toolchain-xtensa 2.40802.200502 (4.8.2)
    LDF: Library Dependency Finder → Library Dependency Finder (LDF) — PlatformIO latest documentation
    LDF Modes: Finder ~ chain, Compatibility ~ soft
    Found 32 compatible libraries
    Scanning dependencies…
    No dependencies
    Building in release mode
    Retrieving maximum program size .pio\build\d1_develop\firmware.elf
    Checking size .pio\build\d1_develop\firmware.elf
    Advanced Memory Usage is available via “PlatformIO Home > Project Inspect”
    RAM: [==== ] 42.5% (used 34780 bytes from 81920 bytes)
    Flash: [==== ] 41.1% (used 394128 bytes from 958448 bytes)
    Configuring upload protocol…
    AVAILABLE: espota, esptool
    CURRENT: upload_protocol = esptool
    Looking for upload port…
    Auto-detected: COM3
    Uploading .pio\build\d1_develop\firmware.bin
    esptool.py v2.8
    Serial port COM3
    Connecting…
    Chip is ESP8266EX
    Features: WiFi
    Crystal is 26MHz
    MAC: a0:20:a6:17:3e:58
    Uploading stub…
    Running stub…
    Stub running…
    Changing baud rate to 921600
    Changed.
    Configuring flash size…
    Auto-detected Flash size: 4MB
    Flash params set to 0x0340
    Compressed 398288 bytes to 267031…

Writing at 0x00000000… (5 %)
Writing at 0x00004000… (11 %)
Writing at 0x00008000… (17 %)
Writing at 0x0000c000… (23 %)
Writing at 0x00010000… (29 %)
Writing at 0x00014000… (35 %)
Writing at 0x00018000… (41 %)
Writing at 0x0001c000… (47 %)
Writing at 0x00020000… (52 %)
Writing at 0x00024000… (58 %)
Writing at 0x00028000… (64 %)
Writing at 0x0002c000… (70 %)
Writing at 0x00030000… (76 %)
Writing at 0x00034000… (82 %)
Writing at 0x00038000… (88 %)
Writing at 0x0003c000… (94 %)
Writing at 0x00040000… (100 %)
Wrote 398288 bytes (267031 compressed) at 0x00000000 in 3.7 seconds (effective 864.9 kbit/s)…
Hash of data verified.

Leaving…
Hard resetting via RTS pin…
================================================= [SUCCESS] Took 7.81 seconds =================================================
— Available filters and text transformations: colorize, debug, default, direct, esp8266_exception_decoder, hexlify, log2file, nocontrol, printable, send_on_enter, time
— More details at Redirecting...
— Miniterm on COM3 115200,8,N,1 —
— Quit: Ctrl+C | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H —
Program started.

User exception (panic/abort/assert)

Seems like a clear bug to me in the PlatformIO ESP8266 builder code. I recall a similiar issue of an exception causing a direct abort() call, due to improper order of linking libraries: Move crtend files to end of link command to prevent exceptions causing fatal sys_exit by nmaitland · Pull Request #33 · sipeed/platform-kendryte210 · GitHub

I’ll try and reproduce the issue and if yes, this bug report should go to the developers at Issues · platformio/platform-espressif8266 · GitHub

Thank you, Max. May I be somewhat helpful? I can send you build log from both Arduino and PlatformIO, for example.

Well, that was easy. When sifting through the Arduino IDE linker commands it because apparent…

The linker flags in the Arduino IDE, with exceptions enabled, read:

-lhal -lphy -lpp -lnet80211 -llwip2-536-feat -lwpa -lcrypto -lmain -lwps -lbearssl -laxtls -lespnow -lsmartconfig -lairkiss -lwpa2 -lstdc++-exc -lm -lc -lgcc -Wl,--end-group

Notice the -lstdc++-exc library in there… well PlatformIO does

…just a linking with stdc++ instead of stdc++-exc in all cases.

Replacing stdc++ with stdc++-exc immediately makes the firmware work with PlatformIO (in C:\Users\<user>\.platformio\packages\framework-arduinoespressif8266\tools\platformio-build.py)

I’ll propose a patch into GitHub - platformio/platform-espressif8266: Espressif 8266: development platform for PlatformIO to get this working.

1 Like

Great! It is working.

I was trying to compare verbose compiling output from Arduino and PlatformIO, but I started from beginning and after couple of commands I gave up. And linker commands are apparently in the end.

Thank you for the solution. You saved me branching my project and and replacing all exceptions with some returns and their handling.

1 Like

I’ve opened Exceptions are not enabled correctly for Arduino-ESP8266 · Issue #237 · platformio/platform-espressif8266 · GitHub so that this is tracked and finally fixed properly.

It is not working in my case.
I have C/C++ extension version 1.6.0
Platformio.ini:
[env:esp12e]
platform = espressif8266
board = esp12e
framework = arduino
lib_deps =
knolleary/PubSubClient@^2.8
m5ez/ezTime@^0.8.3
ropg/ezTime@^0.8.3
adafruit/Adafruit BMP280 Library@^2.4.2
adafruit/Adafruit MCP3008@^1.3.1
build_unflags =
-fno-exceptions
build_flags = -D UPLOAD_SPEED=${upload_settings.upload_speed}
-D MONITOR_SPEED=${upload_settings.monitor_speed}
-std=c++11
-fexceptions
extends = upload_settings

try …catch block:
try
{
Serial.println(" checking _bmpInited");
if(_bmpInited != _NULL)
Serial.printf(“_bmpInited %d \n”, _bmpInited);
}
catch (const std::exception& e)
{
Serial.printf(“Attempted read _bmpInited %s \n”, e.what());
}
catch (…)
{
Serial.println(“attempt at _bmpInited:Exception for unknown reason”);
}
platformio-build.py fragment:

Exceptions

if “PIO_FRAMEWORK_ARDUINO_ENABLE_EXCEPTIONS” in flatten_cppdefines:
env.Append(
CXXFLAGS=[“-fexceptions”],
LIBS=[“stdc+±exc”]
)
else:
env.Append(
CXXFLAGS=[“-fno-exceptions”],
LIBS=[“stdc++”]
)
and still, I observe this:
3ffff3a0: feefeffe feefeffe feefeffe feefeffe
3ffff3b���In BMP280Temperature constructor
checking _bmpInited

--------------- CUT HERE FOR EXCEPTION DECODER ---------------

Exception (28):
epc1=0x40204040 epc2=0x00000000 epc3=0x00000000 excvaddr=0x00000000 depc=0x00000000

stack>>>

ctx: sys
sp: 3fffe870 end: 3fffffb0 offset: 0190
3fffea00: 3ffee3bc 3ffee994 3ffeeac8 4020403e
3fffea10: 00000000 000e000f 00000000 402088a3

You don’t need to unflags fno-exceptions and then build_flag it back in, as you correctly quoted in the builder script, what matters is that build_flags has the -DPIO_FRAMEWORK_ARDUINO_ENABLE_EXCEPTIONS flag, which you don’t have in your configuration.

Do

; no build_unflags
build_flags = 
   -D UPLOAD_SPEED=${upload_settings.upload_speed}
   -D MONITOR_SPEED=${upload_settings.monitor_speed}
   -std=c++11
   -DPIO_FRAMEWORK_ARDUINO_ENABLE_EXCEPTIONS 
2 Likes

Done. Still the same picture.

Everything is working as expected.

[env:nodemcuv2]
platform = espressif8266
board = nodemcuv2
framework = arduino
monitor_speed = 74880
build_flags =
   -DPIO_FRAMEWORK_ARDUINO_ENABLE_EXCEPTIONS
#include <Arduino.h>
#include <stdexcept>

void setup() {
        Serial.begin(74880);
        delay(500);
        Serial.println("Testing exceptions now!!");

        try
        {
                Serial.println("Throwing exception on purpose.");
                throw std::runtime_error("Shit happened");
        }
        catch (const std::exception& e)
        {
                Serial.printf("Exception thrown: \"%s\"", e.what());
        }
        catch (...)
        {
                Serial.println("Other exception thrown.");
        }
}

void loop() {}
>pio run -t upload -t monitor
...
--- Miniterm on COM4  74880,8,N,1 ---
--- Quit: Ctrl+C | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ---
2���0b8, len 40, room 4
tail 4
chksum 0xc9
csum 0xc9
v0004cb90
~ld
Testing exceptions now!!
Throwing exception on purpose.
Exception thrown: "Shit happened"
--- exit ---

You may have corrupted the platform or Arduino core package. Remove all C:\Users\<user>\.platformio\platforms\espressif8266* folders and C:\Users\<user>\.platformio\packages\framework-arduinoespressif8266. Open a CLI and execute

pio upgrade --dev
pio platform install espressif8266
pio platform update espressif8266

to update the PIO core and reinstall the platform. Then retry.

Thank you Max!
The reason it didn’t work in my case was as follows.
I defined a static member as a bool& in a class and initialized it in the main program. When it is
bool _bmpInited = false;
bool& BMP280Temperature::_bmpInited = _bmpInited;
It generates exceptions downstream but exception handling fails.
When I only rename the variable like this
bool bmpInited = false;
bool& BMP280Temperature::_bmpInited = bmpInited;
all works OK.

Max, I know that this is an old post, but I just ran into this issue. FWIW, your solution fixed the issue for me!