Stack overflow

In RTOses, for example vxworks, when we create a task, stacking is indicated. Can we write a routine in C that checks if the stack is full or not for a task?

+2


source to share


7 replies


Have a look at your compiler and they often allow you to add prelude functions to do this, or they might even test it yourself if you're not manipulating the stack pointer register.

And check if the operating system allows you to install "security pages". Mark the last page on the thread stack as unreadable / non-writable and catch the SIGSEGV signal and use the OS / CPU specific way to see if the protection page has failed. To do this, you must make sure that the stack frame of the function (the stack passed parameters, local variables and alloca allocated space) is always less than the page size, otherwise you can skip the "guard page". This is the best way to deal with this, since during normal processing it has no overhead at runtime.



You can see that this is very OS / CPU / compiler dependent. But I'm sure Google will find useful code and helpers for this technique for all systems, as it is a fairly common technique for low-level programmers (e.g. executable commands or interpreter developers).

+4


source


If you know how big the stack is, and if you're careful, then yes (but not portable). If there is no other way to get the base address of the stack, you need to write the address of the stack variable in the main thread function; this gives you the approximate top of the stack. Then, in your check function, you take the address of the local variable; this gives you the bottom of the stack. If the difference between the top and bottom is your stack size, it's time to get worried; if the difference is larger than the stack size, it's too late to worry - the damage has been done (but now you need to think about how to clean up).



+3


source


FYI, you can do something like this from a shell in VxWorks using checkStack ().

+3


source


There are several methods you can use - usually you have a low priority task that checks the stack status of all other tasks every second.

a: Make sure the stack space is filled with a known pattern before running the task. Then you can find out how many remaining stacks are left after checking the pattern.

  • Benefit: Allows you to check the "high watermark" stack usage.
  • Disadvantage: If you allocate stack memory but don't write to it for some reason, this method CANNOT fail to detect an overflow.

b: You can just sniff the stack pointer of all other threads.

  • Disadvantage: This is just a "fetch" of the stack pointer, so a momentary sinking into an overflow cannot be noticed.
  • Benefit: Fast and easy.

I would recommend a mix of both. Since you are using low-level stuff, using functions like VxWorks' TaskInfoGet () functions, it is difficult to make this even remotely portable.

0


source


I don't know about VxWorks, but I recall that the Green Velosity / uVelosity kernels provide the code for this. Even if they didn't, since they provide a source that users can modify and the infrastructure is there, it would be very easy to add.

Edit: For the sake of disclosure, I did a summer internship with them bringing uVelosity to a new architecture. This is how I got intimate with handling thread stacks.

0


source


If your particular application statically allocates its threads, then you can put their stacks in statically defined areas and use a linker map to place a symbol at the end of those areas. Then you just need to get the current stack pointer (as described in other answers) and compare the "end of stack segment" pointer to that address. This can also work for dynamic allocation if each thread has room to store the address given to it as the end of its stack.

0


source


The default stack size is 1 MB, depending on the compiler. Based on this information, you can try to catch the remaining stack with something like this:


unsigned long remaining_stack_size() {
    char dummy;
    return 0x000fffff & (unsigned long)&dummy;
    // 0x000fffff is 1MB -1 (1048576 -1)
}

      

Edit: Note that it actually returns the current stack position, which is the same thing.

Edit (2): For those who said I was wrong, here's a proof of concept:


#include <stdio.h>
#include <windows.h>

unsigned long remaining_stack_size() {
    char dummy;
    return 0x001fffff & (unsigned long)&dummy + 1; // okay, some minor adjusts
}

void recurse_to_death(unsigned long used, char *p) {
    char buf[32*1024];
    used += 32*1024;
    printf("Used: 0x%08x Remaining: 0x%08x\n", used, remaining_stack_size());
    recurse_to_death(used, buf);
}

DWORD WINAPI my_thread(void *p) {
    printf("Total stack size of this Thread: 0x%08x bytes\n", remaining_stack_size() + 72);
    recurse_to_death(0, NULL);
    return 0;
}

int main(int argc, char *argv) {
    DWORD tid;
    // CreateThread stack size actually defaults to 1MB+64KB and does not honor lower values
    CreateThread(NULL, NULL, my_thread, NULL, NULL, NULL);
    Sleep(30000);
    return 0;
}

      

remaining_stack_size()

predicts stack overflow with perfection.

-2


source







All Articles