diff --git a/clang/docs/analyzer/checkers.rst b/clang/docs/analyzer/checkers.rst --- a/clang/docs/analyzer/checkers.rst +++ b/clang/docs/analyzer/checkers.rst @@ -2373,6 +2373,88 @@ alpha.unix ^^^^^^^^^^^ +.. _alpha-unix-StdCLibraryFunctionArgs: + +alpha.unix.StdCLibraryFunctionArgs (C) +"""""""""""""""""""""""""""""""""""""" +Check for calls of standard library functions that violate predefined argument +constraints. For example, it is stated in the C standard that for the ``int +isalnum(int ch)`` function the behavior is undefined if the value of ``ch`` is +not representable as unsigned char and is not equal to ``EOF``. + +.. code-block:: c + + void test_alnum_concrete(int v) { + int ret = isalnum(256); // \ + // warning: Function argument constraint is not satisfied + (void)ret; + } + +If the argument's value is unknown then the value is assumed to hold the proper value range. + +.. code-block:: c + + #define EOF -1 + int test_alnum_symbolic(int x) { + int ret = isalnum(x); + // after the call, ret is assumed to be in the range [-1, 255] + + if (ret > 255) // impossible (infeasible branch) + if (x == 0) + return ret / x; // division by zero is not reported + return ret; + } + +If the user disables the checker then the argument violation warning is +suppressed. However, the assumption about the argument is still modeled. This +is because exploring an execution path that already contains undefined behavior +is not valuable. + +There are different kind of constraints modeled: range constraint, not null +constraint, buffer size constraint. A **range constraint** requires the +argument's value to be in a specific range, see ``isalnum`` as an example above. +A **not null constraint** requires the pointer argument to be non-null. + +A **buffer size** constraint specifies the minimum size of the buffer +argument. The size might be a known constant. For example, ``asctime_r`` requires +that the buffer argument's size must be greater than or equal to ``26`` bytes. In +other cases, the size is denoted by another argument or as a multiplication of +two arguments. +For instance, ``size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)``. +Here, ``ptr`` is the buffer, and its minimum size is ``size * nmemb`` + +.. code-block:: c + + void buffer_size_constraint_violation(FILE *file) { + enum { BUFFER_SIZE = 1024 }; + wchar_t wbuf[BUFFER_SIZE]; + + const size_t size = sizeof(*wbuf); // 4 + const size_t nitems = sizeof(wbuf); // 4096 + + // Below we receive a warning because the 3rd parameter should be the + // number of elements to read, not the size in bytes. This case is a known + // vulnerability described by the the ARR38-C SEI-CERT rule. + fread(wbuf, size, nitems, file); + } + +**Limitations** + +The checker is in alpha because the reports cannot provide notes about the +values of the arguments. Without this information it is hard to confirm if the +constraint is indeed violated. For example, consider the above case for +``fread``. We display in the warning message that the size of the 1st arg +should be equal to or less than the value of the 2nd arg times the 3rd arg. +However, we fail to display the concrete values (``4`` and ``4096``) for those +arguments. + +**Parameters** + +The checker models functions (and emits diagnostics) from the C standard by +default. The ``ModelPOSIX`` option enables the checker to model (and emit +diagnostics) for functions that are defined in the POSIX standard. This option +is disabled by default. + .. _alpha-unix-BlockInCriticalSection: alpha.unix.BlockInCriticalSection (C) diff --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td --- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td +++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td @@ -552,7 +552,7 @@ "or is EOF.">, Dependencies<[StdCLibraryFunctionsChecker]>, WeakDependencies<[CallAndMessageChecker, NonNullParamChecker, StreamChecker]>, - Documentation; + Documentation; } // end "alpha.unix"