blob: 7b28f38ea1d8a1d10a18fa2a3a1fd87bdb332783 [file] [log] [blame]
\htmlhr
\chapterAndLabel{Called Methods Checker}{called-methods-checker}
The Called Methods Checker tracks the names of methods that have definitely
been called on an object. This checker is useful for checking any property
of the form ``call method A before method B''.
The Called Methods Checker provides built-in support for one such property:
that clients of the builder pattern for object
construction always provide all required arguments before calling
\<build()>. The builder pattern is a flexible and readable way to
construct objects, but it is error-prone. Failing to provide
a required argument causes a run-time error that manifests during testing
or in the field, instead of at compile time as for regular Java
constructors. The Called Methods Checker verifies at compile time that
your code correctly uses the builder pattern, never omitting a required
argument. The Called Methods Checker has built-in support for
\href{https://projectlombok.org/}{Lombok} (see the caveats about Lombok in
Section~\ref{called-methods-lombok}) and
\href{https://github.com/google/auto/blob/master/value/userguide/index.md}{AutoValue}.
You can verify other builders, or verify other properties of the form
``foo() must be called before bar()'', by writing method specifications.
Section~\ref{called-methods-other} describes another example related to a
security property.
If the checker issues no warnings, then you have a guarantee that your code
supplies all the required information to the builder. The checker might
yield a false positive warning when your code is too tricky for it to
verify. Please submit an
\href{https://github.com/typetools/checker-framework/issues}{issue} if you
discover this.
\sectionAndLabel{How to run the Called Methods Checker}{called-methods-run-checker}
\begin{Verbatim}
javac -processor CalledMethods MyFile.java ...
\end{Verbatim}
The Called Methods Checker supports the following optional command-line arguments:
\begin{itemize}
\item The \<-ACalledMethodsChecker\_disableBuilderFrameworkSupports> option disables automatic
annotation inference for builder frameworks.
Section~\ref{called-methods-framework-details} describes its syntax.
Supply this if you are uninterested in errors in the use of builders, but
are using the Called Methods Checker to detect errors in other types of
code.
\item The \<-ACalledMethodsChecker\_disableReturnsReceiver> option disables
the Returns Receiver Checker (\chapterpageref{returns-receiver-checker}),
which ordinarily runs as a subchecker of the Called Methods Checker. If
the code being checked does not use fluent APIs, then you can supply this
option and the Called Methods Checker will run much faster.
\item The \<-ACalledMethodsChecker\_useValueChecker> option improves precision when analyzing
code that uses the AWS SDK's \<DescribeImageRequest> API\@. See
Section~\ref{called-methods-other}.
\end{itemize}
\sectionAndLabel{For Lombok users}{called-methods-lombok}
The Called Methods Checker supports projects that use Lombok via
the \href{https://plugins.gradle.org/plugin/io.freefair.lombok}{io.freefair.lombok} Gradle plugin automatically.
However, note that the checker's error messages refer to Lombok's output, which is a variant of your source code
that appears in a \<delombok> directory.
To fix issues, you should edit your original source code, \textbf{not} the files in the checker's error messages.
If you use Lombok with a build system other than Gradle, you must configure it to do two tasks.
If either of these is not done, the checker will not issue any errors on Lombok code.
\begin{itemize}
\item set Lombok configuration option \<lombok.addLombokGeneratedAnnotation = true>
\item delombok the code before passing it to the checker
\end{itemize}
\sectionAndLabel{Specifying your code}{called-methods-spec}
The Called Methods Checker reads method specifications (contracts) that
state what a method requires when it is called. It warns if method
arguments do not satisfy the method's specification.
If you use AutoValue or Lombok, most specifications are automatically
inferred by the Called Methods Checker, from field annotations such as
\<@Nullable> and field types such as
\<Optional>. Section~\ref{called-methods-framework-details} gives
defaulting rules for Lombok and AutoValue.
\begin{figure}
\begin{center}
\hfill
\includeimage{calledmethods}{5cm}
\hfill
\end{center}
\caption{The type hierarchy for the Called Methods type system, for an object with two methods: \<a()> and \<b()>.
Types displayed in gray should rarely be written by the programmer.}
\label{fig-called-methods-types}
\end{figure}
In some cases, you may need to specify your code. You do so by writing one of the following type
annotations (Figure~\ref{fig-called-methods-types}):
\begin{description}
\item[\refqualclasswithparams{checker/calledmethods/qual}{CalledMethods}{String[] methodNames}]
The annotated type represents values on which all the given method were definitely called.
(Other methods might also have been called.) \<@CalledMethods()>, with no
arguments, is the default annotation.
Suppose that the method \<build> is annotated as
\begin{Verbatim}
class MyObjectBuilder {
MyObject build(@CalledMethods({"setX", "setY"}) MyObjectBuilder this) { ... }
}
\end{Verbatim}
Then the receiver for any call to \<build()> must have had \<setX()> and \<setY()> called on it.
\item[\refqualclasswithparams{checker/calledmethods/qual}{CalledMethodsPredicate}{String expression}]
The boolean expression specifies the required method calls. The string
is a boolean expression composed of method names, disjunction (\<||>),
conjunction (\<\&\&>), not (\<!>), and parentheses.
For example, the annotation \<@CalledMethodsPredicate("x \&\& y || z")> on a type represents
objects such that either both the \<x()> and \<y()> methods have been called on the object, \textbf{or}
the \<z()> method has been called on the object.
A note on the not operator (\<!>): the annotation
\<@CalledMethodsPredicate("!m")> means ``it is not true \<m> was
definitely called''; equivalently ``there is some path on which \<m> was
not called''. The annotation \<@CalledMethodsPredicate("!m")> does
\emph{not} mean ``\<m> was not called''.
The Called Methods Checker does not have a way of expressing that a
method must never be called. You can do unsound bug-finding for such a
property by using the \<!> operator. The Called Methods Checker will
detect if the method was always called, but will silently approve the code
if the method is called on some but not all paths.
\item[\refqualclass{common/returnsreceiver/qual}{This}]
\<@This> may only be written on a method return type, and means that the method returns its receiver.
This is helpful when type-checking fluent APIs. This annotation is defined by the
Returns Receiver Checker (\chapterpageref{returns-receiver-checker}), but is particularly useful
for the Called Methods Checker because many builders are fluent APIs.
\item[\refqualclass{checker/calledmethods/qual}{CalledMethodsBottom}]
The bottom type for the Called Methods hierarchy. Conceptually, this annotation
means that all possible methods have been called on the object. Programmers should rarely,
if ever, need to write this annotation---write an appropriate \<@CalledMethods> annotation
instead.
\end{description}
There are also method annotations:
\begin{description}
\item[\refqualclass{checker/calledmethods/qual}{EnsuresCalledMethods}]
This declaration annotation specifies a post-condition on a method, indicating the methods it
guarantees to be called.
For example, this specification:
\begin{Verbatim}
@EnsuresCalledMethods(value = "#1", methods = {"x", "y"})
void m(Param p) { ... }
\end{Verbatim}
guarantees that \<p.x()> and \<p.y()> will always be called before \<m> returns.
The body of \<m> must satisfy that property, and clients of \<m> can depend on the property.
\item[\refqualclass{checker/calledmethods/qual}{EnsuresCalledMethodsIf}]
This declaration annotation specifies a post-condition on a method, indicating the methods it
guarantees to be called if it returns a given result.
For example, this specification:
\begin{Verbatim}
@EnsuresCalledMethodsIf(expression = "#1", methods = {"x", "y"}, result=true)
boolean m(Param p) { ... }
\end{Verbatim}
guarantees that \<p.x()> and \<p.y()> will always be called if \<m> returns \<true>.
The body of \<m> must satisfy that property, and clients of \<m> can depend on the property.
\end{description}
\sectionAndLabel{Default handling for Lombok and AutoValue}{called-methods-framework-details}
This section explains how the Called Methods Checker infers types for code
that uses the Lombok and AutoValue frameworks. Most readers can skip these
details.
You can disable the builder framework support by specifying them in a
comma-separated lowercase list to the command-line flag
\<disableBuilderFrameworkSupports>. For example, to disable both Lombok
and AutoValue support, use: \\
\<-ACalledMethodsChecker\_disableBuilderFrameworkSupports=autovalue,lombok>
The Called Methods Checker automatically assumes default annotations for code that uses builders generated
by Lombok and AutoValue. There are three places annotations are usually assumed:
\begin{itemize}
\item A \<@CalledMethods> annotation is placed on the receiver of the
\<build()> method, indicating the setter methods that must be invoked on
the builder before calling \<build()>. For Lombok, this annotation's
argument is the set of \<@lombok.NonNull> fields that do not have default
values. For AutoValue, it is the set of fields that are not
\<@Nullable>, \<Optional>, or a Guava Immutable Collection.
\item The return type of a \<toBuilder()> method (for example, if the
\<toBuilder = true> option is passed to Lombok's \<@Builder> annotation)
is annotated with the same \<@CalledMethods> annotation as the receiver
of \<build()>, using the same rules as above.
\item A \<@This> annotation is placed on the return type of each setter in
the builder's implementation.
\end{itemize}
If your program directly defines any of these methods (for example, by adding your own setters to
a Lombok builder), you may need to write the annotations manually.
Minor notes/caveats on these rules:
\begin{itemize}
\item Lombok fields annotated with \<@Singular> will be treated as defaulted (i.e., not required), because
Lombok will set them to empty collections if the corresponding setter is not called.
\item If you manually provide defaults to a Lombok builder (for example, by defining the builder yourself
and assigning a default value to the builder's field), the checker will treat that field as defaulted
\emph{most} of the time. In particular, it will not treat it as defaulted if it is defined in bytecode rather
than in source code.
\end{itemize}
\sectionAndLabel{Using the Called Methods Checker for properties unrelated to builders}{called-methods-other}
The Called Methods Checker can be used to verify any property of the form
``always call A before B'', even if the property is unrelated to builders.
For example, consider the AWS EC2 \<describeImages> API, which
clients use during the process of initializing a new cloud instance.
\href{https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-15869}{CVE-2018-15869}
describes how an improperly-configured request to this API can make the
requesting client vulnerable to a ``machine-image sniping'' attack that
would allow a malicious third-party to control the operating system image
used to initialize the machine. To prevent this attack, clients must
specify some trusted source for the image by calling the \<withOwners> or
\<withImageIds> methods on the request prior to sending it to AWS\@. Using
a stub file for the \<describeImages> API
(\href{https://github.com/typetools/checker-framework/blob/master/checker/src/main/java/org/checkerframework/checker/calledmethods/DescribeImages.astub}{DescribeImages.astub}),
the Called Methods Checker can prove that a client is not vulnerable to
such an attack.
To improve precision, you can specify the
\<-ACalledMethodsChecker\_useValueChecker> command-line option, which
instructs the checker to treat provably-safe calls to the \<withFilters>
method of a \<DescribeImagesRequest> as equivalent to the \<withOwners> or
\<withImageIds> methods.