From 820e69fba6e9221867afadfc9d8db789db1672b1 Mon Sep 17 00:00:00 2001 From: Jordan Rose Date: Wed, 20 Aug 2014 16:58:03 +0000 Subject: [PATCH] [analyzer] UnixAPI: Check when open(2) is called with more than three arguments. Patch by Daniel Fahlgren. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@216078 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../Checkers/UnixAPIChecker.cpp | 57 ++++++++++++------- test/Analysis/unix-api.c | 27 +++++++++ 2 files changed, 63 insertions(+), 21 deletions(-) create mode 100644 test/Analysis/unix-api.c diff --git a/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp b/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp index 4887d804c6..e7626ca24b 100644 --- a/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp @@ -62,6 +62,10 @@ private: return; BT.reset(new BugType(this, name, categories::UnixAPI)); } + void ReportOpenBug(CheckerContext &C, + ProgramStateRef State, + const char *Msg, + SourceRange SR) const; }; } //end anonymous namespace @@ -69,7 +73,35 @@ private: // "open" (man 2 open) //===----------------------------------------------------------------------===// +void UnixAPIChecker::ReportOpenBug(CheckerContext &C, + ProgramStateRef State, + const char *Msg, + SourceRange SR) const { + ExplodedNode *N = C.generateSink(State); + if (!N) + return; + + LazyInitialize(BT_open, "Improper use of 'open'"); + + BugReport *Report = new BugReport(*BT_open, Msg, N); + Report->addRange(SR); + C.emitReport(Report); +} + void UnixAPIChecker::CheckOpen(CheckerContext &C, const CallExpr *CE) const { + ProgramStateRef state = C.getState(); + + if (CE->getNumArgs() < 2) { + // The frontend should issue a warning for this case, so this is a sanity + // check. + return; + } else if (CE->getNumArgs() > 3) { + ReportOpenBug(C, state, + "Call to 'open' with more than three arguments", + CE->getArg(3)->getSourceRange()); + 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.hasValue()) { @@ -85,15 +117,6 @@ void UnixAPIChecker::CheckOpen(CheckerContext &C, const CallExpr *CE) const { } } - // Look at the 'oflags' argument for the O_CREAT flag. - ProgramStateRef state = C.getState(); - - if (CE->getNumArgs() < 2) { - // The frontend should issue a warning for this case, so this is a sanity - // check. - return; - } - // Now check if oflags has O_CREAT set. const Expr *oflagsEx = CE->getArg(1); const SVal V = state->getSVal(oflagsEx, C.getLocationContext()); @@ -122,18 +145,10 @@ void UnixAPIChecker::CheckOpen(CheckerContext &C, const CallExpr *CE) const { return; if (CE->getNumArgs() < 3) { - ExplodedNode *N = C.generateSink(trueState); - if (!N) - return; - - LazyInitialize(BT_open, "Improper use of 'open'"); - - BugReport *report = - new BugReport(*BT_open, - "Call to 'open' requires a third argument when " - "the 'O_CREAT' flag is set", N); - report->addRange(oflagsEx->getSourceRange()); - C.emitReport(report); + ReportOpenBug(C, trueState, + "Call to 'open' requires a third argument when " + "the 'O_CREAT' flag is set", + oflagsEx->getSourceRange()); } } diff --git a/test/Analysis/unix-api.c b/test/Analysis/unix-api.c new file mode 100644 index 0000000000..4146822e21 --- /dev/null +++ b/test/Analysis/unix-api.c @@ -0,0 +1,27 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.API -verify %s + +#ifndef O_RDONLY +#define O_RDONLY 0 +#endif + +#ifndef NULL +#define NULL ((void*) 0) +#endif + +int open(const char *, int, ...); +int close(int fildes); + +void open_1(const char *path) { + int fd; + fd = open(path, O_RDONLY); // no-warning + if (fd > -1) + close(fd); +} + +void open_2(const char *path) { + int fd; + int mode = 0x0; + fd = open(path, O_RDONLY, mode, NULL); // expected-warning{{Call to 'open' with more than three arguments}} + if (fd > -1) + close(fd); +} -- 2.40.0