Download LCLint User's Guide
Transcript
Macros
25
typedef /*@abstract@*/ struct {
char *name;
int id;
} *employee;
…
char *employee_getName (employee e) { return e->name; }
LCLint produces a message to indicate that the return value exposes the representation. One solution
would be to return a fresh copy of e->name. This is expensive, though, especially if we expect
employee_getName is used mainly just to get a string for searching or printing. Instead, we could
change the declaration of employee_getName to:
extern /*@observer@*/ char *employee_getName (employee e);
Now, the original implementation is correct. The declaration indicates that the caller may not modify
the result, so it is acceptable to return shared storage.17 LCLint checks that the caller does not modify
the return value. An error is reported if observer storage is modified directly, passed as a function
parameter that may be modified, assigned to a global variable or reference derivable from a global
variable that is not declared with an observer annotation, or returned as a function result or a
reference derivable from the function result that is not annotation with an observer annotation.
String Literals
A program that attempts to modify a string literal has undefined behavior [ANSI, Section 3.1.4]. This
is not enforced by most C compilers, and can lead to particularly pernicious bugs that only appear
when optimizations are turned on and the compiler attempts to minimize storage for string literals.
LCLint can be used to check that string literals are not modified, by treating them as -observer
storage. If read-only-strings is on (default in standard mode), LCLint will report an error if a
string literal is modified.
6.2.2 Exposed Storage
Sometimes it is necessary to expose the representation of an abstract type. This may be evidence of a
design flaw, but in some cases is justified for efficiency reasons. The exposed annotation denotes
storage that is exposed. It may be used on a return value for results that reference storage internal to
an abstract representation, on a parameter value to indicate a parameter that may be assigned directly
to part of an abstract representation,18 or on a field of an abstract representation to indicate that
external references to the storage may exist. An error is reported if exposed storage is released, but
unlike an observer, no error is reported if it is modified.
Figure 12 shows examples of exposure problems detected by LCLint.
17
Strictly, we should also check that the returned observer storage is not used again after any other calls
to the abstract type module using the same parameter. LCLint does not attempt to check this, and in
practice it is not usually a problem.
18
Note that if the parameter is annotated with only, it is not an error to assign it to part of an abstract
representation, since the caller may not use the storage after the call returns.