previous next top complete contents complete index framed top this page unframed
Beginning in MAINSAIL Version 16.29, for every MAINSAIL platform, there is a corresponding SUPERCHECK platform. On a SUPERCHECK platform, MAINSAIL automatically performs far more detailed runtime checking than is the default on non-SUPERCHECK platforms. This makes it much easier to track bugs that corrupt MAINSAIL's memory or violate assumptions made by the MAINSAIL compiler and runtime system.
If you wish to use SUPERCHECK, please contact XIDAK for information on how to obtain a MAINSAIL system for a SUPERCHECK platform.
At the moment, SUPERCHECK does not cause checking code to be
generated to verify $REFERENCE parameters or to check the upper
bound of the first dimension in a reference to an element of an unsized
inplace ARRAY. (The standard subscript-checking code described
in Section 17.2 does not
check the first dimension's subscript against an unsized inplace
ARRAY's upper bound, since the upper bound is not always available,
and even when it is, it must be computed based on the total number of
elements in the ARRAY and the values of the other bounds.)
If the two CLASS descriptor
POINTERs are different, the reference is valid if
the expected CLASS is a prefix of the actual
CLASS. However, since
CLASS descriptors currently
contain no information about prefix CLASSes, the SUPERCHECK
code cannot do as strict a check as the compiler would be able to.
Instead, the SUPERCHECK code does a primitive check for structural
compatibility; if the fields of the expected CLASS and actual
CLASS (up
to and including the referenced field) seem to have the same declared
attributes, the reference is assumed to be valid even if the two
CLASSes
are unrelated.
Rather than actually comparing the fields' attributes, SUPERCHECK
uses a hash code based on the fields' attributes.
This makes for a more efficient check, although it does mean that
there is an extremely small possibility that SUPERCHECK will fail to
flag an erroneous reference.
18.1. What SUPERCHECK Checks
In modules compiled for SUPERCHECK platforms,
extra checking code is generated at most
forms of references to dynamic memory, to verify that the object being
referred to is the kind of object that is expected. At each reference
to a data field or PROCEDURE field of the form p.f
or m.f, the
SUPERCHECK code verifies that the fields
of the record or data section
pointed to by p or m match the fields of
the CLASS in which f was
declared, up to and including field f.
At each $PROCVAR call, the
SUPERCHECK code verifies that the $PROCVAR refers to a
PROCEDURE whose interface matches the $PROCVAR's declared model
PROCEDURE. And at each reference to an element of a dynamic
ARRAY, the SUPERCHECK code verifies that the ARRAY
POINTER points to an ARRAY whose element type, number of
dimensions, and actual bounds match those in the ARRAY POINTER's
declaration.
18.1.1. Implementation Overview: Data Field References
When the SUPERCHECK code checks a reference to a data field of the
form p.f or m.f,
it first makes sure that p or m points to a valid
record chunk or data section,
and then finds the CLASS descriptor for
the CLASS describing that record or data section
(the “actual” CLASS).
Then it compares this descriptor to the CLASS descriptor for the
expected CLASS.
If the two descriptor POINTERs are the same, then
the reference to f is valid; p or m points to
exactly the sort of chunk
it was expected to point to.
18.1.2. Implementation Overview: Intermodule Calls
SUPERCHECK code uses a similar hash encoding scheme when checking
intermodule calls of the form p.f or m.f.
First, the SUPERCHECK code
verifies that p or m
points to a valid data section, and finds the data
section's module descriptor (the “actual” module descriptor).
Then it
compares two hash encodings derived from the PROCEDURE fields'
declared attributes.
One hash encoding denotes the calling module's view
of the interface to the module being called. It is obtained from
information in the expected CLASS's CLASS
descriptor. The other hash
encoding denotes the module's actual interface, and is obtained from the
actual module descriptor.
18.1.3. Implementation Overview: $PROCVAR Calls
The SUPERCHECK code for $PROCVAR
calls first verifies that the $PROCVAR's
data section part refers to a valid data section. Then it finds the
referenced PROCEDURE based on the $PROCVAR's
displacement, verifying that the $PROCVAR actually refers to a
PROCEDURE.
Finally, it compares a hash encoding for the $PROCVAR's model
PROCEDURE (computed by the compiler) to a hash encoding for
the PROCEDURE referred to by the $PROCVAR.
The two hash encodings denote
the expected and actual PROCEDURE interface.
If they are unequal, the
$PROCVAR call is assumed to be invalid.
18.2. Decreased Frequency of POINTER Rigging: DELAYRIGPTRS
Normally when POINTER rigging (the MAINEX subcommand RIGPTRS; see Chapter 6 of the MAINDEBUG User's Guide) is in effect, MAINSAIL walks through memory at each call to dispose, rigging any POINTERs to the disposed chunk. This can make programs run extremely slowly, but on non-SUPERCHECK platforms is the only reliable way to catch dangling POINTER bugs. On SUPERCHECK platforms, many dangling POINTER references can be caught with SUPERCHECK, so MAINSAIL provides an option on SUPERCHECK platforms for batching up the rigging of POINTERs to disposed chunks until a sufficient number of chunks have been disposed to make rigging worthwhile, thereby reducing the number of times MAINSAIL must walk memory to rig POINTERs. On SUPERCHECK platforms, any dangling POINTER references to these chunks will be detected even though the POINTERs have not been rigged yet.
When a chunk is disposed while delayed POINTER rigging is in effect, the chunk is not really freed. Instead, the chunk is specially marked so that a reference to it will cause the SUPERCHECK code to detect an error. When the total amount of space occupied by all such marked chunks exceeds a user-specifiable threshold, MAINSAIL makes a single pass through memory, rigging all POINTERs to any of the chunks on the lists, and marking the chunks on the lists as free. This rigging also happens during calls to $disposeArea, $clearArea, $collect, and any other runtime system routines that could free chunk memory, unless there are no chunks for which rigging has been delayed.
Two CONF parameters (see Chapter 6 of the MAINSAIL Utilities User's Guide) specify the threshold governing the maximum amount of memory that can be occupied by disposed chunks for which rigging has been delayed: MAXSIZEDELAYRIGCHUNKS and MAXPERCENTDELAYRIGCHUNKS. If MAXSIZEDELAYRIGCHUNKS is nonzero, it specifies the threshold as an absolute number of bytes. If MAXPERCENTDELAYRIGCHUNKS is nonzero, it specifies the threshold as a percentage of the total memory currently allocated by MAINSAIL. Both parameters can be nonzero, in which case the smaller threshold is the one that applies. The default value of MAXSIZEDELAYRIGCHUNKS is zero and the default value of MAXPERCENTDELAYRIGCHUNKS is 5.
Two MAINEX subcommands control whether or not delayed POINTER rigging is in effect: DELAYRIGPTRS and NODELAYRIGPTRS. Delayed POINTER rigging can also be controlled from a program by calling the PROCEDUREs $setDelayPtrRigging and $clearDelayPtrRigging.
When delayed POINTER rigging is in effect, programs will use memory differently than they otherwise would, because disposed chunks will not be recycled for reuse in the same way. But delayed POINTER rigging will still catch any dangling POINTERs that are dereferenced when SUPERCHECK is in effect, while reducing on the number of times MAINSAIL walks memory to rig POINTERs.
On SUPERCHECK platforms, delayed rigging is in effect by default.
That is, MAINSAIL acts as if the MAINEX subcommands RIGPTRS,
RIGSTRS, and DELAYRIGPTRS
had all been given; if you do not want
to use rigging on a SUPERCHECK platform, you must turn it off
explicitly.
On non-SUPERCHECK platforms,
all these subcommands are off by default.
In XIDAK's experiments,
SUPERCHECK programs take about 3 to 5 times longer
than the same programs on non-SUPERCHECK platforms.
Because SUPERCHECK makes programs run substantially slower,
XIDAK recommends that you use SUPERCHECK only while
testing your code, and not use it in code that will be put into
production.
18.3. Effect of SUPERCHECK on Speed
SUPERCHECK code makes different programs slower by different
amounts, depending on how many times a program uses a POINTER to
refer to data and how often it does intermodule calls and $PROCVAR
calls. Also, the SUPERCHECK code for POINTER-based data
references where the expected CLASS is the same as the actual
CLASS of
the referenced record are much faster than data references where the
expected CLASS and actual CLASS are different.
18.4. Effect of SUPERCHECK on Size
SUPERCHECK object modules take up more space than standard object
modules.
Although the increase in size depends on exactly what the modules
do, in XIDAK's benchmarks,
SUPERCHECK code is about twice as large as
non-SUPERCHECK code.
MAINSAIL Language Manual, Chapter 18