Click here to Skip to main content
16,022,122 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I've been at this the whole day, and aware of the problem since yesterday.

I have an SVG parser and renderer that's very lightweight. The XML parser uses 2KB window to peephole parse the whole document. I don't even keep it on the stack. I've pruned the stack on the codepath that my troubleshooting/test SVG content is invoking to with in an inch of its life. I did so by hoisting local variables onto the heap and combining multiple parameters in function calls into single references to a struct containing many of the parameters.

It still crashes when I invoke parser. I've narrowed it down to a particular codepath that it gets to, I think.

The thing should be stack shallow, but I don't know how to measure the stack, at least on an ESP32, and the stack corruption clobbers any chance of a meaningful trace.

The thing is, it works fine on a PC.

And I can get it to limp on an ESP32 by moving the initialization to run at static initialization time. It reboots but then works. Go figure. That's not really acceptable for production, but I'm just putting it out there.

Attempts to call the parsing code from within any routine, even one I create on a thread with a ton of stack space cause the crash.

See "what have you tried."

Note the 32768 . That is the number of 32-bit machine *words* to allocate to the stack for that thread. That's 128KB. That's enough effing stack, so I'm thinking maybe that's not my problem.

But I can't really know, can I because I can't get MSVC++ on the PC (which is my alternate) to measure how much stack that codepath is using. And I certainly can't on the ESP32.

Does anyone have any ideas for next moves, or things I can investigate? It's not exactly a hard and fast programming question, and yet it is.

What I have tried:

C++
TaskHandle_t handle;
xTaskCreatePinnedToCore(loop_task,"loop_task",32768,nullptr,24,&handle,1-xTaskGetAffinity(xTaskGetCurrentTaskHandle()));


Here's the loop task.

C++
svg_image img2(doc,150,{128,128});
volatile int draw_state = 0;
#ifdef ARDUINO
static void loop_task(void* arg) {
    img2.initialize(); // causes a stack overflow.
    gfx_result r=img2.draw(((srect16)img2.bounds()).center((srect16)panel_fb.bounds()).crop((srect16)panel_fb.bounds()),
    [](const image_data& data, void* state){
        if(data.is_fill) {
            return draw::filled_rectangle(panel_fb,*data.fill.bounds,data.fill.color);
        }
        return draw::bitmap(panel_fb,data.bitmap.region->bounds().offset(data.bitmap.location),*data.bitmap.region,data.bitmap.region->bounds());
    });
    if(r!=gfx_result::success) {
        printf("draw error: %d\n",(int)r);
    }
    draw_state = 1;
    uint32_t time_ts = millis();
    while(1) {
        //loop();
        if(millis()>time_ts+150) {
            time_ts = millis();
            vTaskDelay(1);
        }
    }
}
Posted
Updated 21-Aug-24 13:03pm
v2

Re calculating the stack size in use, you could do something like this:

* Allocate global static space for a small table containing [thread ID, initial stack pointer, current stack pointer] triplets with enough slots for the maximum No.of threads.
* When the thread starts up, initialize a slot.
* upon entry to every function, update the current stack pointer for the thread in the table. This may be done with a macro that calls a small function in debug mode, but is null in release mode.
* if a stack overflow occurs, examine the table for the stack usage of the offending thread.

This uses a small amount of static global memory O(maximum No. of threads), but may slow your code significantly. This may be acceptable during development. YMMV.
 
Share this answer
 
Comments
honey the codewitch 17-Sep-24 9:49am    
I am upvoting this despite having already solved the issue - which was a memory corruption issue, despite the stack canary error - such is life on this little platform. That said, you taught me a technique, and I always appreciate that. Thanks!
I forgot to initialize a field. The error was spurious. It wasn't a stack error. It was memory corruption, despite the error.
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900