Skip to content

Commit 2e81f7d

Browse files
authored
[analyzer] Fix crash in Stream checker when using void pointers (#97199)
We can get zero type size (thus div by zero crash) if the region is for a 'void*' pointer. In this patch, let's just override the void type with a char type to avoid the crash. Fixes #93408 (comment)
1 parent ae570d8 commit 2e81f7d

File tree

2 files changed

+56
-8
lines changed

2 files changed

+56
-8
lines changed

clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1034,16 +1034,16 @@ void StreamChecker::preWrite(const FnDescription *Desc, const CallEvent &Call,
10341034
C.addTransition(State);
10351035
}
10361036

1037-
static std::optional<QualType> getPointeeType(const MemRegion *R) {
1037+
static QualType getPointeeType(const MemRegion *R) {
10381038
if (!R)
1039-
return std::nullopt;
1039+
return {};
10401040
if (const auto *ER = dyn_cast<ElementRegion>(R))
10411041
return ER->getElementType();
10421042
if (const auto *TR = dyn_cast<TypedValueRegion>(R))
10431043
return TR->getValueType();
10441044
if (const auto *SR = dyn_cast<SymbolicRegion>(R))
10451045
return SR->getPointeeStaticType();
1046-
return std::nullopt;
1046+
return {};
10471047
}
10481048

10491049
static std::optional<NonLoc> getStartIndex(SValBuilder &SVB,
@@ -1073,7 +1073,8 @@ tryToInvalidateFReadBufferByElements(ProgramStateRef State, CheckerContext &C,
10731073
const auto *Buffer =
10741074
dyn_cast_or_null<SubRegion>(Call.getArgSVal(0).getAsRegion());
10751075

1076-
std::optional<QualType> ElemTy = getPointeeType(Buffer);
1076+
const ASTContext &Ctx = C.getASTContext();
1077+
QualType ElemTy = getPointeeType(Buffer);
10771078
std::optional<SVal> StartElementIndex =
10781079
getStartIndex(C.getSValBuilder(), Buffer);
10791080

@@ -1086,18 +1087,20 @@ tryToInvalidateFReadBufferByElements(ProgramStateRef State, CheckerContext &C,
10861087
std::optional<int64_t> StartIndexVal =
10871088
getKnownValue(State, StartElementIndex.value_or(UnknownVal()));
10881089

1089-
if (ElemTy && CountVal && Size && StartIndexVal) {
1090+
if (!ElemTy.isNull() && CountVal && Size && StartIndexVal) {
10901091
int64_t NumBytesRead = Size.value() * CountVal.value();
1091-
int64_t ElemSizeInChars =
1092-
C.getASTContext().getTypeSizeInChars(*ElemTy).getQuantity();
1092+
int64_t ElemSizeInChars = Ctx.getTypeSizeInChars(ElemTy).getQuantity();
1093+
if (ElemSizeInChars == 0)
1094+
return nullptr;
1095+
10931096
bool IncompleteLastElement = (NumBytesRead % ElemSizeInChars) != 0;
10941097
int64_t NumCompleteOrIncompleteElementsRead =
10951098
NumBytesRead / ElemSizeInChars + IncompleteLastElement;
10961099

10971100
constexpr int MaxInvalidatedElementsLimit = 64;
10981101
if (NumCompleteOrIncompleteElementsRead <= MaxInvalidatedElementsLimit) {
10991102
return escapeByStartIndexAndCount(State, Call, C.blockCount(), Buffer,
1100-
*ElemTy, *StartIndexVal,
1103+
ElemTy, *StartIndexVal,
11011104
NumCompleteOrIncompleteElementsRead);
11021105
}
11031106
}

clang/test/Analysis/stream.c

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -453,3 +453,48 @@ void getline_buffer_size_negative() {
453453
free(buffer);
454454
fclose(file);
455455
}
456+
457+
void gh_93408_regression(void *buffer) {
458+
FILE *f = fopen("/tmp/foo.txt", "r");
459+
fread(buffer, 1, 1, f); // expected-warning {{Stream pointer might be NULL}} no-crash
460+
fclose(f);
461+
}
462+
463+
typedef void VOID;
464+
void gh_93408_regression_typedef(VOID *buffer) {
465+
FILE *f = fopen("/tmp/foo.txt", "r");
466+
fread(buffer, 1, 1, f); // expected-warning {{Stream pointer might be NULL}} no-crash
467+
fclose(f);
468+
}
469+
470+
struct FAM {
471+
int data;
472+
int tail[];
473+
};
474+
475+
struct FAM0 {
476+
int data;
477+
int tail[0];
478+
};
479+
480+
void gh_93408_regression_FAM(struct FAM *p) {
481+
FILE *f = fopen("/tmp/foo.txt", "r");
482+
fread(p->tail, 1, 1, f); // expected-warning {{Stream pointer might be NULL}}
483+
fclose(f);
484+
}
485+
486+
void gh_93408_regression_FAM0(struct FAM0 *p) {
487+
FILE *f = fopen("/tmp/foo.txt", "r");
488+
fread(p->tail, 1, 1, f); // expected-warning {{Stream pointer might be NULL}}
489+
fclose(f);
490+
}
491+
492+
struct ZeroSized {
493+
int data[0];
494+
};
495+
496+
void gh_93408_regression_ZeroSized(struct ZeroSized *buffer) {
497+
FILE *f = fopen("/tmp/foo.txt", "r");
498+
fread(buffer, 1, 1, f); // expected-warning {{Stream pointer might be NULL}} no-crash
499+
fclose(f);
500+
}

0 commit comments

Comments
 (0)