[analyzer] Deprecate FAM analyzer-config, recommend -fstrict-flex-arrays instead

By default, clang assumes that all trailing array objects could be a
FAM. So, an array of undefined size, size 0, size 1, or even size 42 is
considered as FAMs for optimizations at least.

One needs to override the default behavior by supplying the
`-fstrict-flex-arrays=<N>` flag, with `N > 0` value to reduce the set of
FAM candidates. Value `3` is the most restrictive and `0` is the most
permissive on this scale.

0: all trailing arrays are FAMs
1: only incomplete, zero and one-element arrays are FAMs
2: only incomplete, zero-element arrays are FAMs
3: only incomplete arrays are FAMs

If the user is happy with consdering single-element arrays as FAMs, they
just need to remove the
`consider-single-element-arrays-as-flexible-array-members` from the
command line.
Otherwise, if they don't want to recognize such cases as FAMs, they
should specify `-fstrict-flex-arrays` anyway, which will be picked up by
CSA.

Any use of the deprecated analyzer-config value will trigger a warning
explaining what to use instead.
The `-analyzer-config-help` is updated accordingly.

Depends on D138657

Reviewed By: xazax.hun

Differential Revision: https://reviews.llvm.org/D138659
This commit is contained in:
Balazs Benics 2022-11-25 10:24:56 +01:00
parent 3648175839
commit 097ce76165
7 changed files with 63 additions and 23 deletions

View File

@ -827,6 +827,12 @@ Static Analyzer
``scanbuild`` was also updated accordingly.
Passing these flags will result in a hard error.
- Deprecate the ``consider-single-element-arrays-as-flexible-array-members``
analyzer-config option.
This option will be still accepted, but a warning will be displayed.
This option will be rejected, thus turned into a hard error starting with
``clang-17``. Use ``-fstrict-flex-array=<N>`` instead if necessary.
- Trailing array objects of structs with single elements will be considered
as flexible-array-members. Use ``-fstrict-flex-array=<N>`` to define
what should be considered as flexible-array-member if needed.

View File

@ -458,6 +458,10 @@ def warn_analyzer_deprecated_option : Warning<
"analyzer option '%0' is deprecated. This flag will be removed in %1, and "
"passing this option will be an error.">,
InGroup<DeprecatedStaticAnalyzerFlag>;
def warn_analyzer_deprecated_option_with_alternative : Warning<
"analyzer option '%0' is deprecated. This flag will be removed in %1, and "
"passing this option will be an error. Use '%2' instead.">,
InGroup<DeprecatedStaticAnalyzerFlag>;
def warn_drv_needs_hvx : Warning<
"%0 requires HVX, use -mhvx/-mhvx= to enable it">,

View File

@ -331,7 +331,8 @@ ANALYZER_OPTION(
"consider-single-element-arrays-as-flexible-array-members",
"Consider single element arrays as flexible array member candidates. "
"This will prevent the analyzer from assuming that a single element array "
"holds a single element.",
"holds a single element. [DEPRECATED, removing in clang-17; "
"use '-fstrict-flex-arrays=<N>' instead]",
true)
ANALYZER_OPTION(

View File

@ -1018,6 +1018,15 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
A->claim();
Opts.Config[key] = std::string(val);
// FIXME: Remove this hunk after clang-17 released.
constexpr auto SingleFAM =
"consider-single-element-arrays-as-flexible-array-members";
if (key == SingleFAM) {
Diags.Report(diag::warn_analyzer_deprecated_option_with_alternative)
<< SingleFAM << "clang-17"
<< "-fstrict-flex-arrays=<N>";
}
}
}

View File

@ -790,22 +790,30 @@ DefinedOrUnknownSVal MemRegionManager::getStaticSize(const MemRegion *MR,
return true;
if (const auto *CAT = dyn_cast<ConstantArrayType>(AT)) {
const llvm::APInt &Size = CAT->getSize();
if (Size.isZero())
return true;
using FAMKind = LangOptions::StrictFlexArraysLevelKind;
const FAMKind StrictFlexArraysLevel =
Ctx.getLangOpts().getStrictFlexArraysLevel();
if (StrictFlexArraysLevel == FAMKind::ZeroOrIncomplete ||
StrictFlexArraysLevel == FAMKind::IncompleteOnly)
return false;
const AnalyzerOptions &Opts = SVB.getAnalyzerOptions();
// FIXME: this option is probably redundant with -fstrict-flex-arrays=1.
if (Opts.ShouldConsiderSingleElementArraysAsFlexibleArrayMembers &&
Size.isOne())
const llvm::APInt &Size = CAT->getSize();
if (StrictFlexArraysLevel <= FAMKind::ZeroOrIncomplete && Size.isZero())
return true;
// The "-fstrict-flex-arrays" should have precedence over
// consider-single-element-arrays-as-flexible-array-members
// analyzer-config when checking single element arrays.
if (StrictFlexArraysLevel == FAMKind::Default) {
// FIXME: After clang-17 released, we should remove this branch.
if (Opts.ShouldConsiderSingleElementArraysAsFlexibleArrayMembers &&
Size.isOne())
return true;
} else {
// -fstrict-flex-arrays was specified, since it's not the default, so
// ignore analyzer-config.
if (StrictFlexArraysLevel <= FAMKind::OneZeroOrIncomplete &&
Size.isOne())
return true;
}
}
return false;
};

