ThingerConsole::parse_command declares its two helpers as static lambdas that capture by reference. Because a function-local static is constructed exactly once (on the first call) the captures in add_token and move_left bind permanently to the stack frame of that first invocation. Every subsequent call to parse_command re-uses those bindings, so command, size, argc, argv, current_arg and max_args all refer to a frame that no longer exists. The first console command after boot parses correctly; every one after that is undefined behaviour, reading and writing through dangling references.
In practice this shows up as an intermittent crash some number of commands into a session, which is easy to misattribute to whatever the device happened to be doing at the time. On an ESP32-S3 (thinger.io 2.41.0, Arduino framework) we hit Guru Meditation Error: Core 1 panic'ed (StoreProhibited) with EXCVADDR 0x00000005, store through a stale command pointer, with frame #0 inside the add_token lambda at ThingerConsole.h:332 and frame #1 in parse_command at ThingerConsole.h:373. Removing static from both lambdas resolves it; they are cheap to construct per call and the surrounding code already assumes ordinary locals. We're currently applying that as a build-time patch to the installed header.
src/ThingerConsole.h, lines 325–346 (v2.41.0):
int parse_command(char* command, size_t size, char *argv[], size_t max_args){
int argc = 0;
char* current_arg = nullptr;
bool open_quote = false;
bool scape_next = false;
static auto add_token = [&](size_t i){
command[i] = 0;
if(argc<max_args){
argv[argc++] = current_arg;
}
current_arg = nullptr;
};
static auto move_left = [&](int& i){
for(auto j=i; j<size-1; j++){
command[j] = command[j+1];
}
command[--size] = 0;
i--;
};
Fix:
- static auto add_token = [&](size_t i){
+ auto add_token = [&](size_t i){
- static auto move_left = [&](int& i){
+ auto move_left = [&](int& i){
ThingerConsole::parse_commanddeclares its two helpers as static lambdas that capture by reference. Because a function-local static is constructed exactly once (on the first call) the captures inadd_tokenandmove_leftbind permanently to the stack frame of that first invocation. Every subsequent call toparse_commandre-uses those bindings, socommand, size, argc, argv, current_arg and max_argsall refer to a frame that no longer exists. The first console command after boot parses correctly; every one after that is undefined behaviour, reading and writing through dangling references.In practice this shows up as an intermittent crash some number of commands into a session, which is easy to misattribute to whatever the device happened to be doing at the time. On an ESP32-S3 (thinger.io 2.41.0, Arduino framework) we hit
Guru Meditation Error: Core 1 panic'ed (StoreProhibited) with EXCVADDR 0x00000005, store through a stale command pointer, with frame #0 inside theadd_tokenlambda atThingerConsole.h:332and frame #1 inparse_commandatThingerConsole.h:373. Removing static from both lambdas resolves it; they are cheap to construct per call and the surrounding code already assumes ordinary locals. We're currently applying that as a build-time patch to the installed header.src/ThingerConsole.h, lines 325–346 (v2.41.0):
Fix: