[clang] [analyzer] Compute length of string literal initializers (#66990) (PR #68368)

via cfe-commits cfe-commits at lists.llvm.org
Tue Oct 10 11:08:48 PDT 2023


https://github.com/luamfb updated https://github.com/llvm/llvm-project/pull/68368

>From 1f0249fdb0cf7b1799eb9e532bfbb4a3ffe983b0 Mon Sep 17 00:00:00 2001
From: luamfb <mcmfbarbosa at gmail.com>
Date: Thu, 5 Oct 2023 21:50:10 -0300
Subject: [PATCH 1/3] [analyzer] Compute length of string literal initializers
 (#66990)

---
 .../StaticAnalyzer/Checkers/CStringChecker.cpp  | 17 ++++++++++++++++-
 clang/test/Analysis/string.c                    | 11 +++++++++++
 2 files changed, 27 insertions(+), 1 deletion(-)

diff --git a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
index f1539f2733298d9..b3b15c35450acdc 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
@@ -930,9 +930,24 @@ SVal CStringChecker::getCStringLength(CheckerContext &C, ProgramStateRef &state,
     const StringLiteral *strLit = cast<StringRegion>(MR)->getStringLiteral();
     return svalBuilder.makeIntVal(strLit->getLength(), sizeTy);
   }
+  case MemRegion::NonParamVarRegionKind: {
+    // If we have a global constant with a string literal initializer,
+    // compute the initializer's length.
+    const VarDecl *decl = cast<NonParamVarRegion>(MR)->getDecl();
+    if (decl->hasGlobalStorage()) {
+      if (const Expr *init = decl->getInit()) {
+        if (auto *strLit = dyn_cast<StringLiteral>(init)) {
+          SValBuilder &svalBuilder = C.getSValBuilder();
+          QualType sizeTy = svalBuilder.getContext().getSizeType();
+          return svalBuilder.makeIntVal(strLit->getLength(), sizeTy);
+        }
+      }
+    }
+    // Otherwise, fallback to this.
+    return getCStringLengthForRegion(C, state, Ex, MR, hypothetical);
+  }
   case MemRegion::SymbolicRegionKind:
   case MemRegion::AllocaRegionKind:
-  case MemRegion::NonParamVarRegionKind:
   case MemRegion::ParamVarRegionKind:
   case MemRegion::FieldRegionKind:
   case MemRegion::ObjCIvarRegionKind:
diff --git a/clang/test/Analysis/string.c b/clang/test/Analysis/string.c
index d369ee9f7d854a1..8da905b33145562 100644
--- a/clang/test/Analysis/string.c
+++ b/clang/test/Analysis/string.c
@@ -97,6 +97,17 @@ void strlen_constant2(char x) {
   clang_analyzer_eval(strlen(a) == 3); // expected-warning{{UNKNOWN}}
 }
 
+const char *const global_str_ptr = "abcd";
+const char global_str_arr[] = "efgh";
+
+void strlen_global_constant_ptr(void) {
+  clang_analyzer_eval(strlen(global_str_ptr) == 4); // expected-warning{{TRUE}}
+}
+
+void strlen_global_constant_arr(void) {
+  clang_analyzer_eval(strlen(global_str_arr) == 4); // expected-warning{{TRUE}}
+}
+
 size_t strlen_null(void) {
   return strlen(0); // expected-warning{{Null pointer passed as 1st argument to string length function}}
 }

>From 2c7c045243492648f08e2ec1017ae3d1b8b00136 Mon Sep 17 00:00:00 2001
From: luamfb <mcmfbarbosa at gmail.com>
Date: Mon, 9 Oct 2023 22:00:14 -0300
Subject: [PATCH 2/3] fixup! [analyzer] Compute length of string literal
 initializers (#66990)

---
 .../StaticAnalyzer/Checkers/CStringChecker.cpp  | 17 ++++++++---------
 clang/test/Analysis/string.c                    |  7 +++++++
 2 files changed, 15 insertions(+), 9 deletions(-)

diff --git a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
index b3b15c35450acdc..b1bc98e93a27995 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
@@ -933,18 +933,17 @@ SVal CStringChecker::getCStringLength(CheckerContext &C, ProgramStateRef &state,
   case MemRegion::NonParamVarRegionKind: {
     // If we have a global constant with a string literal initializer,
     // compute the initializer's length.
-    const VarDecl *decl = cast<NonParamVarRegion>(MR)->getDecl();
-    if (decl->hasGlobalStorage()) {
-      if (const Expr *init = decl->getInit()) {
-        if (auto *strLit = dyn_cast<StringLiteral>(init)) {
-          SValBuilder &svalBuilder = C.getSValBuilder();
-          QualType sizeTy = svalBuilder.getContext().getSizeType();
-          return svalBuilder.makeIntVal(strLit->getLength(), sizeTy);
+    const VarDecl *Decl = cast<NonParamVarRegion>(MR)->getDecl();
+    if (Decl->getType().isConstQualified() && Decl->hasGlobalStorage()) {
+      if (const Expr *Init = Decl->getInit()) {
+        if (auto *StrLit = dyn_cast<StringLiteral>(Init)) {
+          SValBuilder &SvalBuilder = C.getSValBuilder();
+          QualType SizeTy = SvalBuilder.getContext().getSizeType();
+          return SvalBuilder.makeIntVal(StrLit->getLength(), SizeTy);
         }
       }
     }
-    // Otherwise, fallback to this.
-    return getCStringLengthForRegion(C, state, Ex, MR, hypothetical);
+    [[fallthrough]];
   }
   case MemRegion::SymbolicRegionKind:
   case MemRegion::AllocaRegionKind:
diff --git a/clang/test/Analysis/string.c b/clang/test/Analysis/string.c
index 8da905b33145562..c226b6221e3cf59 100644
--- a/clang/test/Analysis/string.c
+++ b/clang/test/Analysis/string.c
@@ -99,6 +99,8 @@ void strlen_constant2(char x) {
 
 const char *const global_str_ptr = "abcd";
 const char global_str_arr[] = "efgh";
+const char *global_non_const_ptr1 = "ijk";
+char *global_non_const_ptr2 = "lmn";
 
 void strlen_global_constant_ptr(void) {
   clang_analyzer_eval(strlen(global_str_ptr) == 4); // expected-warning{{TRUE}}
@@ -108,6 +110,11 @@ void strlen_global_constant_arr(void) {
   clang_analyzer_eval(strlen(global_str_arr) == 4); // expected-warning{{TRUE}}
 }
 
+void strlen_global_non_const_ptr(void) {
+  clang_analyzer_eval(strlen(global_non_const_ptr1) == 3); // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(strlen(global_non_const_ptr2) == 3); // expected-warning{{UNKNOWN}}
+}
+
 size_t strlen_null(void) {
   return strlen(0); // expected-warning{{Null pointer passed as 1st argument to string length function}}
 }

>From b83ce65c081e05e5a297da5329e95a45cabe86fb Mon Sep 17 00:00:00 2001
From: luamfb <mcmfbarbosa at gmail.com>
Date: Tue, 10 Oct 2023 15:07:56 -0300
Subject: [PATCH 3/3] fixup! [analyzer] Compute length of string literal
 initializers (#66990)

---
 clang/test/Analysis/string.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/clang/test/Analysis/string.c b/clang/test/Analysis/string.c
index c226b6221e3cf59..d47de9db8228e57 100644
--- a/clang/test/Analysis/string.c
+++ b/clang/test/Analysis/string.c
@@ -101,6 +101,7 @@ const char *const global_str_ptr = "abcd";
 const char global_str_arr[] = "efgh";
 const char *global_non_const_ptr1 = "ijk";
 char *global_non_const_ptr2 = "lmn";
+char global_non_const_arr[] = "op";
 
 void strlen_global_constant_ptr(void) {
   clang_analyzer_eval(strlen(global_str_ptr) == 4); // expected-warning{{TRUE}}
@@ -115,6 +116,10 @@ void strlen_global_non_const_ptr(void) {
   clang_analyzer_eval(strlen(global_non_const_ptr2) == 3); // expected-warning{{UNKNOWN}}
 }
 
+void strlen_global_non_const_arr(void) {
+  clang_analyzer_eval(strlen(global_non_const_arr) == 2); // expected-warning{{UNKNOWN}}
+}
+
 size_t strlen_null(void) {
   return strlen(0); // expected-warning{{Null pointer passed as 1st argument to string length function}}
 }



More information about the cfe-commits mailing list