Skip to content

Commit

Permalink
[analyzer] Fix modeling some library functions when UCHAR_MAX > INT_MAX.
Browse files Browse the repository at this point in the history
This makes life easier for downstream users who maintain exotic
target platforms.

Patch by Vince Bridgers!

Differential Revision: https://reviews.llvm.org/D75529
  • Loading branch information
haoNoQ committed Mar 16, 2020
1 parent 54146cb commit 0eba5dc
Showing 1 changed file with 27 additions and 15 deletions.
42 changes: 27 additions & 15 deletions clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
Expand Up @@ -510,8 +510,14 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
const RangeInt LongMax = BVF.getMaxValue(LongTy).getLimitedValue();
const RangeInt LongLongMax = BVF.getMaxValue(LongLongTy).getLimitedValue();

const RangeInt UCharMax =
BVF.getMaxValue(ACtx.UnsignedCharTy).getLimitedValue();
// Set UCharRangeMax to min of int or uchar maximum value.
// The C standard states that the arguments of functions like isalpha must
// be representable as an unsigned char. Their type is 'int', so the max
// value of the argument should be min(UCharMax, IntMax). This just happen
// to be true for commonly used and well tested instruction set
// architectures, but not for others.
const RangeInt UCharRangeMax =
std::min(BVF.getMaxValue(ACtx.UnsignedCharTy).getLimitedValue(), IntMax);

// The platform dependent value of EOF.
// Try our best to parse this from the Preprocessor, otherwise fallback to -1.
Expand Down Expand Up @@ -573,8 +579,8 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
// Templates for summaries that are reused by many functions.
auto Getc = [&]() {
return Summary(ArgTypes{Irrelevant}, RetType{IntTy}, NoEvalCall)
.Case(
{ReturnValueCondition(WithinRange, {{EOFv, EOFv}, {0, UCharMax}})});
.Case({ReturnValueCondition(WithinRange,
{{EOFv, EOFv}, {0, UCharRangeMax}})});
};
auto Read = [&](RetType R, RangeInt Max) {
return Summary(ArgTypes{Irrelevant, Irrelevant, SizeTy}, RetType{R},
Expand Down Expand Up @@ -609,12 +615,13 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
// The locale-specific range.
// No post-condition. We are completely unaware of
// locale-specific return values.
.Case({ArgumentCondition(0U, WithinRange, {{128, UCharMax}})})
.Case({ArgumentCondition(0U, WithinRange,
{{128, UCharRangeMax}})})
.Case({ArgumentCondition(0U, OutOfRange,
{{'0', '9'},
{'A', 'Z'},
{'a', 'z'},
{128, UCharMax}}),
{128, UCharRangeMax}}),
ReturnValueCondition(WithinRange, SingleValue(0))})},
},
{
Expand All @@ -625,10 +632,11 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
{{'A', 'Z'}, {'a', 'z'}}),
ReturnValueCondition(OutOfRange, SingleValue(0))})
// The locale-specific range.
.Case({ArgumentCondition(0U, WithinRange, {{128, UCharMax}})})
.Case({ArgumentCondition(0U, WithinRange,
{{128, UCharRangeMax}})})
.Case({ArgumentCondition(
0U, OutOfRange,
{{'A', 'Z'}, {'a', 'z'}, {128, UCharMax}}),
{{'A', 'Z'}, {'a', 'z'}, {128, UCharRangeMax}}),
ReturnValueCondition(WithinRange, SingleValue(0))})},
},
{
Expand Down Expand Up @@ -692,9 +700,11 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
ArgumentCondition(0U, OutOfRange, Range('a', 'z')),
ReturnValueCondition(WithinRange, SingleValue(0))})
// The locale-specific range.
.Case({ArgumentCondition(0U, WithinRange, {{128, UCharMax}})})
.Case({ArgumentCondition(0U, WithinRange,
{{128, UCharRangeMax}})})
// Is not an unsigned char.
.Case({ArgumentCondition(0U, OutOfRange, Range(0, UCharMax)),
.Case({ArgumentCondition(0U, OutOfRange,
Range(0, UCharRangeMax)),
ReturnValueCondition(WithinRange, SingleValue(0))})},
},
{
Expand Down Expand Up @@ -728,10 +738,11 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
{{9, 13}, {' ', ' '}}),
ReturnValueCondition(OutOfRange, SingleValue(0))})
// The locale-specific range.
.Case({ArgumentCondition(0U, WithinRange, {{128, UCharMax}})})
.Case({ArgumentCondition(0U, WithinRange,
{{128, UCharRangeMax}})})
.Case({ArgumentCondition(
0U, OutOfRange,
{{9, 13}, {' ', ' '}, {128, UCharMax}}),
{{9, 13}, {' ', ' '}, {128, UCharRangeMax}}),
ReturnValueCondition(WithinRange, SingleValue(0))})},
},
{
Expand All @@ -742,10 +753,11 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
.Case({ArgumentCondition(0U, WithinRange, Range('A', 'Z')),
ReturnValueCondition(OutOfRange, SingleValue(0))})
// The locale-specific range.
.Case({ArgumentCondition(0U, WithinRange, {{128, UCharMax}})})
.Case({ArgumentCondition(0U, WithinRange,
{{128, UCharRangeMax}})})
// Other.
.Case({ArgumentCondition(0U, OutOfRange,
{{'A', 'Z'}, {128, UCharMax}}),
{{'A', 'Z'}, {128, UCharRangeMax}}),
ReturnValueCondition(WithinRange, SingleValue(0))})},
},
{
Expand All @@ -768,7 +780,7 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
{"getchar",
Summaries{Summary(ArgTypes{}, RetType{IntTy}, NoEvalCall)
.Case({ReturnValueCondition(
WithinRange, {{EOFv, EOFv}, {0, UCharMax}})})}},
WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}})})}},

// read()-like functions that never return more than buffer size.
// We are not sure how ssize_t is defined on every platform, so we
Expand Down

0 comments on commit 0eba5dc

Please sign in to comment.