From f18bfd44c4fe4ab28c44eecb7aeed618bcf8f627 Mon Sep 17 00:00:00 2001 From: Pavel Labath <labath@google.com> Date: Wed, 28 Aug 2013 08:04:08 +0000 Subject: [PATCH] [analyzer] Assume new returns non-null even under -fno-exceptions Summary: -fno-exceptions does not implicitly attach a nothrow specifier to every operator new. Even in this mode, non-nothrow new must not return a null pointer. Failure to allocate memory can be signalled by other means, or just by killing the program. This behaviour is consistent with the compiler - even with -fno-exceptions, the generated code never tests for null (and would segfault if the opeator actually happened to return null). Reviewers: jordan_rose CC: cfe-commits Differential Revision: http://llvm-reviews.chandlerc.com/D1528 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@189452 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 11 +- test/Analysis/NewDelete-path-notes.cpp | 138 ++++++---------------- test/Analysis/new-with-exceptions.cpp | 32 ++--- 3 files changed, 51 insertions(+), 130 deletions(-) diff --git a/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp index c39d779d697..27963ade934 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -367,11 +367,14 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, if (!State) return; - // If we're compiling with exceptions enabled, and this allocation function - // is not declared as non-throwing, failures /must/ be signalled by - // exceptions, and thus the return value will never be NULL. + // If this allocation function is not declared as non-throwing, failures + // /must/ be signalled by exceptions, and thus the return value will never be + // NULL. -fno-exceptions does not influence this semantics. + // FIXME: GCC has a -fcheck-new option, which forces it to consider the case + // where new can return NULL. If we end up supporting that option, we can + // consider adding a check for it here. // C++11 [basic.stc.dynamic.allocation]p3. - if (FD && getContext().getLangOpts().CXXExceptions) { + if (FD) { QualType Ty = FD->getType(); if (const FunctionProtoType *ProtoType = Ty->getAs<FunctionProtoType>()) if (!ProtoType->isNothrow(getContext())) diff --git a/test/Analysis/NewDelete-path-notes.cpp b/test/Analysis/NewDelete-path-notes.cpp index d38bdb692f2..b420551c3e9 100644 --- a/test/Analysis/NewDelete-path-notes.cpp +++ b/test/Analysis/NewDelete-path-notes.cpp @@ -6,8 +6,7 @@ void test() { int *p = new int; // expected-note@-1 {{Memory is allocated}} if (p) - // expected-note@-1 {{Assuming 'p' is non-null}} - // expected-note@-2 {{Taking true branch}} + // expected-note@-1 {{Taking true branch}} delete p; // expected-note@-1 {{Memory is released}} @@ -151,75 +150,12 @@ void test(Odd *odd) { // CHECK-NEXT: <key>end</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>8</integer> -// CHECK-NEXT: <key>col</key><integer>7</integer> -// CHECK-NEXT: <key>file</key><integer>0</integer> -// CHECK-NEXT: </dict> -// CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>8</integer> -// CHECK-NEXT: <key>col</key><integer>7</integer> -// CHECK-NEXT: <key>file</key><integer>0</integer> -// CHECK-NEXT: </dict> -// CHECK-NEXT: </array> -// CHECK-NEXT: </dict> -// CHECK-NEXT: </array> -// CHECK-NEXT: </dict> -// CHECK-NEXT: <dict> -// CHECK-NEXT: <key>kind</key><string>event</string> -// CHECK-NEXT: <key>location</key> -// CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>8</integer> -// CHECK-NEXT: <key>col</key><integer>7</integer> -// CHECK-NEXT: <key>file</key><integer>0</integer> -// CHECK-NEXT: </dict> -// CHECK-NEXT: <key>ranges</key> -// CHECK-NEXT: <array> -// CHECK-NEXT: <array> -// CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>8</integer> -// CHECK-NEXT: <key>col</key><integer>7</integer> -// CHECK-NEXT: <key>file</key><integer>0</integer> -// CHECK-NEXT: </dict> -// CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>8</integer> -// CHECK-NEXT: <key>col</key><integer>7</integer> -// CHECK-NEXT: <key>file</key><integer>0</integer> -// CHECK-NEXT: </dict> -// CHECK-NEXT: </array> -// CHECK-NEXT: </array> -// CHECK-NEXT: <key>depth</key><integer>0</integer> -// CHECK-NEXT: <key>extended_message</key> -// CHECK-NEXT: <string>Assuming 'p' is non-null</string> -// CHECK-NEXT: <key>message</key> -// CHECK-NEXT: <string>Assuming 'p' is non-null</string> -// CHECK-NEXT: </dict> -// CHECK-NEXT: <dict> -// CHECK-NEXT: <key>kind</key><string>control</string> -// CHECK-NEXT: <key>edges</key> -// CHECK-NEXT: <array> -// CHECK-NEXT: <dict> -// CHECK-NEXT: <key>start</key> -// CHECK-NEXT: <array> -// CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>8</integer> -// CHECK-NEXT: <key>col</key><integer>7</integer> -// CHECK-NEXT: <key>file</key><integer>0</integer> -// CHECK-NEXT: </dict> -// CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>8</integer> -// CHECK-NEXT: <key>col</key><integer>7</integer> -// CHECK-NEXT: <key>file</key><integer>0</integer> -// CHECK-NEXT: </dict> -// CHECK-NEXT: </array> -// CHECK-NEXT: <key>end</key> -// CHECK-NEXT: <array> -// CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>11</integer> +// CHECK-NEXT: <key>line</key><integer>10</integer> // CHECK-NEXT: <key>col</key><integer>5</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>11</integer> +// CHECK-NEXT: <key>line</key><integer>10</integer> // CHECK-NEXT: <key>col</key><integer>10</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -231,7 +167,7 @@ void test(Odd *odd) { // CHECK-NEXT: <key>kind</key><string>event</string> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>11</integer> +// CHECK-NEXT: <key>line</key><integer>10</integer> // CHECK-NEXT: <key>col</key><integer>5</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -239,12 +175,12 @@ void test(Odd *odd) { // CHECK-NEXT: <array> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>11</integer> +// CHECK-NEXT: <key>line</key><integer>10</integer> // CHECK-NEXT: <key>col</key><integer>5</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>11</integer> +// CHECK-NEXT: <key>line</key><integer>10</integer> // CHECK-NEXT: <key>col</key><integer>12</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -264,12 +200,12 @@ void test(Odd *odd) { // CHECK-NEXT: <key>start</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>11</integer> +// CHECK-NEXT: <key>line</key><integer>10</integer> // CHECK-NEXT: <key>col</key><integer>5</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>11</integer> +// CHECK-NEXT: <key>line</key><integer>10</integer> // CHECK-NEXT: <key>col</key><integer>10</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -277,12 +213,12 @@ void test(Odd *odd) { // CHECK-NEXT: <key>end</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>14</integer> +// CHECK-NEXT: <key>line</key><integer>13</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>14</integer> +// CHECK-NEXT: <key>line</key><integer>13</integer> // CHECK-NEXT: <key>col</key><integer>8</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -294,7 +230,7 @@ void test(Odd *odd) { // CHECK-NEXT: <key>kind</key><string>event</string> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>14</integer> +// CHECK-NEXT: <key>line</key><integer>13</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -302,12 +238,12 @@ void test(Odd *odd) { // CHECK-NEXT: <array> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>14</integer> +// CHECK-NEXT: <key>line</key><integer>13</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>14</integer> +// CHECK-NEXT: <key>line</key><integer>13</integer> // CHECK-NEXT: <key>col</key><integer>10</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -325,10 +261,10 @@ void test(Odd *odd) { // CHECK-NEXT: <key>type</key><string>Double free</string> // CHECK-NEXT: <key>issue_context_kind</key><string>function</string> // CHECK-NEXT: <key>issue_context</key><string>test</string> -// CHECK-NEXT: <key>issue_hash</key><string>9</string> +// CHECK-NEXT: <key>issue_hash</key><string>8</string> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>14</integer> +// CHECK-NEXT: <key>line</key><integer>13</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -340,7 +276,7 @@ void test(Odd *odd) { // CHECK-NEXT: <key>kind</key><string>event</string> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>25</integer> +// CHECK-NEXT: <key>line</key><integer>24</integer> // CHECK-NEXT: <key>col</key><integer>2</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -348,12 +284,12 @@ void test(Odd *odd) { // CHECK-NEXT: <array> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>25</integer> +// CHECK-NEXT: <key>line</key><integer>24</integer> // CHECK-NEXT: <key>col</key><integer>2</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>25</integer> +// CHECK-NEXT: <key>line</key><integer>24</integer> // CHECK-NEXT: <key>col</key><integer>12</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -369,7 +305,7 @@ void test(Odd *odd) { // CHECK-NEXT: <key>kind</key><string>event</string> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>19</integer> +// CHECK-NEXT: <key>line</key><integer>18</integer> // CHECK-NEXT: <key>col</key><integer>2</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -387,12 +323,12 @@ void test(Odd *odd) { // CHECK-NEXT: <key>start</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>19</integer> +// CHECK-NEXT: <key>line</key><integer>18</integer> // CHECK-NEXT: <key>col</key><integer>2</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>19</integer> +// CHECK-NEXT: <key>line</key><integer>18</integer> // CHECK-NEXT: <key>col</key><integer>5</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -400,12 +336,12 @@ void test(Odd *odd) { // CHECK-NEXT: <key>end</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>20</integer> +// CHECK-NEXT: <key>line</key><integer>19</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>20</integer> +// CHECK-NEXT: <key>line</key><integer>19</integer> // CHECK-NEXT: <key>col</key><integer>8</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -417,7 +353,7 @@ void test(Odd *odd) { // CHECK-NEXT: <key>kind</key><string>event</string> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>20</integer> +// CHECK-NEXT: <key>line</key><integer>19</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -425,12 +361,12 @@ void test(Odd *odd) { // CHECK-NEXT: <array> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>20</integer> +// CHECK-NEXT: <key>line</key><integer>19</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>20</integer> +// CHECK-NEXT: <key>line</key><integer>19</integer> // CHECK-NEXT: <key>col</key><integer>13</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -446,7 +382,7 @@ void test(Odd *odd) { // CHECK-NEXT: <key>kind</key><string>event</string> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>25</integer> +// CHECK-NEXT: <key>line</key><integer>24</integer> // CHECK-NEXT: <key>col</key><integer>2</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -454,12 +390,12 @@ void test(Odd *odd) { // CHECK-NEXT: <array> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>25</integer> +// CHECK-NEXT: <key>line</key><integer>24</integer> // CHECK-NEXT: <key>col</key><integer>2</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>25</integer> +// CHECK-NEXT: <key>line</key><integer>24</integer> // CHECK-NEXT: <key>col</key><integer>12</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -479,12 +415,12 @@ void test(Odd *odd) { // CHECK-NEXT: <key>start</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>25</integer> +// CHECK-NEXT: <key>line</key><integer>24</integer> // CHECK-NEXT: <key>col</key><integer>2</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>25</integer> +// CHECK-NEXT: <key>line</key><integer>24</integer> // CHECK-NEXT: <key>col</key><integer>4</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -492,12 +428,12 @@ void test(Odd *odd) { // CHECK-NEXT: <key>end</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>27</integer> +// CHECK-NEXT: <key>line</key><integer>26</integer> // CHECK-NEXT: <key>col</key><integer>2</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>27</integer> +// CHECK-NEXT: <key>line</key><integer>26</integer> // CHECK-NEXT: <key>col</key><integer>7</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -509,7 +445,7 @@ void test(Odd *odd) { // CHECK-NEXT: <key>kind</key><string>event</string> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>27</integer> +// CHECK-NEXT: <key>line</key><integer>26</integer> // CHECK-NEXT: <key>col</key><integer>2</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -517,12 +453,12 @@ void test(Odd *odd) { // CHECK-NEXT: <array> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>27</integer> +// CHECK-NEXT: <key>line</key><integer>26</integer> // CHECK-NEXT: <key>col</key><integer>2</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>27</integer> +// CHECK-NEXT: <key>line</key><integer>26</integer> // CHECK-NEXT: <key>col</key><integer>11</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -543,7 +479,7 @@ void test(Odd *odd) { // CHECK-NEXT: <key>issue_hash</key><string>3</string> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>27</integer> +// CHECK-NEXT: <key>line</key><integer>26</integer> // CHECK-NEXT: <key>col</key><integer>2</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> diff --git a/test/Analysis/new-with-exceptions.cpp b/test/Analysis/new-with-exceptions.cpp index d909f1fb8b6..84d77c22302 100644 --- a/test/Analysis/new-with-exceptions.cpp +++ b/test/Analysis/new-with-exceptions.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-store region -std=c++11 -fexceptions -fcxx-exceptions -verify -DEXCEPTIONS %s +// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-store region -std=c++11 -fexceptions -fcxx-exceptions -verify %s // RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-store region -std=c++11 -verify %s void clang_analyzer_eval(bool); @@ -32,33 +32,15 @@ void testNew() { clang_analyzer_eval(new NoThrow); // expected-warning{{UNKNOWN}} clang_analyzer_eval(new NoExcept); // expected-warning{{UNKNOWN}} - clang_analyzer_eval(new DefaultThrow); - clang_analyzer_eval(new ExplicitThrow); -#ifdef EXCEPTIONS - // expected-warning@-3 {{TRUE}} - // expected-warning@-3 {{TRUE}} -#else - // expected-warning@-6 {{UNKNOWN}} - // expected-warning@-6 {{UNKNOWN}} -#endif + clang_analyzer_eval(new DefaultThrow); // expected-warning{{TRUE}} + clang_analyzer_eval(new ExplicitThrow); // expected-warning{{TRUE}} } void testNewArray() { - clang_analyzer_eval(new NoThrow[2]); - clang_analyzer_eval(new NoExcept[2]); - clang_analyzer_eval(new DefaultThrow[2]); - clang_analyzer_eval(new ExplicitThrow[2]); -#ifdef EXCEPTIONS - // expected-warning@-5 {{TRUE}} - // expected-warning@-5 {{TRUE}} - // expected-warning@-5 {{TRUE}} - // expected-warning@-5 {{TRUE}} -#else - // expected-warning@-10 {{UNKNOWN}} - // expected-warning@-10 {{UNKNOWN}} - // expected-warning@-10 {{UNKNOWN}} - // expected-warning@-10 {{UNKNOWN}} -#endif + clang_analyzer_eval(new NoThrow[2]); // expected-warning{{TRUE}} + clang_analyzer_eval(new NoExcept[2]); // expected-warning{{TRUE}} + clang_analyzer_eval(new DefaultThrow[2]); // expected-warning{{TRUE}} + clang_analyzer_eval(new ExplicitThrow[2]); // expected-warning{{TRUE}} } extern void *operator new[](size_t, int) noexcept; -- GitLab