Stack Scrubbing (GNAT Reference Manual) (original) (raw)
18.2 Stack Scrubbing ¶
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, or their types. (This attribute always applies to a type, even when it is associated with a subprogram or a variable.)
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. Shorthand for: -- pragma Machine_Attribute (Foo, "strub", "at-calls");
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. Furthermore, if -- Var is declared within a subprogram, this also enables -- scrubbing of the stack space used by that subprogram.
Given these declarations, Foo has its type and body modified as follows:
function Foo ( : in out System.Address) returns Integer is -- ... begin <__strub_update> (); -- Updates the stack WaterMark. -- ... end;
whereas its callers are modified from:
to:
declare : System.Address; begin <__strub_enter> (); -- Initialize . X := Foo (); <__strub_leave> (); -- Scrubs stack up to . end;
As for Bar, because it is strubbed in internal mode, its callers are not modified. Its definition is modified roughly as follows:
procedure Bar is : System.Address; procedure Strubbed_Bar ( : in out System.Address) is begin <__strub_update> (); -- Updates the stack WaterMark. -- original Bar body. end Strubbed_Bar; begin <__strub_enter> (); -- Initialize . Strubbed_Bar (); <__strub_leave> (); -- Scrubs stack up to . end Bar;
There are also -fstrub=`choice' command-line options to control default settings. For usage and more details on the command-line options, on the strub attribute, and their use with other programming languages, see Using the GNU Compiler Collection (GCC).
Note that Ada secondary stacks are not scrubbed. The restrictionNo_Secondary_Stack avoids their use, and thus their accidental preservation of data that should be scrubbed.
Attributes Access and Unconstrained_Access of variables and constants with strub enabled require types with strub enabled; 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 : aliased Integer; pragma Machine_Attribute (VI, "strub"); XsVI : access Integer := VI'Access; -- Error. UXsVI : access Integer := VI'Unchecked_Access; -- OK, -- UXsVI does not enable strub in subprograms that -- dereference it to obtain the UXsVI.all value.
type Strub_Int is new Integer; pragma Machine_Attribute (Strub_Int, "strub"); VSI : aliased Strub_Int; XsVSI : access Strub_Int := VSI'Access; -- OK, -- VSI and XsVSI.all both enable strub in subprograms that -- read their values.
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 strub-disabled subprogram can be turned callable through such an explicit conversion:
type TBar is access procedure;
type TBar_Callable is access procedure; pragma Machine_Attribute (TBar_Callable, "strub", "callable"); -- The attribute modifies the procedure type, rather than the -- access type, because of the extra argument after "strub", -- only applicable to subprogram types.
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.