Szelethus created this revision.
Szelethus added reviewers: NoQ, george.karpenkov, rnkovacs, xazax.hun.
Herald added subscribers: cfe-commits, mikhail.ramalho, a.sidorin, szepet, 
whisperity.

The idea came from both @george.karpenkov 
(https://reviews.llvm.org/D45532#1145592) and from bugzilla 
(https://bugs.llvm.org/show_bug.cgi?id=37965).

Assigning an object with uninitialized value to a pointer/reference could be 
intentional, especially if one writes a class that just initializes values.

  struct Initializer {
    int *a;
  
    void initialize(/* ... */) {
      a = /* ... */;
    }
    
    Initializer(int *a) : a(a) {}
  };
  
  void f() {
    int b;
    Initializer init(&b);
    // ...
    init.initialize(/* ... */);
  }

I actually have seen some examples for this in LLVM. While I absolutely agree 
that a flag like this would be neat, I also think that it should be disabled by 
default, as for example some objects are only created with `malloc`/`new`, and 
because I didn't find this functionality to be too noisy.


Repository:
  rC Clang

https://reviews.llvm.org/D49438

Files:
  lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
  test/Analysis/cxx-uninitialized-no-dereference.cpp

Index: test/Analysis/cxx-uninitialized-no-dereference.cpp
===================================================================
--- /dev/null
+++ test/Analysis/cxx-uninitialized-no-dereference.cpp
@@ -0,0 +1,26 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.UninitializedObject -analyzer-config alpha.cplusplus.UninitializedObject:NoDereference=true -std=c++11 -DPEDANTIC -verify %s
+
+class UninitPointerTest {
+  int *ptr; // expected-note{{uninitialized pointer 'this->ptr'}}
+  int dontGetFilteredByNonPedanticMode = 0;
+
+public:
+  UninitPointerTest() {} // expected-warning{{1 uninitialized field}}
+};
+
+void fUninitPointerTest() {
+  UninitPointerTest();
+}
+
+class UninitPointeeTest {
+  int *ptr; // no-note
+  int dontGetFilteredByNonPedanticMode = 0;
+
+public:
+  UninitPointeeTest(int *ptr) : ptr(ptr) {} // no-warning
+};
+
+void fUninitPointeeTest() {
+  int a;
+  UninitPointeeTest t(&a);
+}
Index: lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
===================================================================
--- lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
+++ lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
@@ -10,7 +10,7 @@
 // This file defines a checker that reports uninitialized fields in objects
 // created after a constructor call.
 //
-// This checker has two options:
+// This checker has several options:
 //   - "Pedantic" (boolean). If its not set or is set to false, the checker
 //     won't emit warnings for objects that don't have at least one initialized
 //     field. This may be set with
@@ -24,6 +24,12 @@
 //
 //  `-analyzer-config alpha.cplusplus.UninitializedObject:NotesAsWarnings=true`.
 //
+//   - "NoDereference" (boolean). If set to true, the checker will not analyze
+//     the pointee of pointer/reference fields, and will only check whether the
+//     object itself is initialized. Defaults to false.
+//
+//  `-analyzer-config alpha.cplusplus.UninitializedObject:NoDereference=true`.
+//
 //===----------------------------------------------------------------------===//
 
 #include "ClangSACheckers.h"
@@ -44,6 +50,7 @@
   // These fields will be initialized when registering the checker.
   bool IsPedantic;
   bool ShouldConvertNotesToWarnings;
+  bool ShouldDereference;
 
   UninitializedObjectChecker()
       : BT_uninitField(new BuiltinBug(this, "Uninitialized fields")) {}
@@ -109,13 +116,16 @@
   const TypedValueRegion *const ObjectR;
 
   const bool IsPedantic;
+  const bool ShouldDereference;
+
   bool IsAnyFieldInitialized = false;
 
   UninitFieldSet UninitFields;
 
 public:
   FindUninitializedFields(ProgramStateRef State,
-                          const TypedValueRegion *const R, bool IsPedantic);
+                          const TypedValueRegion *const R, bool IsPedantic,
+                          bool ShouldDereference);
   const UninitFieldSet &getUninitFields();
 
 private:
@@ -261,8 +271,8 @@
   if (!Object)
     return;
 
-  FindUninitializedFields F(Context.getState(), Object->getRegion(),
-                            IsPedantic);
+  FindUninitializedFields F(Context.getState(), Object->getRegion(), IsPedantic,
+                            ShouldDereference);
 
   const UninitFieldSet &UninitFields = F.getUninitFields();
 
@@ -326,8 +336,10 @@
 //===----------------------------------------------------------------------===//
 
 FindUninitializedFields::FindUninitializedFields(
-    ProgramStateRef State, const TypedValueRegion *const R, bool IsPedantic)
-    : State(State), ObjectR(R), IsPedantic(IsPedantic) {}
+    ProgramStateRef State, const TypedValueRegion *const R, bool IsPedantic,
+    bool ShouldDereference)
+    : State(State), ObjectR(R), IsPedantic(IsPedantic),
+      ShouldDereference(ShouldDereference) {}
 
 const UninitFieldSet &FindUninitializedFields::getUninitFields() {
   isNonUnionUninit(ObjectR, FieldChainInfo());
@@ -474,6 +486,11 @@
     return addFieldToUninits({LocalChain, FR});
   }
 
+  if (!ShouldDereference) {
+    IsAnyFieldInitialized = true;
+    return false;
+  }
+
   const FieldDecl *FD = FR->getDecl();
 
   // TODO: The dynamic type of a void pointer may be retrieved with
@@ -700,4 +717,6 @@
       "Pedantic", /*DefaultVal*/ false, Chk);
   Chk->ShouldConvertNotesToWarnings = Mgr.getAnalyzerOptions().getBooleanOption(
       "NotesAsWarnings", /*DefaultVal*/ false, Chk);
+  Chk->ShouldDereference = !Mgr.getAnalyzerOptions().getBooleanOption(
+      "NoDereference", /*DefaultVal*/ false, Chk);
 }
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to