7

I am writing an Ada program using the Ravenscar subset (thus, I am aware of the number of running tasks at execution time). The code is compiled by gcc with the -fstack-check switch enabled. This should cause the program raise a STORAGE_ERROR at runtime if any of my tasks exceed their stack.

Ada allows to set the upper limit for those (task-specific) stacks during the specification of the respective task like so:

pragma Storage_Size (Some_Value);

Now I was wondering what options I have to determine Some_Value. What I have heard of so far:

  1. Do wild guesses until no STORAGE_ERROR is raised anymore. This is more or less what the OP suggests here.
  2. Feed the output of -fstack-usage in there.
  3. Use some gnat specific extensions as outlined here (how does this technically differ from item #2?).
  4. Get a stack analyzer like gnatstack and let it do the work for you.

If I understand this correctly all the above techniques are dynamic (i.e. they require the program to run in order to work). Are static approaches also conceivable? E.g. by restricting myself further through some of Ada's high integrity options (such as No_Recursion, what else?).

Perhaps any of you can name some best practices to tackle this problem and/or extend/comment on my (surely incomplete) list.

Bonus question: What is the default size of a task's stack when the above pragma is not specified? GCC's docs only state this value depends on the runtime, without giving any concrete numbers.

Community
  • 1
  • 1
morido
  • 1,027
  • 7
  • 24
  • 1
    Good question with good background research! –  Jan 13 '16 at 12:03
  • 1
    The default stack size is given in `System.Parameters.Default_Stack_Size` (file `s-parame.adb`). – Simon Wright Jan 13 '16 at 14:26
  • @Simon : does that stack size relate to the environment task, declared tasks or all tasks? I ask because I came across a "set stack size" option that didn't affect the environment task - which was apparently not settable by any means with that specific compiler release, which also disobeyed ulimit settings. I worked around it by moving the entire program into a new task... –  Jan 13 '16 at 14:43
  • 1
    @Brian: a few lines below there’s `Default_Env_Stack_Size` (8 MB here, 5.2.0). Is there an environment _task_ if the program doesn’t call in the tasking runtime? (NB, what I’ve said is all desktop-related; I don’t know how AdaCore’s bare-board RTSs behave). – Simon Wright Jan 13 '16 at 17:43

1 Answers1

1

You can generally check the stack space required by individual types with the 'Storage_Size attribute (which counts in bits).

Once you have tabulated this (you may need to round it up to whole words/double words), you can add up how much stack space is used by each declarative region, and then walk through your calls to find the maximum stack usage.

Jacob Sparre Andersen
  • 6,733
  • 17
  • 22
  • Are you suggesting to do this manually? That sounds like a tedious endeavour... Is there perhaps any tool support for this? – morido Jan 14 '16 at 08:11
  • 1
    I was literally suggesting that you do it manually. I doubt that you can do it through static analysis unless you restrict yourself not to use recursion. If you don't use recursion, it should be possible to write a small ASIS-based tool to do the job. – Jacob Sparre Andersen Jan 14 '16 at 16:48