Skip to content

Commit

Permalink
[analyzer] UnixAPIMisuseChecker Get O_CREAT from preprocessor (#81855)
Browse files Browse the repository at this point in the history
Now calling `open` with the `O_CREAT` flag and no mode parameter will
raise an issue in any system that defines `O_CREAT`.

The value for this flag is obtained after the full source code has been
parsed, leveraging `checkASTDecl`.
Hence, any `#define` or `#undefine` of `O_CREAT` following an `open` may
alter the results. Nevertheless, since redefining reserved identifiers
is UB, this is probably ok.
  • Loading branch information
alejandro-alvarez-sonarsource committed Feb 20, 2024
1 parent c7799fa commit 37c19f9
Show file tree
Hide file tree
Showing 4 changed files with 404 additions and 357 deletions.
42 changes: 24 additions & 18 deletions clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
Expand All @@ -39,13 +40,18 @@ enum class OpenVariant {

namespace {

class UnixAPIMisuseChecker : public Checker< check::PreStmt<CallExpr> > {
class UnixAPIMisuseChecker
: public Checker<check::PreStmt<CallExpr>,
check::ASTDecl<TranslationUnitDecl>> {
const BugType BT_open{this, "Improper use of 'open'", categories::UnixAPI};
const BugType BT_pthreadOnce{this, "Improper use of 'pthread_once'",
categories::UnixAPI};
mutable std::optional<uint64_t> Val_O_CREAT;

public:
void checkASTDecl(const TranslationUnitDecl *TU, AnalysisManager &Mgr,
BugReporter &BR) const;

void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;

void CheckOpen(CheckerContext &C, const CallExpr *CE) const;
Expand All @@ -55,11 +61,8 @@ class UnixAPIMisuseChecker : public Checker< check::PreStmt<CallExpr> > {
void CheckOpenVariant(CheckerContext &C,
const CallExpr *CE, OpenVariant Variant) const;

void ReportOpenBug(CheckerContext &C,
ProgramStateRef State,
const char *Msg,
void ReportOpenBug(CheckerContext &C, ProgramStateRef State, const char *Msg,
SourceRange SR) const;

};

class UnixAPIPortabilityChecker : public Checker< check::PreStmt<CallExpr> > {
Expand Down Expand Up @@ -90,7 +93,21 @@ class UnixAPIPortabilityChecker : public Checker< check::PreStmt<CallExpr> > {
const char *fn) const;
};

} //end anonymous namespace
} // end anonymous namespace

void UnixAPIMisuseChecker::checkASTDecl(const TranslationUnitDecl *TU,
AnalysisManager &Mgr,
BugReporter &) const {
// The definition of O_CREAT is platform specific.
// Try to get the macro value from the preprocessor.
Val_O_CREAT = tryExpandAsInteger("O_CREAT", Mgr.getPreprocessor());
// If we failed, fall-back to known values.
if (!Val_O_CREAT) {
if (TU->getASTContext().getTargetInfo().getTriple().getVendor() ==
llvm::Triple::Apple)
Val_O_CREAT = 0x0200;
}
}

//===----------------------------------------------------------------------===//
// "open" (man 2 open)
Expand Down Expand Up @@ -204,19 +221,8 @@ void UnixAPIMisuseChecker::CheckOpenVariant(CheckerContext &C,
return;
}

// The definition of O_CREAT is platform specific. We need a better way
// of querying this information from the checking environment.
if (!Val_O_CREAT) {
if (C.getASTContext().getTargetInfo().getTriple().getVendor()
== llvm::Triple::Apple)
Val_O_CREAT = 0x0200;
else {
// FIXME: We need a more general way of getting the O_CREAT value.
// We could possibly grovel through the preprocessor state, but
// that would require passing the Preprocessor object to the ExprEngine.
// See also: MallocChecker.cpp / M_ZERO.
return;
}
return;
}

// Now check if oflags has O_CREAT set.
Expand Down

0 comments on commit 37c19f9

Please sign in to comment.