CCured consists of several components: an Ocaml application that does the
main work, a set of Perl scripts that are used to invoke the CCured
application, and a set of header and run-time library files.
The easiest way to use CCured is through the bin/ccured script. This
script is intended to be used in the same context and with the same
command-options as either the gcc compiler or the Microsoft Visual C
compiler (MSVC). This script is configured at installation time to know where
the rest of the CCured installation resides. If you move this script to
another directory you must also make a copy in the new directory of the
CilConfig.pm file.
Since ccured is a drop-in replacement for gcc, for most software
projects you can reuse the regular build-infrastructure:
make mystuff CC="bin/ccured [options]"
Here is the sequence of actions that the ccured script performs:
-
It recognizes among the command-line arguments those that are intended
for the pre-processor; then, for each source file (i.e. with the extension
t.c), calls the preprocessor and places the result in a file with the
extension .i in the same directory as the source file.
- For every .i file that it produces and that must be compiled (i.e.
the -E option was not specified to require only preprocessing) ccured
will save a copy of the file with the extension .o, thus “fooling”
make that the object file was actually produced.
- Whenever ccured is invoked to link into a library a number of
.o files that are actually preprocessed sources saved in the previous
step, the CCured engine will be invoked to parse all of the files and produce
a single C file with the same content but with names of types and
variables properly renamed. The output is then saved as the resulting library.
You should use the –mode=AR argument to CCured if you want to pass the
remaining arguments as for the ar utility. More details about the merging
stage that CCured used can be found .
- Finally, when ccured is called to link into an executable a
number of object files and libraries it will separate from them those that are
actually saved sources and will merge them all in memory. The resulting file
is then subject to CCured type inference followed by the insertion of run-time
checks. Optionally, an optimizer is invoked to try to clean up some of the
inserted run-time checks. The result is saved using the full name of the
desired executable with the suffix ccured.c. Finally this file is
preprocessed, compiled and linked using the underlying compiler.
Notice that by default the curing process is invoked on the whole program.
This is necessary to allow the CCured inferencer to see all the uses of your
pointers. An alternative is to annotate the include files with pointer-kind
annotation and let the inferencer do the inference within one file only.
4.1 Command-line options
You always run CCured with the command options of gcc (e.g., -c to
compile only, -o to specify the output file, etc.). Here are some common
ways to use invoke CCured:
-
bin/ccured –nocure –nomerge hello1.c hello2.c -o hello.exe
- Compiles and links without curing and without merging (still
uses the CIL front-end)
- bin/ccured –nocure hello1.c hello2.c -o hello.exe
-Merges using CIL, then compiles and links with gcc
- bin/ccured hello1.c hello2.c -o hello.exe -Merges using
CIL, processes with CCured, the compiles and links with gcc
- bin/ccured -c hello1.c hello2.c -Just put preprocessed source in the object files
- bin/ccured hello1.o hello2.o -o hello.exe -Take the
preprocessed source in the object file, merge, cure, gcc.
- bin/ccured –mode=AR cr hello.a hello1.o hello2.o -Merge
the preprocessed source in the object files into an archive (which itself
contains source)
- bin/ccured hello.a main.c -o hello.exe -Preprocess the C
source, merge with the sources in the archive, cure and gcc.
Most of the command-line options that you pass to ccured will be passed
along to the underlying preprocessor, compiler or linker. However the
ccured script recognizes the following special options:
-
General options
-
–save-temps. It tells the CCured script to save the temporary files
(including the output of CCured).
- –nocure. It does not actually cure the code. However, it reads it
in using the CIL front-end and then it prints it out immediately. Use this in
the first phase to check that the CIL front-end works for you.
- –mode=AR. Invoke CCured to act as the archiver. In this case there
should be no more arguments, except those that the ar utility would take.
This is because the ar arguments are positional.
- –mode=MSVC. Use instead of the Microsoft Visual C compiler
(cl). CCured and the CIL front-end know how to handle the MSVC extensions.
- –leavealone=foo. CCured will not merge and will not process the
file whose name starts with foo. Instead it will compile it as usual and will
link it in when needed. You can put in this file functions that you do not
want CCured to see (e.g., if they are really ugly and you are ashamed of
what you did!). See Section 7.4 for details.
- –stats. Print some statistics about the inserted checks.
- –stages. Print details about the various stages.
- –extrafiles=<xxx>. Give the name of a text file that contains
whitespace-separated named of additional files to process (in case your
command lines are too long).
- –nomerge. Invoke the curing process during the compilation stage,
without waiting to have the whole program.
- –keepunused. Disable the removal of apparently unused elements from
the file, such as local variables or prototypes.
- Inference
-
–noemitbrowser. Do not produce the browser information (speed up
curing).
- –browserdir=<dir>. Use <dir> as the name of the directory where
to store the browser information. By default it is placed in a directory whose
name is formed from the name of the executable followed by .browser.
- –browserSourceFileSize=N. Specify the number of statements to put
in a source file fragment. Default is 2000. Larger value means fewer source
fragments but also slower browser operation.
- –browserNodeFileSize=N. Specify the number of inference nodes to
put in a file. Default is 2000. Larger value means fewer
source fragments but also slower browser operation.
- –emitinfer. This means that the result of inference is also printed
in a file fooinfer.c where foo is the desired executable. See
Chapter A. It is recommended that you use the browser instead.
- –emitGraphDetailLevel. Controls how much information to put in the
infer file. Values range from 0 to 3.
- Curing
-
–allowInlineAssembly. Allow (unsound, best-effort) handling of
inline assembly.
- –nogc. Will assume that you do not use a garbage collector. In this
case the cured code will use explicit deallocation and might be unsafe.
- –optimize. Run the optimizer after curing.
- –releaselib. Use the release library (compiled with optimizations
on)
- –noUnrefPointerChecks. Treat as scalars those pointer variables
whose values are never used as pointers.
- –allowPartialElementsInSequence. Do not check that a sequence
contains a whole number of elements. If you turn this on, more programs will
cure, but the bounds checks for sequence pointers will be more expensive (see
Section 3.6.3).
- –noSplitPointers. Do not split CCured multi-word pointers into
single-word variables (Section 3.9).
- –alwaysStopOnError. Generate code that always stops on error
(slightly faster).
- –failIsTerse. Do not print source-file location on failure. This
makes your program smaller and faster.
- –noPrintLn. Turns off the printing of line-number information. This
way the errors will be referenced to the Cured file not the source file.
- –commPrintLn. Print line-number information as comments. This
way the errors that CCured prints at run-time and the debugging information in
the cured code refer to the cured file, not the original source, but
you can still figure out from what file this is coming.
- –printCilAsIs. Do not attempt to simplify the program while
printing. If this is turned on, then all loops will be printed as
“while(1)”, as they are in the internal language.
For most performance you should use the options:
--optimize --releaselib --alwaysStopOnError --failIsTerse
All of the other options that start with – (and are not recognized as
compiler options) are passed unmodified to the CCured Ocaml application.
4.2 Controlling error handling at run time
After you cure a program you can run it as usual. The operations of the
CCured-inserted run-time checks can be controlled with a few environment
variables when the target program is run:
-
CCURED_CONTINUE_ON_ERROR: if set and if –alwaysStopOnError
was not used during curing, the execution will continue on error. This means
that your program might be unsafe. It might also be possible that a cascade of
check failures will be triggered.
- CCURED_SLEEP_ON_ERROR: if set the program goes to sleep on an
error. When it does so, it prints the process id. You can then connect to it
using gdb as follows (replace test with the name of your executable
and 10343 with the actual process id printed when the process goes to
sleep.):
This is useful for debugging multi-threaded code or code that
is started by daemons. This has effect only if the program would actually stop
there.
Note that this mode is most useful when you compiled the code with -g and
you did not use –releaselib. I also prefer to use -commPrintLn so
that the debugging information refers to the cured file, not the original.
- CCURED_ERROR_HANDLERS: if set, then its value is taken to be the
name of a text file that contains indications on how to handle various error
conditions. First, the error messages that CCured prints are like this:
Failure UBOUND at hello.c:10: main(): Ubound
Each message has an error name (UBOUND), a file location (hello.c), a
line number (10), a function in which the error occurred (main), and
some explanation. You can specify error handlers based on the error name and
error location.
Each line in the error handler file must look like this:
[stop|warn|sleep|ignore|//] [*|ERRNAME] at [*|FILE] : [*|LINE] : [*:FUNC]
Note that you can almost copy and paste CCured error messages into this file.
stop means that the execution stops, warn that a warning is printed
and the execution continues, ignore that not even a warning is printed.
// means that the rest of the line is to be ignored.
* is a wildcard that matches anything. Except for the first two elements,
any suffix of the line can be missing. Whatever comes after the function name
is ignored. Empty lines are ignored and lines are matched in order. The file
is parsed when the program starts and then it is indexed by the error number
and looked up when an error occurs. Note that you cannot override
–alwaysStopOnError this way!
For example, the following file:
ignore UBOUND
stop * at hello.c: 10
ignore LBOUND at *:*:tricky
means that all UBOUND errors are ignored, the execution stops for any error
in line 10 of hello.c (except UBOUND), and LBOUND in function tricky is
ignored (except if it happens in line 10 of hello.c). Errors that do not
match are treated in the default way (stop if –alwaysStopOnError or
CCURED_CONTINUE_ON_ERROR are not specified).
- CCURED_DUMP_HANDLERS: if set, then CCured dumps its error handler
table (so that you can check that it has the values you want).
- CCURED_ERROR_LOG: If set, CCured will print all error
messages (except those which are are listed as ignore in the error
handling file) to the specified log file in addition to
stderr. This variable should be set to the absolute path of the
log file.
- CCURED_NO_SIGABRT: When CCured handles an error by
stopping the program's execution, it will normally call abort().
If this variable is set, CCured will use exit(-1) instead of
abort(), which means that SIGABRT is not thrown.