GNAT can generate code to zero-out stack frames used by subprograms.
It can be activated with the
Machine_Attribute pragma, on
specific subprograms and variables.
function Foo returns Integer; pragma Machine_Attribute (Foo, "strub"); -- Foo and its callers are modified so as to scrub the stack -- space used by Foo after it returns. procedure Bar; pragma Machine_Attribute (Bar, "strub", "internal"); -- Bar is turned into a wrapper for its original body, -- and they scrub the stack used by the original body. Var : Integer; pragma Machine_Attribute (Var, "strub"); -- Reading from Var in a subprogram enables stack scrubbing -- of the stack space used by the subprogram.
There are also `-fstrub' command line options to control default
settings. For usage and more details on the command line option, and
strub attribute, see Using the GNU Compiler Collection (GCC).
Note that Ada secondary stacks are not scrubbed. The restriction
No_Secondary_Stack avoids their use, and thus their accidental
preservation of data that should be scrubbed.
Unconstrained_Access of variables and
strub enabled require types with
there is no way to express an access-to-strub type otherwise.
Unchecked_Access bypasses this constraint, but the resulting
access type designates a non-strub type.
VI : Integer; XsVI : access Integer := VI'Access; -- Error. UXsVI : access Integer := VI'Unchecked_Access; -- OK, -- UXsVI.all does not enable strub in the enclosing subprogram. type Strub_Int is new Integer; pragma Machine_Attribute (Strub_Int, "strub"); VSI : Strub_Int; XsVSI : access Strub_Int := VSI'Access; -- OK. -- XsVSI.all enables strub in the enclosing subprogram.
Every access-to-subprogram type, renaming, and overriding and
overridden dispatching operations that may refer to a subprogram with
an attribute-modified interface must be annotated with the same
interface-modifying attribute. Access-to-subprogram types can be
explicitly converted to different strub modes, as long as they are
interface-compatible (i.e., adding or removing
at-calls is not
allowed). For example, a
disabled subprogram can be
callable through such an explicit conversion:
type TBar is access procedure; type TBar_Callable is access procedure; pragma Machine_Attribute (TBar_Callable, "strub", "callable"); Bar_Callable_Ptr : constant TBar_Callable := TBar_Callable (TBar'(Bar'Access)); procedure Bar_Callable renames Bar_Callable_Ptr.all; pragma Machine_Attribute (Bar_Callable, "strub", "callable");
Note that the renaming declaration is expanded to a full subprogram body, it won’t be just an alias. Only if it is inlined will it be as efficient as a call by dereferencing the access-to-subprogram constant Bar_Callable_Ptr.