View File

@ -9,6 +9,15 @@
// RUN: | FileCheck %s --check-prefixes=DEPRECATED-NESTED-BLOCKS
// DEPRECATED-NESTED-BLOCKS: error: unknown argument: '-analyzer-opt-analyze-nested-blocks'
// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-config consider-single-element-arrays-as-flexible-array-members=true %s 2>&1 \
// RUN: | FileCheck %s --check-prefixes=CHECK,DEPRECATED-SINGLE-ELEM-FAM
// DEPRECATED-SINGLE-ELEM-FAM: warning: analyzer option 'consider-single-element-arrays-as-flexible-array-members' is deprecated. This flag will be removed in clang-17, and passing this option will be an error. Use '-fstrict-flex-arrays=<N>' instead.
// RUN: %clang_analyze_cc1 -analyzer-config-help 2>&1 \
// RUN: | FileCheck %s --check-prefixes=CHECK-HELP
// CHECK-HELP: [DEPRECATED, removing in clang-17; use '-fstrict-flex-arrays=<N>'
// CHECK-HELP-NEXT: instead] (default: true)
int empty(int x) {
// CHECK: warning: Division by zero
return x ? 0 : 0 / x;

View File

@ -1,27 +1,30 @@
// -fstrict-flex-arrays=2 means that only undefined or zero element arrays are considered as FAMs.
// RUN: %clang_analyze_cc1 -triple x86_64-linux-gnu -analyzer-checker=core,unix,debug.ExprInspection %s -verify -std=c90 \
// RUN: -analyzer-config consider-single-element-arrays-as-flexible-array-members=false
// RUN: -fstrict-flex-arrays=2
// RUN: %clang_analyze_cc1 -triple x86_64-linux-gnu -analyzer-checker=core,unix,debug.ExprInspection %s -verify -std=c99 \
// RUN: -analyzer-config consider-single-element-arrays-as-flexible-array-members=false
// RUN: -fstrict-flex-arrays=2
// RUN: %clang_analyze_cc1 -triple x86_64-linux-gnu -analyzer-checker=core,unix,debug.ExprInspection %s -verify -std=c11 \
// RUN: -analyzer-config consider-single-element-arrays-as-flexible-array-members=false
// RUN: -fstrict-flex-arrays=2
// RUN: %clang_analyze_cc1 -triple x86_64-linux-gnu -analyzer-checker=core,unix,debug.ExprInspection %s -verify -std=c17 \
// RUN: -analyzer-config consider-single-element-arrays-as-flexible-array-members=false
// RUN: -fstrict-flex-arrays=2
// RUN: %clang_analyze_cc1 -triple x86_64-linux-gnu -analyzer-checker=core,unix,debug.ExprInspection %s -verify -std=c++98 -x c++ \
// RUN: -analyzer-config consider-single-element-arrays-as-flexible-array-members=false
// RUN: -fstrict-flex-arrays=2
// RUN: %clang_analyze_cc1 -triple x86_64-linux-gnu -analyzer-checker=core,unix,debug.ExprInspection %s -verify -std=c++03 -x c++ \
// RUN: -analyzer-config consider-single-element-arrays-as-flexible-array-members=false
// RUN: -fstrict-flex-arrays=2
// RUN: %clang_analyze_cc1 -triple x86_64-linux-gnu -analyzer-checker=core,unix,debug.ExprInspection %s -verify -std=c++11 -x c++ \
// RUN: -analyzer-config consider-single-element-arrays-as-flexible-array-members=false
// RUN: -fstrict-flex-arrays=2
// RUN: %clang_analyze_cc1 -triple x86_64-linux-gnu -analyzer-checker=core,unix,debug.ExprInspection %s -verify -std=c++14 -x c++ \
// RUN: -analyzer-config consider-single-element-arrays-as-flexible-array-members=false
// RUN: -fstrict-flex-arrays=2
// RUN: %clang_analyze_cc1 -triple x86_64-linux-gnu -analyzer-checker=core,unix,debug.ExprInspection %s -verify -std=c++17 -x c++ \
// RUN: -analyzer-config consider-single-element-arrays-as-flexible-array-members=false
// RUN: -fstrict-flex-arrays=2
// By default, -fstrict-flex-arrays=0, which means that even single element arrays are considered as FAMs.
// RUN: %clang_analyze_cc1 -triple x86_64-linux-gnu -analyzer-checker=core,unix,debug.ExprInspection %s -verify -std=c17 \
// RUN: -analyzer-config consider-single-element-arrays-as-flexible-array-members=true -DSINGLE_ELEMENT_FAMS
// RUN: -DSINGLE_ELEMENT_FAMS
// RUN: %clang_analyze_cc1 -triple x86_64-linux-gnu -analyzer-checker=core,unix,debug.ExprInspection %s -verify -std=c++17 -x c++ \
// RUN: -analyzer-config consider-single-element-arrays-as-flexible-array-members=true -DSINGLE_ELEMENT_FAMS
// RUN: -DSINGLE_ELEMENT_FAMS
typedef __typeof(sizeof(int)) size_t;
size_t clang_analyzer_getExtent(void *);