Next: , Previous: Style Checking, Up: Switches for gcc


3.2.6 Run-Time Checks

By default, the following checks are suppressed: integer overflow checks, stack overflow checks, and checks for access before elaboration on subprogram calls. All other checks, including range checks and array bounds checks, are turned on by default. The following gcc switches refine this default behavior.

-gnatp
This switch causes the unit to be compiled as though pragma Suppress (All_checks) had been present in the source. Validity checks are also eliminated (in other words -gnatp also implies -gnatVn. Use this switch to improve the performance of the code at the expense of safety in the presence of invalid data or program bugs.

Note that when checks are suppressed, the compiler is allowed, but not required, to omit the checking code. If the run-time cost of the checking code is zero or near-zero, the compiler will generate it even if checks are suppressed. In particular, if the compiler can prove that a certain check will necessarily fail, it will generate code to do an unconditional “raise”, even if checks are suppressed. The compiler warns in this case. Another case in which checks may not be eliminated is when they are embedded in certain run time routines such as math library routines.

Of course, run-time checks are omitted whenever the compiler can prove that they will not fail, whether or not checks are suppressed.

Note that if you suppress a check that would have failed, program execution is erroneous, which means the behavior is totally unpredictable. The program might crash, or print wrong answers, or do anything else. It might even do exactly what you wanted it to do (and then it might start failing mysteriously next week or next year). The compiler will generate code based on the assumption that the condition being checked is true, which can result in disaster if that assumption is wrong.

-gnato
Enables overflow checking for integer operations. This causes GNAT to generate slower and larger executable programs by adding code to check for overflow (resulting in raising Constraint_Error as required by standard Ada semantics). These overflow checks correspond to situations in which the true value of the result of an operation may be outside the base range of the result type. The following example shows the distinction:
          X1 : Integer := "Integer'Last";
          X2 : Integer range 1 .. 5 := "5";
          X3 : Integer := "Integer'Last";
          X4 : Integer range 1 .. 5 := "5";
          F  : Float := "2.0E+20";
          ...
          X1 := X1 + 1;
          X2 := X2 + 1;
          X3 := Integer (F);
          X4 := Integer (F);
     

Note that if explicit values are assigned at compile time, the compiler may be able to detect overflow at compile time, in which case no actual run-time checking code is required, and Constraint_Error will be raised unconditionally, with or without -gnato. That's why the assigned values in the above fragment are in quotes, the meaning is "assign a value not known to the compiler that happens to be equal to ...". The remaining discussion assumes that the compiler cannot detect the values at compile time.

Here the first addition results in a value that is outside the base range of Integer, and hence requires an overflow check for detection of the constraint error. Thus the first assignment to X1 raises a Constraint_Error exception only if -gnato is set.

The second increment operation results in a violation of the explicit range constraint; such range checks are performed by default, and are unaffected by -gnato.

The two conversions of F both result in values that are outside the base range of type Integer and thus will raise Constraint_Error exceptions only if -gnato is used. The fact that the result of the second conversion is assigned to variable X4 with a restricted range is irrelevant, since the problem is in the conversion, not the assignment.

Basically the rule is that in the default mode (-gnato not used), the generated code assures that all integer variables stay within their declared ranges, or within the base range if there is no declared range. This prevents any serious problems like indexes out of range for array operations.

What is not checked in default mode is an overflow that results in an in-range, but incorrect value. In the above example, the assignments to X1, X2, X3 all give results that are within the range of the target variable, but the result is wrong in the sense that it is too large to be represented correctly. Typically the assignment to X1 will result in wrap around to the largest negative number. The conversions of F will result in some Integer value and if that integer value is out of the X4 range then the subsequent assignment would generate an exception.

Note that the -gnato switch does not affect the code generated for any floating-point operations; it applies only to integer semantics). For floating-point, GNAT has the Machine_Overflows attribute set to False and the normal mode of operation is to generate IEEE NaN and infinite values on overflow or invalid operations (such as dividing 0.0 by 0.0).

The reason that we distinguish overflow checking from other kinds of range constraint checking is that a failure of an overflow check, unlike for example the failure of a range check, can result in an incorrect value, but cannot cause random memory destruction (like an out of range subscript), or a wild jump (from an out of range case value). Overflow checking is also quite expensive in time and space, since in general it requires the use of double length arithmetic.

Note again that -gnato is off by default, so overflow checking is not performed in default mode. This means that out of the box, with the default settings, GNAT does not do all the checks expected from the language description in the Ada Reference Manual. If you want all constraint checks to be performed, as described in this Manual, then you must explicitly use the -gnato switch either on the gnatmake or gcc command.

-gnatE
Enables dynamic checks for access-before-elaboration on subprogram calls and generic instantiations. Note that -gnatE is not necessary for safety, because in the default mode, GNAT ensures statically that the checks would not fail. For full details of the effect and use of this switch, See Compiling Using gcc.
-fstack-check
Activates stack overflow checking. For full details of the effect and use of this switch see Stack Overflow Checking.

The setting of these switches only controls the default setting of the checks. You may modify them using either Suppress (to remove checks) or Unsuppress (to add back suppressed checks) pragmas in the program source.