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.