[clang] [clang][analyzer] Model more getline/getdelim pre and postconditions (PR #83027)
Balazs Benics via cfe-commits
cfe-commits at lists.llvm.org
Thu Mar 7 04:41:39 PST 2024
Alejandro =?utf-8?q?Álvarez_Ayllón?Message-ID:
In-Reply-To: <llvm.org/llvm/llvm-project/pull/83027 at github.com>
================
@@ -1158,6 +1173,123 @@ void StreamChecker::evalUngetc(const FnDescription *Desc, const CallEvent &Call,
C.addTransition(StateFailed);
}
+ProgramStateRef
+StreamChecker::ensurePtrNotNull(SVal PtrVal, const Expr *PtrExpr,
+ CheckerContext &C, ProgramStateRef State,
+ const StringRef PtrDescr) const {
+ const auto Ptr = PtrVal.getAs<DefinedSVal>();
+ if (!Ptr)
+ return nullptr;
+
+ assert(PtrExpr && "Expected an argument");
+
+ const auto [PtrNotNull, PtrNull] = State->assume(*Ptr);
+ if (!PtrNotNull && PtrNull) {
+ if (ExplodedNode *N = C.generateErrorNode(PtrNull)) {
+ SmallString<256> buf;
+ llvm::raw_svector_ostream os(buf);
+ os << PtrDescr << " pointer might be NULL.";
+
+ auto R = std::make_unique<PathSensitiveBugReport>(BT_SizeNull, buf, N);
+ bugreporter::trackExpressionValue(N, PtrExpr, *R);
+ C.emitReport(std::move(R));
+ }
+ return nullptr;
+ }
+
+ return PtrNotNull;
+}
+
+ProgramStateRef StreamChecker::ensureSizeZeroIfLineNull(
+ SVal LinePtrPtrSVal, SVal SizePtrSVal, const Expr *LinePtrPtrExpr,
+ const Expr *SizePtrExpr, CheckerContext &C, ProgramStateRef State) const {
+ static constexpr char SizeNotZeroMsg[] =
+ "Line pointer might be null while n value is not zero";
+
+ // We have a pointer to a pointer to the buffer, and a pointer to the size.
+ // We want what they point at.
+ auto LinePtrSVal = getPointeeDefVal(LinePtrPtrSVal, State);
+ auto NSVal = getPointeeDefVal(SizePtrSVal, State);
+ if (!LinePtrSVal || !NSVal)
+ return nullptr;
+
+ assert(LinePtrPtrExpr &&
+ "Expected an argument with a pointer to a pointer to the buffer.");
+ assert(SizePtrExpr &&
+ "Expected an argument with a pointer to the buffer size.");
+
+ // If the line pointer is null, and n is > 0, there is UB.
+ const auto [LinePtrNotNull, LinePtrNull] = State->assume(*LinePtrSVal);
+ if (LinePtrNull && !LinePtrNotNull) {
+ const auto [NIsNotZero, NIsZero] = LinePtrNull->assume(*NSVal);
+ if (NIsNotZero && !NIsZero) {
+ if (ExplodedNode *N = C.generateErrorNode(NIsNotZero)) {
+ auto R = std::make_unique<PathSensitiveBugReport>(BT_SizeNotZero,
+ SizeNotZeroMsg, N);
+ bugreporter::trackExpressionValue(N, SizePtrExpr, *R);
+ bugreporter::trackExpressionValue(N, LinePtrPtrExpr, *R);
+ C.emitReport(std::move(R));
+ }
+ return nullptr;
+ }
+ return NIsZero;
+ }
+ return LinePtrNotNull;
+}
+
+void StreamChecker::preGetdelim(const FnDescription *Desc,
+ const CallEvent &Call,
+ CheckerContext &C) const {
+ ProgramStateRef State = C.getState();
+ SVal StreamVal = getStreamArg(Desc, Call);
+
+ auto AddTransitionOnReturn = llvm::make_scope_exit([&] {
+ if (State != nullptr) {
+ C.addTransition(State);
+ }
+ });
+
+ State = ensureStreamNonNull(StreamVal, Call.getArgExpr(Desc->StreamArgNo), C,
+ State);
+ if (!State)
+ return;
+ State = ensureStreamOpened(StreamVal, C, State);
+ if (!State)
+ return;
+ State = ensureNoFilePositionIndeterminate(StreamVal, C, State);
+ if (!State)
+ return;
+
+ // The parameter `n` must not be NULL.
+ SVal SizePtrSval = Call.getArgSVal(1);
+ State = ensurePtrNotNull(SizePtrSval, Call.getArgExpr(1), C, State, "Size");
+ if (!State)
+ return;
+
+ // The parameter `lineptr` must not be NULL.
+ SVal LinePtrPtrSVal = Call.getArgSVal(0);
+ State =
+ ensurePtrNotNull(LinePtrPtrSVal, Call.getArgExpr(0), C, State, "Line");
+ if (!State)
+ return;
+
+ // If `lineptr` points to a NULL pointer, `*n` must be 0.
+ State =
+ ensureSizeZeroIfLineNull(LinePtrPtrSVal, SizePtrSval, Call.getArgExpr(0),
+ Call.getArgExpr(1), C, State);
+ if (!State)
+ return;
+
+ SymbolRef Sym = StreamVal.getAsSymbol();
+ if (Sym && State->get<StreamMap>(Sym)) {
+ const StreamState *SS = State->get<StreamMap>(Sym);
+ if (SS->ErrorState & ErrorFEof)
+ reportFEofWarning(Sym, C, State);
+ } else {
+ C.addTransition(State);
+ }
----------------
steakhal wrote:
```suggestion
}
```
You add this transition anyways via the scope_exit.
https://github.com/llvm/llvm-project/pull/83027
More information about the cfe-commits
mailing list