giannicrivello created this revision.
giannicrivello added reviewers: NoQ, tbaeder.
giannicrivello added a project: clang.
Herald added subscribers: steakhal, martong.
Herald added a reviewer: sscalpone.
Herald added projects: Flang, All.
giannicrivello requested review of this revision.
Herald added subscribers: cfe-commits, jdoerfert.

Patched llvm-project/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp to 
account for the user passing a nullptr to the implementation dependent function 
printf(). Invoked with `bin/scan-build -enable-checker optin.portability 
bin/clang -g test.cpp` where the contents of test.cpp is:

  c++
  #include <stdio.h>
  #include <stdlib.h>
  
  int main() {
      int *p = nullptr;
      printf("%p", p);
  }

now produces the warning:

  test.cpp:6:5: warning: Passing a null pointer to printf() is implementation 
dependant. Portability warning [optin.portability.UnixAPI]
      printf("%p", p);
      ^~~~~~~~~~~~~~~
  1 warning generated.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D139604

Files:
  clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
  clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
  flang/docs/Extensions.md
  flang/lib/Parser/Fortran-parsers.cpp
  flang/test/Parser/missing-colons.f90

Index: flang/test/Parser/missing-colons.f90
===================================================================
--- /dev/null
+++ flang/test/Parser/missing-colons.f90
@@ -0,0 +1,13 @@
+! RUN: %flang_fc1 -fsyntax-only -pedantic %s 2>&1 | FileCheck %s
+module m
+  type t
+   contains
+!CHECK: portability: type-bound procedure statement should have '::' if it has '=>'
+    procedure p => sub
+  end type
+ contains
+  subroutine sub(x)
+    class(t), intent(in) :: x
+  end subroutine
+end module
+
Index: flang/lib/Parser/Fortran-parsers.cpp
===================================================================
--- flang/lib/Parser/Fortran-parsers.cpp
+++ flang/lib/Parser/Fortran-parsers.cpp
@@ -522,6 +522,9 @@
 // R749 type-bound-procedure-stmt ->
 //        PROCEDURE [[, bind-attr-list] ::] type-bound-proc-decl-list |
 //        PROCEDURE ( interface-name ) , bind-attr-list :: binding-name-list
+// The "::" is required by the standard (C768) in the first production if
+// any type-bound-proc-decl has a "=>', but it's not strictly necessary to
+// avoid a bad parse.
 TYPE_CONTEXT_PARSER("type bound PROCEDURE statement"_en_US,
     "PROCEDURE" >>
         (construct<TypeBoundProcedureStmt>(
@@ -531,6 +534,15 @@
                      "," >> nonemptyList(Parser<BindAttr>{}), ok),
                  localRecovery("expected list of binding names"_err_en_US,
                      "::" >> listOfNames, SkipTo<'\n'>{}))) ||
+            construct<TypeBoundProcedureStmt>(construct<
+                TypeBoundProcedureStmt::WithoutInterface>(
+                pure<std::list<BindAttr>>(),
+                nonemptyList(
+                    "expected type bound procedure declarations"_err_en_US,
+                    construct<TypeBoundProcDecl>(name,
+                        maybe(extension<LanguageFeature::MissingColons>(
+                            "type-bound procedure statement should have '::' if it has '=>'"_port_en_US,
+                            "=>" >> name)))))) ||
             construct<TypeBoundProcedureStmt>(
                 construct<TypeBoundProcedureStmt::WithoutInterface>(
                     optionalListBeforeColons(Parser<BindAttr>{}),
Index: flang/docs/Extensions.md
===================================================================
--- flang/docs/Extensions.md
+++ flang/docs/Extensions.md
@@ -242,6 +242,11 @@
   compilers, so it is not supported.
 * f18 doesn't impose a limit on the number of continuation lines
   allowed for a single statement.
+* When a type-bound procedure declaration statement has neither interface
+  nor attributes, the "::" before the bindings is optional, even
+  if a binding has renaming with "=> proc".
+  The colons are not necessary for an unambiguous parse, C768
+  notwithstanding.
 
 ### Extensions supported when enabled by options
 
Index: clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
@@ -11,11 +11,12 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
 #include "clang/Basic/TargetInfo.h"
+#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
 #include "clang/StaticAnalyzer/Core/Checker.h"
 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
 #include "llvm/ADT/Optional.h"
 #include "llvm/ADT/STLExtras.h"
@@ -59,9 +60,11 @@
 
 };
 
-class UnixAPIPortabilityChecker : public Checker< check::PreStmt<CallExpr> > {
+class UnixAPIPortabilityChecker
+    : public Checker<check::PreStmt<CallExpr>, check::PostCall> {
 public:
   void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
+  void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
 
 private:
   mutable std::unique_ptr<BugType> BT_mallocZero;
@@ -493,6 +496,41 @@
     CheckVallocZero(C, CE);
 }
 
+void UnixAPIPortabilityChecker::checkPostCall(const CallEvent &Call,
+                                              CheckerContext &C) const {
+
+  auto State = C.getState();
+
+  const IdentifierInfo *II = Call.getCalleeIdentifier();
+  if (!II)
+    return;
+  if (!II->isStr("printf"))
+    return;
+
+  if (!BT_mallocZero)
+    BT_mallocZero.reset(new BugType(this, "Call to printf", "Example checker"));
+
+  for (unsigned int i = 0; i < Call.getNumArgs(); i++) {
+    const auto *Arg = Call.getArgExpr(i);
+    if (!Arg)
+      return;
+    const auto *LC = C.getLocationContext();
+    auto Val = State->getSVal(Arg, LC);
+    if (Val.isZeroConstant()) {
+      ExplodedNode *N = C.generateErrorNode();
+
+      // Further better the diagnostic message by adding a bug report visitor
+      auto Report = std::make_unique<PathSensitiveBugReport>(
+          *BT_mallocZero,
+          "Passing a null pointer to printf() is implementation dependant. "
+          "Portability warning.",
+          N);
+      Report->addRange(Arg->getSourceRange());
+      C.emitReport(std::move(Report));
+    }
+  }
+}
+
 //===----------------------------------------------------------------------===//
 // Registration.
 //===----------------------------------------------------------------------===//
Index: clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
===================================================================
--- clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -1667,7 +1667,7 @@
 def UnixAPIPortabilityChecker : Checker<"UnixAPI">,
   HelpText<"Finds implementation-defined behavior in UNIX/Posix functions">,
   Documentation<NotDocumented>;
-
+  
 } // end optin.portability
 
 //===----------------------------------------------------------------------===//
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to