Are setjmp()/longjmp() working correctly?

取消
显示结果 
显示  仅  | 搜索替代 
您的意思是: 

Are setjmp()/longjmp() working correctly?

1,442 次查看
massimomanca
Contributor III

I am using LpcXpresso + GNU GCC + newlib-nano to write a short example to show how is possible to recover the execution from a Hard Fault (using a LPC1768). The problem is that longjmp() jumps out to the main() in startup code where I put an infinite while(1) loop instead to jump back to setjmp and choose the alternative path. Seems to me that this is a VERY BIG ERROR in the library. Any report confirming that?

#include <setjmp.h>

jmp_buf s_buf;

void printBoh(uint32_t sp, const char* str)
{
   printf("sp: %08X err: %s\r\n", sp, str);
}

void Pippo()
{
   longjmp(s_buf, 2);
}

void Start()
{
   if(!setjmp(s_buf))
      Pippo();
   else
      printBoh(0x10008000, "Hello World!");
}

int main(void)
{
   // TODO: insert code here
   Start();
   puts("End\n");
   return 0;
}‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

and this is the relevant part of the RESET handler:

__attribute__ ((section(".after_vectors")))void ResetISR(void)
{

    // Copy the data sections from flash to SRAM.
    unsigned int LoadAddr, ExeAddr, SectionLen;    
    unsigned int *SectionTableAddr;

    // Load base address of Global Section Table    
    SectionTableAddr = &__data_section_table;

    // Copy the data sections from flash to SRAM.    
    while (SectionTableAddr < &__data_section_table_end)
    {        
        LoadAddr = *SectionTableAddr++;        
        ExeAddr = *SectionTableAddr++;        
        SectionLen = *SectionTableAddr++;        
        data_init(LoadAddr, ExeAddr, SectionLen);    
    }    
    // At this point, SectionTableAddr = &__bss_section_table;    
    // Zero fill the bss segment    
    while (SectionTableAddr < &__bss_section_table_end)
    {        
        ExeAddr = *SectionTableAddr++;        
        SectionLen = *SectionTableAddr++;        
        bss_init(ExeAddr, SectionLen);    
    }    
    // fill the stack with 32bit mask data to find stack corruption    
    SectionLen = (unsigned)&__stack_start - (unsigned)&__stack_end;    
    _fill(&__stack_end, SectionLen, 0xDEADBEEF);

#if defined (__USE_CMSIS) || defined (__USE_LPCOPEN)    
   SystemInit();
#endif

#if defined (__cplusplus)    // Call C++ library initialisation
   __libc_init_array();
#endif

#if defined (__REDLIB__)    // Call the Redlib library, which in turn calls main()    
   __main() ;
#else    
   main();
#endif

    // main() shouldn't return, but if it does, we'll just enter an infinite loop    
    while (1) 
    {        
       ;    
    }
}
标签 (3)
3 回复数

1,127 次查看
soledad
NXP Employee
NXP Employee

Hello Massimo,

We are discussing Internally, as soon as we got a response,  I let you know.  

1,127 次查看
massimomanca
Contributor III

Hello Soledad,

in the mean time I found the problem and the solution.

First of all the original code where I had the problem was inside a RTX task (longjmp() call) and the setjmp() was on another task (initiatorTask) that should start after reset and never return or estart.

Unfortunately a bug in the error management task restarted initiatorTask() so longjmp() can't jump back to setjmp() call  and jmp_buf content is wrong. Difficult bug to find...

Then, the code I posted was oversimplified (for obviously reasons) but is NOT CORRECT because startjmp() should be moved inside main() because longjmp() can't jump to setjmp() because Start() is already run to finish so the stack was unwinded.
Thanks for the attention, I wish you a Happy 2017.
Massimo

0 项奖励
回复

1,127 次查看
soledad
NXP Employee
NXP Employee

Hello Massimo,

I get the following answer:

Firstly, in my opition, hardfault should be rooted out instead of geting recovered.

And what's the meaning of library? LPCopen?

If so, the RESETISR will call the user defined main(), and there is no issue on this.

what will the main() do is totally up to the user.

Please help me with more information about your report.

Regards

Soledad

0 项奖励
回复