[clang] Add FixableGadget for AddAssign in UnspecifiedUntypedContext (PR #71862)

2023-11-09 Thread Rashmi Mudduluru via cfe-commits

https://github.com/t-rasmud created 
https://github.com/llvm/llvm-project/pull/71862

None

>From 6636745d1c444747a33c91b366a730d81ca5db5a Mon Sep 17 00:00:00 2001
From: Rashmi Mudduluru 
Date: Wed, 1 Nov 2023 13:43:12 -0700
Subject: [PATCH 1/3] [-Wunsafe-buffer-usage][WIP] Fixable gadget for AddAssign

---
 .../Analyses/UnsafeBufferUsageGadgets.def |  1 +
 clang/lib/Analysis/UnsafeBufferUsage.cpp  | 65 +++
 ...-unsafe-buffer-usage-fixits-add-assign.cpp | 38 +++
 3 files changed, 104 insertions(+)
 create mode 100644 
clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-add-assign.cpp

diff --git a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def 
b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
index ff687a0d178bdea..757ee452ced7488 100644
--- a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
+++ b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
@@ -36,6 +36,7 @@ FIXABLE_GADGET(PointerDereference)
 FIXABLE_GADGET(UPCAddressofArraySubscript) // '&DRE[any]' in an Unspecified 
Pointer Context
 FIXABLE_GADGET(UPCStandalonePointer)
 FIXABLE_GADGET(UPCPreIncrement)// '++Ptr' in an Unspecified 
Pointer Context
+FIXABLE_GADGET(UUCAddAssign)// 'Ptr += n' in an Unspecified 
Untyped Context
 FIXABLE_GADGET(PointerAssignment)
 FIXABLE_GADGET(PointerInit)
 
diff --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp 
b/clang/lib/Analysis/UnsafeBufferUsage.cpp
index e332a3609290aac..7b79f5360c79d6e 100644
--- a/clang/lib/Analysis/UnsafeBufferUsage.cpp
+++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp
@@ -1028,6 +1028,42 @@ class UPCPreIncrementGadget : public FixableGadget {
   }
 };
 
+// Representing a pointer type expression of the form `Ptr += n` in an
+// Unspecified Untyped Context (UUC):
+class UUCAddAssignGadget : public FixableGadget {
+private:
+  static constexpr const char *const UUCAddAssignTag =
+"PointerAddAssignUnderUUC";
+  const BinaryOperator *Node; // the `Ptr += n` node
+
+public:
+  UUCAddAssignGadget(const MatchFinder::MatchResult &Result)
+: FixableGadget(Kind::UUCAddAssign),
+  Node(Result.Nodes.getNodeAs(UUCAddAssignTag)) {
+assert(Node != nullptr && "Expecting a non-null matching result");
+  }
+
+  static bool classof(const Gadget *G) {
+return G->getKind() == Kind::UUCAddAssign;
+  }
+
+  static Matcher matcher() {
+return stmt(isInUnspecifiedUntypedContext(expr(ignoringImpCasts(
+binaryOperator(hasOperatorName("+="),
+  hasLHS(declRefExpr(
+toSupportedVariable()))
+  ).bind(UUCAddAssignTag);
+  }
+
+  virtual std::optional getFixits(const Strategy &S) const override;
+
+  virtual const Stmt *getBaseStmt() const override { return Node; }
+
+  virtual DeclUseList getClaimedVarUseSites() const override {
+return {dyn_cast(Node->getLHS())};
+  }
+};
+
 // Representing a fixable expression of the form `*(ptr + 123)` or `*(123 +
 // ptr)`:
 class DerefSimplePtrArithFixableGadget : public FixableGadget {
@@ -1766,6 +1802,35 @@ fixUPCAddressofArraySubscriptWithSpan(const 
UnaryOperator *Node) {
   FixItHint::CreateReplacement(Node->getSourceRange(), SS.str())};
 }
 
+std::optional UUCAddAssignGadget::getFixits(const Strategy &S) 
const {
+  DeclUseList DREs = getClaimedVarUseSites();
+
+  if (DREs.size() != 1)
+return std::nullopt; // In cases of `Ptr += n` where `Ptr` is not a DRE, we
+ // give up
+  if (const VarDecl *VD = dyn_cast(DREs.front()->getDecl())) {
+if (S.lookup(VD) == Strategy::Kind::Span) {
+  FixItList Fixes;
+  std::stringstream SS;
+  const Stmt *AddAssignNode = getBaseStmt();
+  StringRef varName = VD->getName();
+  const ASTContext &Ctx = VD->getASTContext();
+
+  // To transform UUC(p += n) to UUC((p = p.subspan(1)).data()):
+  SS << varName.data() << " = " << varName.data()
+ << ".subspan(" << getUserFillPlaceHolder() << ")";
+  std::optional AddAssignLocation =
+  getEndCharLoc(AddAssignNode, Ctx.getSourceManager(), 
Ctx.getLangOpts());
+  if (!AddAssignLocation)
+return std::nullopt;
+
+  Fixes.push_back(FixItHint::CreateReplacement(
+  SourceRange(AddAssignNode->getBeginLoc(), *AddAssignLocation), 
SS.str()));
+  return Fixes;
+}
+  }
+  return std::nullopt; // Not in the cases that we can handle for now, give up.
+}
 
 std::optional UPCPreIncrementGadget::getFixits(const Strategy &S) 
const {
   DeclUseList DREs = getClaimedVarUseSites();
diff --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-add-assign.cpp 
b/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-add-assign.cpp
new file mode 100644
index 000..e2b9a43dee9b3c3
--- /dev/null
+++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-add-assign.cpp
@@ -0,0 +1,38 @@
+// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage \

[clang] [-Wunsafe-buffer-usage] Add FixableGadget for AddAssign in UnspecifiedUntypedContext (PR #71862)

2023-11-09 Thread Rashmi Mudduluru via cfe-commits

https://github.com/t-rasmud edited 
https://github.com/llvm/llvm-project/pull/71862
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [-Wunsafe-buffer-usage] Add FixableGadget for AddAssign in UnspecifiedUntypedContext (PR #71862)

2023-11-09 Thread Rashmi Mudduluru via cfe-commits

https://github.com/t-rasmud updated 
https://github.com/llvm/llvm-project/pull/71862

>From 6636745d1c444747a33c91b366a730d81ca5db5a Mon Sep 17 00:00:00 2001
From: Rashmi Mudduluru 
Date: Wed, 1 Nov 2023 13:43:12 -0700
Subject: [PATCH 1/4] [-Wunsafe-buffer-usage][WIP] Fixable gadget for AddAssign

---
 .../Analyses/UnsafeBufferUsageGadgets.def |  1 +
 clang/lib/Analysis/UnsafeBufferUsage.cpp  | 65 +++
 ...-unsafe-buffer-usage-fixits-add-assign.cpp | 38 +++
 3 files changed, 104 insertions(+)
 create mode 100644 
clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-add-assign.cpp

diff --git a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def 
b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
index ff687a0d178bdea..757ee452ced7488 100644
--- a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
+++ b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
@@ -36,6 +36,7 @@ FIXABLE_GADGET(PointerDereference)
 FIXABLE_GADGET(UPCAddressofArraySubscript) // '&DRE[any]' in an Unspecified 
Pointer Context
 FIXABLE_GADGET(UPCStandalonePointer)
 FIXABLE_GADGET(UPCPreIncrement)// '++Ptr' in an Unspecified 
Pointer Context
+FIXABLE_GADGET(UUCAddAssign)// 'Ptr += n' in an Unspecified 
Untyped Context
 FIXABLE_GADGET(PointerAssignment)
 FIXABLE_GADGET(PointerInit)
 
diff --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp 
b/clang/lib/Analysis/UnsafeBufferUsage.cpp
index e332a3609290aac..7b79f5360c79d6e 100644
--- a/clang/lib/Analysis/UnsafeBufferUsage.cpp
+++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp
@@ -1028,6 +1028,42 @@ class UPCPreIncrementGadget : public FixableGadget {
   }
 };
 
+// Representing a pointer type expression of the form `Ptr += n` in an
+// Unspecified Untyped Context (UUC):
+class UUCAddAssignGadget : public FixableGadget {
+private:
+  static constexpr const char *const UUCAddAssignTag =
+"PointerAddAssignUnderUUC";
+  const BinaryOperator *Node; // the `Ptr += n` node
+
+public:
+  UUCAddAssignGadget(const MatchFinder::MatchResult &Result)
+: FixableGadget(Kind::UUCAddAssign),
+  Node(Result.Nodes.getNodeAs(UUCAddAssignTag)) {
+assert(Node != nullptr && "Expecting a non-null matching result");
+  }
+
+  static bool classof(const Gadget *G) {
+return G->getKind() == Kind::UUCAddAssign;
+  }
+
+  static Matcher matcher() {
+return stmt(isInUnspecifiedUntypedContext(expr(ignoringImpCasts(
+binaryOperator(hasOperatorName("+="),
+  hasLHS(declRefExpr(
+toSupportedVariable()))
+  ).bind(UUCAddAssignTag);
+  }
+
+  virtual std::optional getFixits(const Strategy &S) const override;
+
+  virtual const Stmt *getBaseStmt() const override { return Node; }
+
+  virtual DeclUseList getClaimedVarUseSites() const override {
+return {dyn_cast(Node->getLHS())};
+  }
+};
+
 // Representing a fixable expression of the form `*(ptr + 123)` or `*(123 +
 // ptr)`:
 class DerefSimplePtrArithFixableGadget : public FixableGadget {
@@ -1766,6 +1802,35 @@ fixUPCAddressofArraySubscriptWithSpan(const 
UnaryOperator *Node) {
   FixItHint::CreateReplacement(Node->getSourceRange(), SS.str())};
 }
 
+std::optional UUCAddAssignGadget::getFixits(const Strategy &S) 
const {
+  DeclUseList DREs = getClaimedVarUseSites();
+
+  if (DREs.size() != 1)
+return std::nullopt; // In cases of `Ptr += n` where `Ptr` is not a DRE, we
+ // give up
+  if (const VarDecl *VD = dyn_cast(DREs.front()->getDecl())) {
+if (S.lookup(VD) == Strategy::Kind::Span) {
+  FixItList Fixes;
+  std::stringstream SS;
+  const Stmt *AddAssignNode = getBaseStmt();
+  StringRef varName = VD->getName();
+  const ASTContext &Ctx = VD->getASTContext();
+
+  // To transform UUC(p += n) to UUC((p = p.subspan(1)).data()):
+  SS << varName.data() << " = " << varName.data()
+ << ".subspan(" << getUserFillPlaceHolder() << ")";
+  std::optional AddAssignLocation =
+  getEndCharLoc(AddAssignNode, Ctx.getSourceManager(), 
Ctx.getLangOpts());
+  if (!AddAssignLocation)
+return std::nullopt;
+
+  Fixes.push_back(FixItHint::CreateReplacement(
+  SourceRange(AddAssignNode->getBeginLoc(), *AddAssignLocation), 
SS.str()));
+  return Fixes;
+}
+  }
+  return std::nullopt; // Not in the cases that we can handle for now, give up.
+}
 
 std::optional UPCPreIncrementGadget::getFixits(const Strategy &S) 
const {
   DeclUseList DREs = getClaimedVarUseSites();
diff --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-add-assign.cpp 
b/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-add-assign.cpp
new file mode 100644
index 000..e2b9a43dee9b3c3
--- /dev/null
+++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-add-assign.cpp
@@ -0,0 +1,38 @@
+// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage \
+// R

[clang] [-Wunsafe-buffer-usage] Add FixableGadget for AddAssign in UnspecifiedUntypedContext (PR #71862)

2023-11-09 Thread Rashmi Mudduluru via cfe-commits

https://github.com/t-rasmud updated 
https://github.com/llvm/llvm-project/pull/71862

>From 6636745d1c444747a33c91b366a730d81ca5db5a Mon Sep 17 00:00:00 2001
From: Rashmi Mudduluru 
Date: Wed, 1 Nov 2023 13:43:12 -0700
Subject: [PATCH 1/5] [-Wunsafe-buffer-usage][WIP] Fixable gadget for AddAssign

---
 .../Analyses/UnsafeBufferUsageGadgets.def |  1 +
 clang/lib/Analysis/UnsafeBufferUsage.cpp  | 65 +++
 ...-unsafe-buffer-usage-fixits-add-assign.cpp | 38 +++
 3 files changed, 104 insertions(+)
 create mode 100644 
clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-add-assign.cpp

diff --git a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def 
b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
index ff687a0d178bdea..757ee452ced7488 100644
--- a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
+++ b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
@@ -36,6 +36,7 @@ FIXABLE_GADGET(PointerDereference)
 FIXABLE_GADGET(UPCAddressofArraySubscript) // '&DRE[any]' in an Unspecified 
Pointer Context
 FIXABLE_GADGET(UPCStandalonePointer)
 FIXABLE_GADGET(UPCPreIncrement)// '++Ptr' in an Unspecified 
Pointer Context
+FIXABLE_GADGET(UUCAddAssign)// 'Ptr += n' in an Unspecified 
Untyped Context
 FIXABLE_GADGET(PointerAssignment)
 FIXABLE_GADGET(PointerInit)
 
diff --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp 
b/clang/lib/Analysis/UnsafeBufferUsage.cpp
index e332a3609290aac..7b79f5360c79d6e 100644
--- a/clang/lib/Analysis/UnsafeBufferUsage.cpp
+++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp
@@ -1028,6 +1028,42 @@ class UPCPreIncrementGadget : public FixableGadget {
   }
 };
 
+// Representing a pointer type expression of the form `Ptr += n` in an
+// Unspecified Untyped Context (UUC):
+class UUCAddAssignGadget : public FixableGadget {
+private:
+  static constexpr const char *const UUCAddAssignTag =
+"PointerAddAssignUnderUUC";
+  const BinaryOperator *Node; // the `Ptr += n` node
+
+public:
+  UUCAddAssignGadget(const MatchFinder::MatchResult &Result)
+: FixableGadget(Kind::UUCAddAssign),
+  Node(Result.Nodes.getNodeAs(UUCAddAssignTag)) {
+assert(Node != nullptr && "Expecting a non-null matching result");
+  }
+
+  static bool classof(const Gadget *G) {
+return G->getKind() == Kind::UUCAddAssign;
+  }
+
+  static Matcher matcher() {
+return stmt(isInUnspecifiedUntypedContext(expr(ignoringImpCasts(
+binaryOperator(hasOperatorName("+="),
+  hasLHS(declRefExpr(
+toSupportedVariable()))
+  ).bind(UUCAddAssignTag);
+  }
+
+  virtual std::optional getFixits(const Strategy &S) const override;
+
+  virtual const Stmt *getBaseStmt() const override { return Node; }
+
+  virtual DeclUseList getClaimedVarUseSites() const override {
+return {dyn_cast(Node->getLHS())};
+  }
+};
+
 // Representing a fixable expression of the form `*(ptr + 123)` or `*(123 +
 // ptr)`:
 class DerefSimplePtrArithFixableGadget : public FixableGadget {
@@ -1766,6 +1802,35 @@ fixUPCAddressofArraySubscriptWithSpan(const 
UnaryOperator *Node) {
   FixItHint::CreateReplacement(Node->getSourceRange(), SS.str())};
 }
 
+std::optional UUCAddAssignGadget::getFixits(const Strategy &S) 
const {
+  DeclUseList DREs = getClaimedVarUseSites();
+
+  if (DREs.size() != 1)
+return std::nullopt; // In cases of `Ptr += n` where `Ptr` is not a DRE, we
+ // give up
+  if (const VarDecl *VD = dyn_cast(DREs.front()->getDecl())) {
+if (S.lookup(VD) == Strategy::Kind::Span) {
+  FixItList Fixes;
+  std::stringstream SS;
+  const Stmt *AddAssignNode = getBaseStmt();
+  StringRef varName = VD->getName();
+  const ASTContext &Ctx = VD->getASTContext();
+
+  // To transform UUC(p += n) to UUC((p = p.subspan(1)).data()):
+  SS << varName.data() << " = " << varName.data()
+ << ".subspan(" << getUserFillPlaceHolder() << ")";
+  std::optional AddAssignLocation =
+  getEndCharLoc(AddAssignNode, Ctx.getSourceManager(), 
Ctx.getLangOpts());
+  if (!AddAssignLocation)
+return std::nullopt;
+
+  Fixes.push_back(FixItHint::CreateReplacement(
+  SourceRange(AddAssignNode->getBeginLoc(), *AddAssignLocation), 
SS.str()));
+  return Fixes;
+}
+  }
+  return std::nullopt; // Not in the cases that we can handle for now, give up.
+}
 
 std::optional UPCPreIncrementGadget::getFixits(const Strategy &S) 
const {
   DeclUseList DREs = getClaimedVarUseSites();
diff --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-add-assign.cpp 
b/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-add-assign.cpp
new file mode 100644
index 000..e2b9a43dee9b3c3
--- /dev/null
+++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-add-assign.cpp
@@ -0,0 +1,38 @@
+// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage \
+// R

[clang] [-Wunsafe-buffer-usage] Add FixableGadget for AddAssign in UnspecifiedUntypedContext (PR #71862)

2023-11-10 Thread Rashmi Mudduluru via cfe-commits

https://github.com/t-rasmud updated 
https://github.com/llvm/llvm-project/pull/71862

>From 6636745d1c444747a33c91b366a730d81ca5db5a Mon Sep 17 00:00:00 2001
From: Rashmi Mudduluru 
Date: Wed, 1 Nov 2023 13:43:12 -0700
Subject: [PATCH 1/6] [-Wunsafe-buffer-usage][WIP] Fixable gadget for AddAssign

---
 .../Analyses/UnsafeBufferUsageGadgets.def |  1 +
 clang/lib/Analysis/UnsafeBufferUsage.cpp  | 65 +++
 ...-unsafe-buffer-usage-fixits-add-assign.cpp | 38 +++
 3 files changed, 104 insertions(+)
 create mode 100644 
clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-add-assign.cpp

diff --git a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def 
b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
index ff687a0d178bdea..757ee452ced7488 100644
--- a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
+++ b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
@@ -36,6 +36,7 @@ FIXABLE_GADGET(PointerDereference)
 FIXABLE_GADGET(UPCAddressofArraySubscript) // '&DRE[any]' in an Unspecified 
Pointer Context
 FIXABLE_GADGET(UPCStandalonePointer)
 FIXABLE_GADGET(UPCPreIncrement)// '++Ptr' in an Unspecified 
Pointer Context
+FIXABLE_GADGET(UUCAddAssign)// 'Ptr += n' in an Unspecified 
Untyped Context
 FIXABLE_GADGET(PointerAssignment)
 FIXABLE_GADGET(PointerInit)
 
diff --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp 
b/clang/lib/Analysis/UnsafeBufferUsage.cpp
index e332a3609290aac..7b79f5360c79d6e 100644
--- a/clang/lib/Analysis/UnsafeBufferUsage.cpp
+++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp
@@ -1028,6 +1028,42 @@ class UPCPreIncrementGadget : public FixableGadget {
   }
 };
 
+// Representing a pointer type expression of the form `Ptr += n` in an
+// Unspecified Untyped Context (UUC):
+class UUCAddAssignGadget : public FixableGadget {
+private:
+  static constexpr const char *const UUCAddAssignTag =
+"PointerAddAssignUnderUUC";
+  const BinaryOperator *Node; // the `Ptr += n` node
+
+public:
+  UUCAddAssignGadget(const MatchFinder::MatchResult &Result)
+: FixableGadget(Kind::UUCAddAssign),
+  Node(Result.Nodes.getNodeAs(UUCAddAssignTag)) {
+assert(Node != nullptr && "Expecting a non-null matching result");
+  }
+
+  static bool classof(const Gadget *G) {
+return G->getKind() == Kind::UUCAddAssign;
+  }
+
+  static Matcher matcher() {
+return stmt(isInUnspecifiedUntypedContext(expr(ignoringImpCasts(
+binaryOperator(hasOperatorName("+="),
+  hasLHS(declRefExpr(
+toSupportedVariable()))
+  ).bind(UUCAddAssignTag);
+  }
+
+  virtual std::optional getFixits(const Strategy &S) const override;
+
+  virtual const Stmt *getBaseStmt() const override { return Node; }
+
+  virtual DeclUseList getClaimedVarUseSites() const override {
+return {dyn_cast(Node->getLHS())};
+  }
+};
+
 // Representing a fixable expression of the form `*(ptr + 123)` or `*(123 +
 // ptr)`:
 class DerefSimplePtrArithFixableGadget : public FixableGadget {
@@ -1766,6 +1802,35 @@ fixUPCAddressofArraySubscriptWithSpan(const 
UnaryOperator *Node) {
   FixItHint::CreateReplacement(Node->getSourceRange(), SS.str())};
 }
 
+std::optional UUCAddAssignGadget::getFixits(const Strategy &S) 
const {
+  DeclUseList DREs = getClaimedVarUseSites();
+
+  if (DREs.size() != 1)
+return std::nullopt; // In cases of `Ptr += n` where `Ptr` is not a DRE, we
+ // give up
+  if (const VarDecl *VD = dyn_cast(DREs.front()->getDecl())) {
+if (S.lookup(VD) == Strategy::Kind::Span) {
+  FixItList Fixes;
+  std::stringstream SS;
+  const Stmt *AddAssignNode = getBaseStmt();
+  StringRef varName = VD->getName();
+  const ASTContext &Ctx = VD->getASTContext();
+
+  // To transform UUC(p += n) to UUC((p = p.subspan(1)).data()):
+  SS << varName.data() << " = " << varName.data()
+ << ".subspan(" << getUserFillPlaceHolder() << ")";
+  std::optional AddAssignLocation =
+  getEndCharLoc(AddAssignNode, Ctx.getSourceManager(), 
Ctx.getLangOpts());
+  if (!AddAssignLocation)
+return std::nullopt;
+
+  Fixes.push_back(FixItHint::CreateReplacement(
+  SourceRange(AddAssignNode->getBeginLoc(), *AddAssignLocation), 
SS.str()));
+  return Fixes;
+}
+  }
+  return std::nullopt; // Not in the cases that we can handle for now, give up.
+}
 
 std::optional UPCPreIncrementGadget::getFixits(const Strategy &S) 
const {
   DeclUseList DREs = getClaimedVarUseSites();
diff --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-add-assign.cpp 
b/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-add-assign.cpp
new file mode 100644
index 000..e2b9a43dee9b3c3
--- /dev/null
+++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-add-assign.cpp
@@ -0,0 +1,38 @@
+// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage \
+// R

[clang] [-Wunsafe-buffer-usage] Add FixableGadget for AddAssign in UnspecifiedUntypedContext (PR #71862)

2023-11-13 Thread Rashmi Mudduluru via cfe-commits


@@ -1028,6 +1028,50 @@ class UPCPreIncrementGadget : public FixableGadget {
   }
 };
 
+// Representing a pointer type expression of the form `Ptr += n` in an
+// Unspecified Untyped Context (UUC):
+class UUCAddAssignGadget : public FixableGadget {
+private:
+  static constexpr const char *const UUCAddAssignTag =
+  "PointerAddAssignUnderUUC";
+  static constexpr const char *const IntOffsetTag = "IntOffset";
+  static constexpr const char *const OffsetTag = "Offset";
+
+  const BinaryOperator *Node; // the `Ptr += n` node
+  const IntegerLiteral *IntOffset = nullptr;
+  const DeclRefExpr *Offset = nullptr;
+
+public:
+  UUCAddAssignGadget(const MatchFinder::MatchResult &Result)
+  : FixableGadget(Kind::UUCAddAssign),
+Node(Result.Nodes.getNodeAs(UUCAddAssignTag)),
+IntOffset(Result.Nodes.getNodeAs(IntOffsetTag)),
+Offset(Result.Nodes.getNodeAs(OffsetTag)) {
+assert(Node != nullptr && "Expecting a non-null matching result");
+  }
+
+  static bool classof(const Gadget *G) {
+return G->getKind() == Kind::UUCAddAssign;
+  }
+
+  static Matcher matcher() {
+return stmt(isInUnspecifiedUntypedContext(expr(ignoringImpCasts(
+binaryOperator(
+hasOperatorName("+="), hasLHS(declRefExpr(toSupportedVariable())),
+hasRHS(expr(anyOf(ignoringImpCasts(declRefExpr().bind(OffsetTag)),
+  integerLiteral().bind(IntOffsetTag)

t-rasmud wrote:

I make this differentiation to ensure we do not suggest a fixit if the integer 
literal happens to be negative. Although there's no such check in the case of a 
`DeclRefExpr`.

https://github.com/llvm/llvm-project/pull/71862
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [-Wunsafe-buffer-usage] Add FixableGadget for AddAssign in UnspecifiedUntypedContext (PR #71862)

2023-12-11 Thread Rashmi Mudduluru via cfe-commits

https://github.com/t-rasmud closed 
https://github.com/llvm/llvm-project/pull/71862
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [-Wunsafe-buffer-usage] Add FixableGadget for AddAssign in UnspecifiedUntypedContext (PR #71862)

2023-11-14 Thread Rashmi Mudduluru via cfe-commits

https://github.com/t-rasmud updated 
https://github.com/llvm/llvm-project/pull/71862

>From 6636745d1c444747a33c91b366a730d81ca5db5a Mon Sep 17 00:00:00 2001
From: Rashmi Mudduluru 
Date: Wed, 1 Nov 2023 13:43:12 -0700
Subject: [PATCH 1/7] [-Wunsafe-buffer-usage][WIP] Fixable gadget for AddAssign

---
 .../Analyses/UnsafeBufferUsageGadgets.def |  1 +
 clang/lib/Analysis/UnsafeBufferUsage.cpp  | 65 +++
 ...-unsafe-buffer-usage-fixits-add-assign.cpp | 38 +++
 3 files changed, 104 insertions(+)
 create mode 100644 
clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-add-assign.cpp

diff --git a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def 
b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
index ff687a0d178bdea..757ee452ced7488 100644
--- a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
+++ b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
@@ -36,6 +36,7 @@ FIXABLE_GADGET(PointerDereference)
 FIXABLE_GADGET(UPCAddressofArraySubscript) // '&DRE[any]' in an Unspecified 
Pointer Context
 FIXABLE_GADGET(UPCStandalonePointer)
 FIXABLE_GADGET(UPCPreIncrement)// '++Ptr' in an Unspecified 
Pointer Context
+FIXABLE_GADGET(UUCAddAssign)// 'Ptr += n' in an Unspecified 
Untyped Context
 FIXABLE_GADGET(PointerAssignment)
 FIXABLE_GADGET(PointerInit)
 
diff --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp 
b/clang/lib/Analysis/UnsafeBufferUsage.cpp
index e332a3609290aac..7b79f5360c79d6e 100644
--- a/clang/lib/Analysis/UnsafeBufferUsage.cpp
+++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp
@@ -1028,6 +1028,42 @@ class UPCPreIncrementGadget : public FixableGadget {
   }
 };
 
+// Representing a pointer type expression of the form `Ptr += n` in an
+// Unspecified Untyped Context (UUC):
+class UUCAddAssignGadget : public FixableGadget {
+private:
+  static constexpr const char *const UUCAddAssignTag =
+"PointerAddAssignUnderUUC";
+  const BinaryOperator *Node; // the `Ptr += n` node
+
+public:
+  UUCAddAssignGadget(const MatchFinder::MatchResult &Result)
+: FixableGadget(Kind::UUCAddAssign),
+  Node(Result.Nodes.getNodeAs(UUCAddAssignTag)) {
+assert(Node != nullptr && "Expecting a non-null matching result");
+  }
+
+  static bool classof(const Gadget *G) {
+return G->getKind() == Kind::UUCAddAssign;
+  }
+
+  static Matcher matcher() {
+return stmt(isInUnspecifiedUntypedContext(expr(ignoringImpCasts(
+binaryOperator(hasOperatorName("+="),
+  hasLHS(declRefExpr(
+toSupportedVariable()))
+  ).bind(UUCAddAssignTag);
+  }
+
+  virtual std::optional getFixits(const Strategy &S) const override;
+
+  virtual const Stmt *getBaseStmt() const override { return Node; }
+
+  virtual DeclUseList getClaimedVarUseSites() const override {
+return {dyn_cast(Node->getLHS())};
+  }
+};
+
 // Representing a fixable expression of the form `*(ptr + 123)` or `*(123 +
 // ptr)`:
 class DerefSimplePtrArithFixableGadget : public FixableGadget {
@@ -1766,6 +1802,35 @@ fixUPCAddressofArraySubscriptWithSpan(const 
UnaryOperator *Node) {
   FixItHint::CreateReplacement(Node->getSourceRange(), SS.str())};
 }
 
+std::optional UUCAddAssignGadget::getFixits(const Strategy &S) 
const {
+  DeclUseList DREs = getClaimedVarUseSites();
+
+  if (DREs.size() != 1)
+return std::nullopt; // In cases of `Ptr += n` where `Ptr` is not a DRE, we
+ // give up
+  if (const VarDecl *VD = dyn_cast(DREs.front()->getDecl())) {
+if (S.lookup(VD) == Strategy::Kind::Span) {
+  FixItList Fixes;
+  std::stringstream SS;
+  const Stmt *AddAssignNode = getBaseStmt();
+  StringRef varName = VD->getName();
+  const ASTContext &Ctx = VD->getASTContext();
+
+  // To transform UUC(p += n) to UUC((p = p.subspan(1)).data()):
+  SS << varName.data() << " = " << varName.data()
+ << ".subspan(" << getUserFillPlaceHolder() << ")";
+  std::optional AddAssignLocation =
+  getEndCharLoc(AddAssignNode, Ctx.getSourceManager(), 
Ctx.getLangOpts());
+  if (!AddAssignLocation)
+return std::nullopt;
+
+  Fixes.push_back(FixItHint::CreateReplacement(
+  SourceRange(AddAssignNode->getBeginLoc(), *AddAssignLocation), 
SS.str()));
+  return Fixes;
+}
+  }
+  return std::nullopt; // Not in the cases that we can handle for now, give up.
+}
 
 std::optional UPCPreIncrementGadget::getFixits(const Strategy &S) 
const {
   DeclUseList DREs = getClaimedVarUseSites();
diff --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-add-assign.cpp 
b/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-add-assign.cpp
new file mode 100644
index 000..e2b9a43dee9b3c3
--- /dev/null
+++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-add-assign.cpp
@@ -0,0 +1,38 @@
+// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage \
+// R

[clang] [-Wunsafe-buffer-usage] Add FixableGadget for AddAssign in UnspecifiedUntypedContext (PR #71862)

2023-11-14 Thread Rashmi Mudduluru via cfe-commits

https://github.com/t-rasmud updated 
https://github.com/llvm/llvm-project/pull/71862

>From 6636745d1c444747a33c91b366a730d81ca5db5a Mon Sep 17 00:00:00 2001
From: Rashmi Mudduluru 
Date: Wed, 1 Nov 2023 13:43:12 -0700
Subject: [PATCH 1/8] [-Wunsafe-buffer-usage][WIP] Fixable gadget for AddAssign

---
 .../Analyses/UnsafeBufferUsageGadgets.def |  1 +
 clang/lib/Analysis/UnsafeBufferUsage.cpp  | 65 +++
 ...-unsafe-buffer-usage-fixits-add-assign.cpp | 38 +++
 3 files changed, 104 insertions(+)
 create mode 100644 
clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-add-assign.cpp

diff --git a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def 
b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
index ff687a0d178bdea..757ee452ced7488 100644
--- a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
+++ b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
@@ -36,6 +36,7 @@ FIXABLE_GADGET(PointerDereference)
 FIXABLE_GADGET(UPCAddressofArraySubscript) // '&DRE[any]' in an Unspecified 
Pointer Context
 FIXABLE_GADGET(UPCStandalonePointer)
 FIXABLE_GADGET(UPCPreIncrement)// '++Ptr' in an Unspecified 
Pointer Context
+FIXABLE_GADGET(UUCAddAssign)// 'Ptr += n' in an Unspecified 
Untyped Context
 FIXABLE_GADGET(PointerAssignment)
 FIXABLE_GADGET(PointerInit)
 
diff --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp 
b/clang/lib/Analysis/UnsafeBufferUsage.cpp
index e332a3609290aac..7b79f5360c79d6e 100644
--- a/clang/lib/Analysis/UnsafeBufferUsage.cpp
+++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp
@@ -1028,6 +1028,42 @@ class UPCPreIncrementGadget : public FixableGadget {
   }
 };
 
+// Representing a pointer type expression of the form `Ptr += n` in an
+// Unspecified Untyped Context (UUC):
+class UUCAddAssignGadget : public FixableGadget {
+private:
+  static constexpr const char *const UUCAddAssignTag =
+"PointerAddAssignUnderUUC";
+  const BinaryOperator *Node; // the `Ptr += n` node
+
+public:
+  UUCAddAssignGadget(const MatchFinder::MatchResult &Result)
+: FixableGadget(Kind::UUCAddAssign),
+  Node(Result.Nodes.getNodeAs(UUCAddAssignTag)) {
+assert(Node != nullptr && "Expecting a non-null matching result");
+  }
+
+  static bool classof(const Gadget *G) {
+return G->getKind() == Kind::UUCAddAssign;
+  }
+
+  static Matcher matcher() {
+return stmt(isInUnspecifiedUntypedContext(expr(ignoringImpCasts(
+binaryOperator(hasOperatorName("+="),
+  hasLHS(declRefExpr(
+toSupportedVariable()))
+  ).bind(UUCAddAssignTag);
+  }
+
+  virtual std::optional getFixits(const Strategy &S) const override;
+
+  virtual const Stmt *getBaseStmt() const override { return Node; }
+
+  virtual DeclUseList getClaimedVarUseSites() const override {
+return {dyn_cast(Node->getLHS())};
+  }
+};
+
 // Representing a fixable expression of the form `*(ptr + 123)` or `*(123 +
 // ptr)`:
 class DerefSimplePtrArithFixableGadget : public FixableGadget {
@@ -1766,6 +1802,35 @@ fixUPCAddressofArraySubscriptWithSpan(const 
UnaryOperator *Node) {
   FixItHint::CreateReplacement(Node->getSourceRange(), SS.str())};
 }
 
+std::optional UUCAddAssignGadget::getFixits(const Strategy &S) 
const {
+  DeclUseList DREs = getClaimedVarUseSites();
+
+  if (DREs.size() != 1)
+return std::nullopt; // In cases of `Ptr += n` where `Ptr` is not a DRE, we
+ // give up
+  if (const VarDecl *VD = dyn_cast(DREs.front()->getDecl())) {
+if (S.lookup(VD) == Strategy::Kind::Span) {
+  FixItList Fixes;
+  std::stringstream SS;
+  const Stmt *AddAssignNode = getBaseStmt();
+  StringRef varName = VD->getName();
+  const ASTContext &Ctx = VD->getASTContext();
+
+  // To transform UUC(p += n) to UUC((p = p.subspan(1)).data()):
+  SS << varName.data() << " = " << varName.data()
+ << ".subspan(" << getUserFillPlaceHolder() << ")";
+  std::optional AddAssignLocation =
+  getEndCharLoc(AddAssignNode, Ctx.getSourceManager(), 
Ctx.getLangOpts());
+  if (!AddAssignLocation)
+return std::nullopt;
+
+  Fixes.push_back(FixItHint::CreateReplacement(
+  SourceRange(AddAssignNode->getBeginLoc(), *AddAssignLocation), 
SS.str()));
+  return Fixes;
+}
+  }
+  return std::nullopt; // Not in the cases that we can handle for now, give up.
+}
 
 std::optional UPCPreIncrementGadget::getFixits(const Strategy &S) 
const {
   DeclUseList DREs = getClaimedVarUseSites();
diff --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-add-assign.cpp 
b/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-add-assign.cpp
new file mode 100644
index 000..e2b9a43dee9b3c3
--- /dev/null
+++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-add-assign.cpp
@@ -0,0 +1,38 @@
+// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage \
+// R

[clang] [-Wunsafe-buffer-usage] Add FixableGadget for AddAssign in UnspecifiedUntypedContext (PR #71862)

2023-11-15 Thread Rashmi Mudduluru via cfe-commits

https://github.com/t-rasmud updated 
https://github.com/llvm/llvm-project/pull/71862

>From 6636745d1c444747a33c91b366a730d81ca5db5a Mon Sep 17 00:00:00 2001
From: Rashmi Mudduluru 
Date: Wed, 1 Nov 2023 13:43:12 -0700
Subject: [PATCH 1/9] [-Wunsafe-buffer-usage][WIP] Fixable gadget for AddAssign

---
 .../Analyses/UnsafeBufferUsageGadgets.def |  1 +
 clang/lib/Analysis/UnsafeBufferUsage.cpp  | 65 +++
 ...-unsafe-buffer-usage-fixits-add-assign.cpp | 38 +++
 3 files changed, 104 insertions(+)
 create mode 100644 
clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-add-assign.cpp

diff --git a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def 
b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
index ff687a0d178bdea..757ee452ced7488 100644
--- a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
+++ b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
@@ -36,6 +36,7 @@ FIXABLE_GADGET(PointerDereference)
 FIXABLE_GADGET(UPCAddressofArraySubscript) // '&DRE[any]' in an Unspecified 
Pointer Context
 FIXABLE_GADGET(UPCStandalonePointer)
 FIXABLE_GADGET(UPCPreIncrement)// '++Ptr' in an Unspecified 
Pointer Context
+FIXABLE_GADGET(UUCAddAssign)// 'Ptr += n' in an Unspecified 
Untyped Context
 FIXABLE_GADGET(PointerAssignment)
 FIXABLE_GADGET(PointerInit)
 
diff --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp 
b/clang/lib/Analysis/UnsafeBufferUsage.cpp
index e332a3609290aac..7b79f5360c79d6e 100644
--- a/clang/lib/Analysis/UnsafeBufferUsage.cpp
+++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp
@@ -1028,6 +1028,42 @@ class UPCPreIncrementGadget : public FixableGadget {
   }
 };
 
+// Representing a pointer type expression of the form `Ptr += n` in an
+// Unspecified Untyped Context (UUC):
+class UUCAddAssignGadget : public FixableGadget {
+private:
+  static constexpr const char *const UUCAddAssignTag =
+"PointerAddAssignUnderUUC";
+  const BinaryOperator *Node; // the `Ptr += n` node
+
+public:
+  UUCAddAssignGadget(const MatchFinder::MatchResult &Result)
+: FixableGadget(Kind::UUCAddAssign),
+  Node(Result.Nodes.getNodeAs(UUCAddAssignTag)) {
+assert(Node != nullptr && "Expecting a non-null matching result");
+  }
+
+  static bool classof(const Gadget *G) {
+return G->getKind() == Kind::UUCAddAssign;
+  }
+
+  static Matcher matcher() {
+return stmt(isInUnspecifiedUntypedContext(expr(ignoringImpCasts(
+binaryOperator(hasOperatorName("+="),
+  hasLHS(declRefExpr(
+toSupportedVariable()))
+  ).bind(UUCAddAssignTag);
+  }
+
+  virtual std::optional getFixits(const Strategy &S) const override;
+
+  virtual const Stmt *getBaseStmt() const override { return Node; }
+
+  virtual DeclUseList getClaimedVarUseSites() const override {
+return {dyn_cast(Node->getLHS())};
+  }
+};
+
 // Representing a fixable expression of the form `*(ptr + 123)` or `*(123 +
 // ptr)`:
 class DerefSimplePtrArithFixableGadget : public FixableGadget {
@@ -1766,6 +1802,35 @@ fixUPCAddressofArraySubscriptWithSpan(const 
UnaryOperator *Node) {
   FixItHint::CreateReplacement(Node->getSourceRange(), SS.str())};
 }
 
+std::optional UUCAddAssignGadget::getFixits(const Strategy &S) 
const {
+  DeclUseList DREs = getClaimedVarUseSites();
+
+  if (DREs.size() != 1)
+return std::nullopt; // In cases of `Ptr += n` where `Ptr` is not a DRE, we
+ // give up
+  if (const VarDecl *VD = dyn_cast(DREs.front()->getDecl())) {
+if (S.lookup(VD) == Strategy::Kind::Span) {
+  FixItList Fixes;
+  std::stringstream SS;
+  const Stmt *AddAssignNode = getBaseStmt();
+  StringRef varName = VD->getName();
+  const ASTContext &Ctx = VD->getASTContext();
+
+  // To transform UUC(p += n) to UUC((p = p.subspan(1)).data()):
+  SS << varName.data() << " = " << varName.data()
+ << ".subspan(" << getUserFillPlaceHolder() << ")";
+  std::optional AddAssignLocation =
+  getEndCharLoc(AddAssignNode, Ctx.getSourceManager(), 
Ctx.getLangOpts());
+  if (!AddAssignLocation)
+return std::nullopt;
+
+  Fixes.push_back(FixItHint::CreateReplacement(
+  SourceRange(AddAssignNode->getBeginLoc(), *AddAssignLocation), 
SS.str()));
+  return Fixes;
+}
+  }
+  return std::nullopt; // Not in the cases that we can handle for now, give up.
+}
 
 std::optional UPCPreIncrementGadget::getFixits(const Strategy &S) 
const {
   DeclUseList DREs = getClaimedVarUseSites();
diff --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-add-assign.cpp 
b/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-add-assign.cpp
new file mode 100644
index 000..e2b9a43dee9b3c3
--- /dev/null
+++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-add-assign.cpp
@@ -0,0 +1,38 @@
+// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage \
+// R

[clang] [-Wunsafe-buffer-usage] Add FixableGadget for AddAssign in UnspecifiedUntypedContext (PR #71862)

2023-11-15 Thread Rashmi Mudduluru via cfe-commits


@@ -0,0 +1,55 @@
+// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage \
+// RUN:-fsafe-buffer-usage-suggestions \
+// RUN:-fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
+void foo(int * , int *);
+
+void add_assign_test(unsigned int n, int *a, int y) {
+  int *p = new int[10];
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span p"
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{"
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:23-[[@LINE-3]]:23}:", 10}"
+  p += 2;
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:9}:"p = p.subspan(2)"

t-rasmud wrote:

IIUC, the default for count is `std::dynamic_extent` which ensures the correct 
number of elements in the subspan (and I guess the fixit for UPC pre-increment 
makes this assumption as well.) Is this not the case?

https://github.com/llvm/llvm-project/pull/71862
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [-Wunsafe-buffer-usage] Add FixableGadget for AddAssign in UnspecifiedUntypedContext (PR #71862)

2023-11-15 Thread Rashmi Mudduluru via cfe-commits

https://github.com/t-rasmud updated 
https://github.com/llvm/llvm-project/pull/71862

>From 6636745d1c444747a33c91b366a730d81ca5db5a Mon Sep 17 00:00:00 2001
From: Rashmi Mudduluru 
Date: Wed, 1 Nov 2023 13:43:12 -0700
Subject: [PATCH 01/10] [-Wunsafe-buffer-usage][WIP] Fixable gadget for
 AddAssign

---
 .../Analyses/UnsafeBufferUsageGadgets.def |  1 +
 clang/lib/Analysis/UnsafeBufferUsage.cpp  | 65 +++
 ...-unsafe-buffer-usage-fixits-add-assign.cpp | 38 +++
 3 files changed, 104 insertions(+)
 create mode 100644 
clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-add-assign.cpp

diff --git a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def 
b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
index ff687a0d178bdea..757ee452ced7488 100644
--- a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
+++ b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
@@ -36,6 +36,7 @@ FIXABLE_GADGET(PointerDereference)
 FIXABLE_GADGET(UPCAddressofArraySubscript) // '&DRE[any]' in an Unspecified 
Pointer Context
 FIXABLE_GADGET(UPCStandalonePointer)
 FIXABLE_GADGET(UPCPreIncrement)// '++Ptr' in an Unspecified 
Pointer Context
+FIXABLE_GADGET(UUCAddAssign)// 'Ptr += n' in an Unspecified 
Untyped Context
 FIXABLE_GADGET(PointerAssignment)
 FIXABLE_GADGET(PointerInit)
 
diff --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp 
b/clang/lib/Analysis/UnsafeBufferUsage.cpp
index e332a3609290aac..7b79f5360c79d6e 100644
--- a/clang/lib/Analysis/UnsafeBufferUsage.cpp
+++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp
@@ -1028,6 +1028,42 @@ class UPCPreIncrementGadget : public FixableGadget {
   }
 };
 
+// Representing a pointer type expression of the form `Ptr += n` in an
+// Unspecified Untyped Context (UUC):
+class UUCAddAssignGadget : public FixableGadget {
+private:
+  static constexpr const char *const UUCAddAssignTag =
+"PointerAddAssignUnderUUC";
+  const BinaryOperator *Node; // the `Ptr += n` node
+
+public:
+  UUCAddAssignGadget(const MatchFinder::MatchResult &Result)
+: FixableGadget(Kind::UUCAddAssign),
+  Node(Result.Nodes.getNodeAs(UUCAddAssignTag)) {
+assert(Node != nullptr && "Expecting a non-null matching result");
+  }
+
+  static bool classof(const Gadget *G) {
+return G->getKind() == Kind::UUCAddAssign;
+  }
+
+  static Matcher matcher() {
+return stmt(isInUnspecifiedUntypedContext(expr(ignoringImpCasts(
+binaryOperator(hasOperatorName("+="),
+  hasLHS(declRefExpr(
+toSupportedVariable()))
+  ).bind(UUCAddAssignTag);
+  }
+
+  virtual std::optional getFixits(const Strategy &S) const override;
+
+  virtual const Stmt *getBaseStmt() const override { return Node; }
+
+  virtual DeclUseList getClaimedVarUseSites() const override {
+return {dyn_cast(Node->getLHS())};
+  }
+};
+
 // Representing a fixable expression of the form `*(ptr + 123)` or `*(123 +
 // ptr)`:
 class DerefSimplePtrArithFixableGadget : public FixableGadget {
@@ -1766,6 +1802,35 @@ fixUPCAddressofArraySubscriptWithSpan(const 
UnaryOperator *Node) {
   FixItHint::CreateReplacement(Node->getSourceRange(), SS.str())};
 }
 
+std::optional UUCAddAssignGadget::getFixits(const Strategy &S) 
const {
+  DeclUseList DREs = getClaimedVarUseSites();
+
+  if (DREs.size() != 1)
+return std::nullopt; // In cases of `Ptr += n` where `Ptr` is not a DRE, we
+ // give up
+  if (const VarDecl *VD = dyn_cast(DREs.front()->getDecl())) {
+if (S.lookup(VD) == Strategy::Kind::Span) {
+  FixItList Fixes;
+  std::stringstream SS;
+  const Stmt *AddAssignNode = getBaseStmt();
+  StringRef varName = VD->getName();
+  const ASTContext &Ctx = VD->getASTContext();
+
+  // To transform UUC(p += n) to UUC((p = p.subspan(1)).data()):
+  SS << varName.data() << " = " << varName.data()
+ << ".subspan(" << getUserFillPlaceHolder() << ")";
+  std::optional AddAssignLocation =
+  getEndCharLoc(AddAssignNode, Ctx.getSourceManager(), 
Ctx.getLangOpts());
+  if (!AddAssignLocation)
+return std::nullopt;
+
+  Fixes.push_back(FixItHint::CreateReplacement(
+  SourceRange(AddAssignNode->getBeginLoc(), *AddAssignLocation), 
SS.str()));
+  return Fixes;
+}
+  }
+  return std::nullopt; // Not in the cases that we can handle for now, give up.
+}
 
 std::optional UPCPreIncrementGadget::getFixits(const Strategy &S) 
const {
   DeclUseList DREs = getClaimedVarUseSites();
diff --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-add-assign.cpp 
b/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-add-assign.cpp
new file mode 100644
index 000..e2b9a43dee9b3c3
--- /dev/null
+++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-add-assign.cpp
@@ -0,0 +1,38 @@
+// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage \
+/

[clang] [-Wunsafe-buffer-usage] Add FixableGadget for AddAssign in UnspecifiedUntypedContext (PR #71862)

2023-11-15 Thread Rashmi Mudduluru via cfe-commits

https://github.com/t-rasmud updated 
https://github.com/llvm/llvm-project/pull/71862

>From 6636745d1c444747a33c91b366a730d81ca5db5a Mon Sep 17 00:00:00 2001
From: Rashmi Mudduluru 
Date: Wed, 1 Nov 2023 13:43:12 -0700
Subject: [PATCH 01/11] [-Wunsafe-buffer-usage][WIP] Fixable gadget for
 AddAssign

---
 .../Analyses/UnsafeBufferUsageGadgets.def |  1 +
 clang/lib/Analysis/UnsafeBufferUsage.cpp  | 65 +++
 ...-unsafe-buffer-usage-fixits-add-assign.cpp | 38 +++
 3 files changed, 104 insertions(+)
 create mode 100644 
clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-add-assign.cpp

diff --git a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def 
b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
index ff687a0d178bdea..757ee452ced7488 100644
--- a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
+++ b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
@@ -36,6 +36,7 @@ FIXABLE_GADGET(PointerDereference)
 FIXABLE_GADGET(UPCAddressofArraySubscript) // '&DRE[any]' in an Unspecified 
Pointer Context
 FIXABLE_GADGET(UPCStandalonePointer)
 FIXABLE_GADGET(UPCPreIncrement)// '++Ptr' in an Unspecified 
Pointer Context
+FIXABLE_GADGET(UUCAddAssign)// 'Ptr += n' in an Unspecified 
Untyped Context
 FIXABLE_GADGET(PointerAssignment)
 FIXABLE_GADGET(PointerInit)
 
diff --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp 
b/clang/lib/Analysis/UnsafeBufferUsage.cpp
index e332a3609290aac..7b79f5360c79d6e 100644
--- a/clang/lib/Analysis/UnsafeBufferUsage.cpp
+++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp
@@ -1028,6 +1028,42 @@ class UPCPreIncrementGadget : public FixableGadget {
   }
 };
 
+// Representing a pointer type expression of the form `Ptr += n` in an
+// Unspecified Untyped Context (UUC):
+class UUCAddAssignGadget : public FixableGadget {
+private:
+  static constexpr const char *const UUCAddAssignTag =
+"PointerAddAssignUnderUUC";
+  const BinaryOperator *Node; // the `Ptr += n` node
+
+public:
+  UUCAddAssignGadget(const MatchFinder::MatchResult &Result)
+: FixableGadget(Kind::UUCAddAssign),
+  Node(Result.Nodes.getNodeAs(UUCAddAssignTag)) {
+assert(Node != nullptr && "Expecting a non-null matching result");
+  }
+
+  static bool classof(const Gadget *G) {
+return G->getKind() == Kind::UUCAddAssign;
+  }
+
+  static Matcher matcher() {
+return stmt(isInUnspecifiedUntypedContext(expr(ignoringImpCasts(
+binaryOperator(hasOperatorName("+="),
+  hasLHS(declRefExpr(
+toSupportedVariable()))
+  ).bind(UUCAddAssignTag);
+  }
+
+  virtual std::optional getFixits(const Strategy &S) const override;
+
+  virtual const Stmt *getBaseStmt() const override { return Node; }
+
+  virtual DeclUseList getClaimedVarUseSites() const override {
+return {dyn_cast(Node->getLHS())};
+  }
+};
+
 // Representing a fixable expression of the form `*(ptr + 123)` or `*(123 +
 // ptr)`:
 class DerefSimplePtrArithFixableGadget : public FixableGadget {
@@ -1766,6 +1802,35 @@ fixUPCAddressofArraySubscriptWithSpan(const 
UnaryOperator *Node) {
   FixItHint::CreateReplacement(Node->getSourceRange(), SS.str())};
 }
 
+std::optional UUCAddAssignGadget::getFixits(const Strategy &S) 
const {
+  DeclUseList DREs = getClaimedVarUseSites();
+
+  if (DREs.size() != 1)
+return std::nullopt; // In cases of `Ptr += n` where `Ptr` is not a DRE, we
+ // give up
+  if (const VarDecl *VD = dyn_cast(DREs.front()->getDecl())) {
+if (S.lookup(VD) == Strategy::Kind::Span) {
+  FixItList Fixes;
+  std::stringstream SS;
+  const Stmt *AddAssignNode = getBaseStmt();
+  StringRef varName = VD->getName();
+  const ASTContext &Ctx = VD->getASTContext();
+
+  // To transform UUC(p += n) to UUC((p = p.subspan(1)).data()):
+  SS << varName.data() << " = " << varName.data()
+ << ".subspan(" << getUserFillPlaceHolder() << ")";
+  std::optional AddAssignLocation =
+  getEndCharLoc(AddAssignNode, Ctx.getSourceManager(), 
Ctx.getLangOpts());
+  if (!AddAssignLocation)
+return std::nullopt;
+
+  Fixes.push_back(FixItHint::CreateReplacement(
+  SourceRange(AddAssignNode->getBeginLoc(), *AddAssignLocation), 
SS.str()));
+  return Fixes;
+}
+  }
+  return std::nullopt; // Not in the cases that we can handle for now, give up.
+}
 
 std::optional UPCPreIncrementGadget::getFixits(const Strategy &S) 
const {
   DeclUseList DREs = getClaimedVarUseSites();
diff --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-add-assign.cpp 
b/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-add-assign.cpp
new file mode 100644
index 000..e2b9a43dee9b3c3
--- /dev/null
+++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-add-assign.cpp
@@ -0,0 +1,38 @@
+// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage \
+/

[clang] [-Wunsafe-buffer-usage] Add FixableGadget for AddAssign in UnspecifiedUntypedContext (PR #71862)

2023-11-16 Thread Rashmi Mudduluru via cfe-commits

https://github.com/t-rasmud updated 
https://github.com/llvm/llvm-project/pull/71862

>From 6636745d1c444747a33c91b366a730d81ca5db5a Mon Sep 17 00:00:00 2001
From: Rashmi Mudduluru 
Date: Wed, 1 Nov 2023 13:43:12 -0700
Subject: [PATCH 01/12] [-Wunsafe-buffer-usage][WIP] Fixable gadget for
 AddAssign

---
 .../Analyses/UnsafeBufferUsageGadgets.def |  1 +
 clang/lib/Analysis/UnsafeBufferUsage.cpp  | 65 +++
 ...-unsafe-buffer-usage-fixits-add-assign.cpp | 38 +++
 3 files changed, 104 insertions(+)
 create mode 100644 
clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-add-assign.cpp

diff --git a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def 
b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
index ff687a0d178bdea..757ee452ced7488 100644
--- a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
+++ b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
@@ -36,6 +36,7 @@ FIXABLE_GADGET(PointerDereference)
 FIXABLE_GADGET(UPCAddressofArraySubscript) // '&DRE[any]' in an Unspecified 
Pointer Context
 FIXABLE_GADGET(UPCStandalonePointer)
 FIXABLE_GADGET(UPCPreIncrement)// '++Ptr' in an Unspecified 
Pointer Context
+FIXABLE_GADGET(UUCAddAssign)// 'Ptr += n' in an Unspecified 
Untyped Context
 FIXABLE_GADGET(PointerAssignment)
 FIXABLE_GADGET(PointerInit)
 
diff --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp 
b/clang/lib/Analysis/UnsafeBufferUsage.cpp
index e332a3609290aac..7b79f5360c79d6e 100644
--- a/clang/lib/Analysis/UnsafeBufferUsage.cpp
+++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp
@@ -1028,6 +1028,42 @@ class UPCPreIncrementGadget : public FixableGadget {
   }
 };
 
+// Representing a pointer type expression of the form `Ptr += n` in an
+// Unspecified Untyped Context (UUC):
+class UUCAddAssignGadget : public FixableGadget {
+private:
+  static constexpr const char *const UUCAddAssignTag =
+"PointerAddAssignUnderUUC";
+  const BinaryOperator *Node; // the `Ptr += n` node
+
+public:
+  UUCAddAssignGadget(const MatchFinder::MatchResult &Result)
+: FixableGadget(Kind::UUCAddAssign),
+  Node(Result.Nodes.getNodeAs(UUCAddAssignTag)) {
+assert(Node != nullptr && "Expecting a non-null matching result");
+  }
+
+  static bool classof(const Gadget *G) {
+return G->getKind() == Kind::UUCAddAssign;
+  }
+
+  static Matcher matcher() {
+return stmt(isInUnspecifiedUntypedContext(expr(ignoringImpCasts(
+binaryOperator(hasOperatorName("+="),
+  hasLHS(declRefExpr(
+toSupportedVariable()))
+  ).bind(UUCAddAssignTag);
+  }
+
+  virtual std::optional getFixits(const Strategy &S) const override;
+
+  virtual const Stmt *getBaseStmt() const override { return Node; }
+
+  virtual DeclUseList getClaimedVarUseSites() const override {
+return {dyn_cast(Node->getLHS())};
+  }
+};
+
 // Representing a fixable expression of the form `*(ptr + 123)` or `*(123 +
 // ptr)`:
 class DerefSimplePtrArithFixableGadget : public FixableGadget {
@@ -1766,6 +1802,35 @@ fixUPCAddressofArraySubscriptWithSpan(const 
UnaryOperator *Node) {
   FixItHint::CreateReplacement(Node->getSourceRange(), SS.str())};
 }
 
+std::optional UUCAddAssignGadget::getFixits(const Strategy &S) 
const {
+  DeclUseList DREs = getClaimedVarUseSites();
+
+  if (DREs.size() != 1)
+return std::nullopt; // In cases of `Ptr += n` where `Ptr` is not a DRE, we
+ // give up
+  if (const VarDecl *VD = dyn_cast(DREs.front()->getDecl())) {
+if (S.lookup(VD) == Strategy::Kind::Span) {
+  FixItList Fixes;
+  std::stringstream SS;
+  const Stmt *AddAssignNode = getBaseStmt();
+  StringRef varName = VD->getName();
+  const ASTContext &Ctx = VD->getASTContext();
+
+  // To transform UUC(p += n) to UUC((p = p.subspan(1)).data()):
+  SS << varName.data() << " = " << varName.data()
+ << ".subspan(" << getUserFillPlaceHolder() << ")";
+  std::optional AddAssignLocation =
+  getEndCharLoc(AddAssignNode, Ctx.getSourceManager(), 
Ctx.getLangOpts());
+  if (!AddAssignLocation)
+return std::nullopt;
+
+  Fixes.push_back(FixItHint::CreateReplacement(
+  SourceRange(AddAssignNode->getBeginLoc(), *AddAssignLocation), 
SS.str()));
+  return Fixes;
+}
+  }
+  return std::nullopt; // Not in the cases that we can handle for now, give up.
+}
 
 std::optional UPCPreIncrementGadget::getFixits(const Strategy &S) 
const {
   DeclUseList DREs = getClaimedVarUseSites();
diff --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-add-assign.cpp 
b/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-add-assign.cpp
new file mode 100644
index 000..e2b9a43dee9b3c3
--- /dev/null
+++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-add-assign.cpp
@@ -0,0 +1,38 @@
+// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage \
+/

[clang] [-Wunsafe-buffer-usage] Add FixableGadget for AddAssign in UnspecifiedUntypedContext (PR #71862)

2023-11-16 Thread Rashmi Mudduluru via cfe-commits

https://github.com/t-rasmud updated 
https://github.com/llvm/llvm-project/pull/71862

>From 6636745d1c444747a33c91b366a730d81ca5db5a Mon Sep 17 00:00:00 2001
From: Rashmi Mudduluru 
Date: Wed, 1 Nov 2023 13:43:12 -0700
Subject: [PATCH 01/13] [-Wunsafe-buffer-usage][WIP] Fixable gadget for
 AddAssign

---
 .../Analyses/UnsafeBufferUsageGadgets.def |  1 +
 clang/lib/Analysis/UnsafeBufferUsage.cpp  | 65 +++
 ...-unsafe-buffer-usage-fixits-add-assign.cpp | 38 +++
 3 files changed, 104 insertions(+)
 create mode 100644 
clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-add-assign.cpp

diff --git a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def 
b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
index ff687a0d178bdea..757ee452ced7488 100644
--- a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
+++ b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
@@ -36,6 +36,7 @@ FIXABLE_GADGET(PointerDereference)
 FIXABLE_GADGET(UPCAddressofArraySubscript) // '&DRE[any]' in an Unspecified 
Pointer Context
 FIXABLE_GADGET(UPCStandalonePointer)
 FIXABLE_GADGET(UPCPreIncrement)// '++Ptr' in an Unspecified 
Pointer Context
+FIXABLE_GADGET(UUCAddAssign)// 'Ptr += n' in an Unspecified 
Untyped Context
 FIXABLE_GADGET(PointerAssignment)
 FIXABLE_GADGET(PointerInit)
 
diff --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp 
b/clang/lib/Analysis/UnsafeBufferUsage.cpp
index e332a3609290aac..7b79f5360c79d6e 100644
--- a/clang/lib/Analysis/UnsafeBufferUsage.cpp
+++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp
@@ -1028,6 +1028,42 @@ class UPCPreIncrementGadget : public FixableGadget {
   }
 };
 
+// Representing a pointer type expression of the form `Ptr += n` in an
+// Unspecified Untyped Context (UUC):
+class UUCAddAssignGadget : public FixableGadget {
+private:
+  static constexpr const char *const UUCAddAssignTag =
+"PointerAddAssignUnderUUC";
+  const BinaryOperator *Node; // the `Ptr += n` node
+
+public:
+  UUCAddAssignGadget(const MatchFinder::MatchResult &Result)
+: FixableGadget(Kind::UUCAddAssign),
+  Node(Result.Nodes.getNodeAs(UUCAddAssignTag)) {
+assert(Node != nullptr && "Expecting a non-null matching result");
+  }
+
+  static bool classof(const Gadget *G) {
+return G->getKind() == Kind::UUCAddAssign;
+  }
+
+  static Matcher matcher() {
+return stmt(isInUnspecifiedUntypedContext(expr(ignoringImpCasts(
+binaryOperator(hasOperatorName("+="),
+  hasLHS(declRefExpr(
+toSupportedVariable()))
+  ).bind(UUCAddAssignTag);
+  }
+
+  virtual std::optional getFixits(const Strategy &S) const override;
+
+  virtual const Stmt *getBaseStmt() const override { return Node; }
+
+  virtual DeclUseList getClaimedVarUseSites() const override {
+return {dyn_cast(Node->getLHS())};
+  }
+};
+
 // Representing a fixable expression of the form `*(ptr + 123)` or `*(123 +
 // ptr)`:
 class DerefSimplePtrArithFixableGadget : public FixableGadget {
@@ -1766,6 +1802,35 @@ fixUPCAddressofArraySubscriptWithSpan(const 
UnaryOperator *Node) {
   FixItHint::CreateReplacement(Node->getSourceRange(), SS.str())};
 }
 
+std::optional UUCAddAssignGadget::getFixits(const Strategy &S) 
const {
+  DeclUseList DREs = getClaimedVarUseSites();
+
+  if (DREs.size() != 1)
+return std::nullopt; // In cases of `Ptr += n` where `Ptr` is not a DRE, we
+ // give up
+  if (const VarDecl *VD = dyn_cast(DREs.front()->getDecl())) {
+if (S.lookup(VD) == Strategy::Kind::Span) {
+  FixItList Fixes;
+  std::stringstream SS;
+  const Stmt *AddAssignNode = getBaseStmt();
+  StringRef varName = VD->getName();
+  const ASTContext &Ctx = VD->getASTContext();
+
+  // To transform UUC(p += n) to UUC((p = p.subspan(1)).data()):
+  SS << varName.data() << " = " << varName.data()
+ << ".subspan(" << getUserFillPlaceHolder() << ")";
+  std::optional AddAssignLocation =
+  getEndCharLoc(AddAssignNode, Ctx.getSourceManager(), 
Ctx.getLangOpts());
+  if (!AddAssignLocation)
+return std::nullopt;
+
+  Fixes.push_back(FixItHint::CreateReplacement(
+  SourceRange(AddAssignNode->getBeginLoc(), *AddAssignLocation), 
SS.str()));
+  return Fixes;
+}
+  }
+  return std::nullopt; // Not in the cases that we can handle for now, give up.
+}
 
 std::optional UPCPreIncrementGadget::getFixits(const Strategy &S) 
const {
   DeclUseList DREs = getClaimedVarUseSites();
diff --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-add-assign.cpp 
b/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-add-assign.cpp
new file mode 100644
index 000..e2b9a43dee9b3c3
--- /dev/null
+++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-add-assign.cpp
@@ -0,0 +1,38 @@
+// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage \
+/

[clang] [-Wunsafe-buffer-usage] Add FixableGadget for AddAssign in UnspecifiedUntypedContext (PR #71862)

2023-11-17 Thread Rashmi Mudduluru via cfe-commits

https://github.com/t-rasmud updated 
https://github.com/llvm/llvm-project/pull/71862

>From 6636745d1c444747a33c91b366a730d81ca5db5a Mon Sep 17 00:00:00 2001
From: Rashmi Mudduluru 
Date: Wed, 1 Nov 2023 13:43:12 -0700
Subject: [PATCH 01/14] [-Wunsafe-buffer-usage][WIP] Fixable gadget for
 AddAssign

---
 .../Analyses/UnsafeBufferUsageGadgets.def |  1 +
 clang/lib/Analysis/UnsafeBufferUsage.cpp  | 65 +++
 ...-unsafe-buffer-usage-fixits-add-assign.cpp | 38 +++
 3 files changed, 104 insertions(+)
 create mode 100644 
clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-add-assign.cpp

diff --git a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def 
b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
index ff687a0d178bdea..757ee452ced7488 100644
--- a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
+++ b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
@@ -36,6 +36,7 @@ FIXABLE_GADGET(PointerDereference)
 FIXABLE_GADGET(UPCAddressofArraySubscript) // '&DRE[any]' in an Unspecified 
Pointer Context
 FIXABLE_GADGET(UPCStandalonePointer)
 FIXABLE_GADGET(UPCPreIncrement)// '++Ptr' in an Unspecified 
Pointer Context
+FIXABLE_GADGET(UUCAddAssign)// 'Ptr += n' in an Unspecified 
Untyped Context
 FIXABLE_GADGET(PointerAssignment)
 FIXABLE_GADGET(PointerInit)
 
diff --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp 
b/clang/lib/Analysis/UnsafeBufferUsage.cpp
index e332a3609290aac..7b79f5360c79d6e 100644
--- a/clang/lib/Analysis/UnsafeBufferUsage.cpp
+++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp
@@ -1028,6 +1028,42 @@ class UPCPreIncrementGadget : public FixableGadget {
   }
 };
 
+// Representing a pointer type expression of the form `Ptr += n` in an
+// Unspecified Untyped Context (UUC):
+class UUCAddAssignGadget : public FixableGadget {
+private:
+  static constexpr const char *const UUCAddAssignTag =
+"PointerAddAssignUnderUUC";
+  const BinaryOperator *Node; // the `Ptr += n` node
+
+public:
+  UUCAddAssignGadget(const MatchFinder::MatchResult &Result)
+: FixableGadget(Kind::UUCAddAssign),
+  Node(Result.Nodes.getNodeAs(UUCAddAssignTag)) {
+assert(Node != nullptr && "Expecting a non-null matching result");
+  }
+
+  static bool classof(const Gadget *G) {
+return G->getKind() == Kind::UUCAddAssign;
+  }
+
+  static Matcher matcher() {
+return stmt(isInUnspecifiedUntypedContext(expr(ignoringImpCasts(
+binaryOperator(hasOperatorName("+="),
+  hasLHS(declRefExpr(
+toSupportedVariable()))
+  ).bind(UUCAddAssignTag);
+  }
+
+  virtual std::optional getFixits(const Strategy &S) const override;
+
+  virtual const Stmt *getBaseStmt() const override { return Node; }
+
+  virtual DeclUseList getClaimedVarUseSites() const override {
+return {dyn_cast(Node->getLHS())};
+  }
+};
+
 // Representing a fixable expression of the form `*(ptr + 123)` or `*(123 +
 // ptr)`:
 class DerefSimplePtrArithFixableGadget : public FixableGadget {
@@ -1766,6 +1802,35 @@ fixUPCAddressofArraySubscriptWithSpan(const 
UnaryOperator *Node) {
   FixItHint::CreateReplacement(Node->getSourceRange(), SS.str())};
 }
 
+std::optional UUCAddAssignGadget::getFixits(const Strategy &S) 
const {
+  DeclUseList DREs = getClaimedVarUseSites();
+
+  if (DREs.size() != 1)
+return std::nullopt; // In cases of `Ptr += n` where `Ptr` is not a DRE, we
+ // give up
+  if (const VarDecl *VD = dyn_cast(DREs.front()->getDecl())) {
+if (S.lookup(VD) == Strategy::Kind::Span) {
+  FixItList Fixes;
+  std::stringstream SS;
+  const Stmt *AddAssignNode = getBaseStmt();
+  StringRef varName = VD->getName();
+  const ASTContext &Ctx = VD->getASTContext();
+
+  // To transform UUC(p += n) to UUC((p = p.subspan(1)).data()):
+  SS << varName.data() << " = " << varName.data()
+ << ".subspan(" << getUserFillPlaceHolder() << ")";
+  std::optional AddAssignLocation =
+  getEndCharLoc(AddAssignNode, Ctx.getSourceManager(), 
Ctx.getLangOpts());
+  if (!AddAssignLocation)
+return std::nullopt;
+
+  Fixes.push_back(FixItHint::CreateReplacement(
+  SourceRange(AddAssignNode->getBeginLoc(), *AddAssignLocation), 
SS.str()));
+  return Fixes;
+}
+  }
+  return std::nullopt; // Not in the cases that we can handle for now, give up.
+}
 
 std::optional UPCPreIncrementGadget::getFixits(const Strategy &S) 
const {
   DeclUseList DREs = getClaimedVarUseSites();
diff --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-add-assign.cpp 
b/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-add-assign.cpp
new file mode 100644
index 000..e2b9a43dee9b3c3
--- /dev/null
+++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-add-assign.cpp
@@ -0,0 +1,38 @@
+// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage \
+/

[clang] Warning for unsafe invocation of span::data (PR #75650)

2023-12-15 Thread Rashmi Mudduluru via cfe-commits


@@ -721,6 +721,33 @@ class UnsafeBufferUsageAttrGadget : public WarningGadget {
   DeclUseList getClaimedVarUseSites() const override { return {}; }
 };
 
+// Warning gadget for unsafe invocation of span::data method.
+// Triggers when the pointer returned by the invocation is immediately
+// cast to a larger type.
+
+class DataInvocationGadget : public WarningGadget {
+  constexpr static const char *const OpTag = "data_invocation_expr";
+  const ExplicitCastExpr *Op;
+
+  public:
+  DataInvocationGadget(const MatchFinder::MatchResult &Result)
+  : WarningGadget(Kind::DataInvocation),
+Op(Result.Nodes.getNodeAs(OpTag)) {}
+
+  static bool classof(const Gadget *G) {
+return G->getKind() == Kind::DataInvocation;
+  }
+ 
+  static Matcher matcher() {
+return stmt(
+explicitCastExpr(has(cxxMemberCallExpr(callee(
+   cxxMethodDecl(hasName("data")).bind(OpTag));

t-rasmud wrote:

Will this also match on user defined functions called "data"? I think something 
like `cxxMethodDecl(ofClass(hasName("span")))` might be needed to match 
`span.data()` alone (but I might be wrong). In any case, maybe have a test case 
with a user defined function called "data" which'll show the matcher matches 
only on `span.data()`.

https://github.com/llvm/llvm-project/pull/75650
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Warning for unsafe invocation of span::data (PR #75650)

2023-12-15 Thread Rashmi Mudduluru via cfe-commits

https://github.com/t-rasmud edited 
https://github.com/llvm/llvm-project/pull/75650
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Warning for unsafe invocation of span::data (PR #75650)

2023-12-15 Thread Rashmi Mudduluru via cfe-commits

https://github.com/t-rasmud requested changes to this pull request.


https://github.com/llvm/llvm-project/pull/75650
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [-Wunsafe-buffer-usage] Add a subgroup `-Wunsafe-buffer-usage-in-container` (PR #75665)

2023-12-15 Thread Rashmi Mudduluru via cfe-commits

https://github.com/t-rasmud approved this pull request.


https://github.com/llvm/llvm-project/pull/75665
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Warning for unsafe invocation of span::data (PR #75650)

2023-12-18 Thread Rashmi Mudduluru via cfe-commits

https://github.com/t-rasmud approved this pull request.

LGTM!

https://github.com/llvm/llvm-project/pull/75650
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] eb1d908 - Adds AST matcher for ObjCStringLiteral

2022-06-30 Thread Rashmi Mudduluru via cfe-commits

Author: Rashmi Mudduluru
Date: 2022-06-30T15:20:10-07:00
New Revision: eb1d908e5cf7279b98b84d1587d4665d3cdecbe9

URL: 
https://github.com/llvm/llvm-project/commit/eb1d908e5cf7279b98b84d1587d4665d3cdecbe9
DIFF: 
https://github.com/llvm/llvm-project/commit/eb1d908e5cf7279b98b84d1587d4665d3cdecbe9.diff

LOG: Adds AST matcher for ObjCStringLiteral

Differential Revision: https://reviews.llvm.org/D128103

Added: 


Modified: 
clang/docs/LibASTMatchersReference.html
clang/docs/ReleaseNotes.rst
clang/include/clang/ASTMatchers/ASTMatchers.h
clang/lib/ASTMatchers/ASTMatchersInternal.cpp
clang/lib/ASTMatchers/Dynamic/Registry.cpp
clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp

Removed: 




diff  --git a/clang/docs/LibASTMatchersReference.html 
b/clang/docs/LibASTMatchersReference.html
index c206c63e84acb..03ca48cc1a9b3 100644
--- a/clang/docs/LibASTMatchersReference.html
+++ b/clang/docs/LibASTMatchersReference.html
@@ -1236,7 +1236,7 @@ Node Matchers
   #pragma omp parallel
 
 ``ompDefaultClause()`` matches ``default(none)``, ``default(shared)``,
-``default(private)`` and ``default(firstprivate)``
+`` default(private)`` and ``default(firstprivate)``
 
 
 
@@ -2036,6 +2036,14 @@ Node Matchers
 
 
 
+MatcherStmt>objcStringLiteralMatcherObjCStringLiteral>...
+Matches 
ObjectiveC String literal expressions.
+
+Example matches @"abcd"
+  NSString *s = @"abcd";
+
+
+
 MatcherStmt>objcThrowStmtMatcherObjCAtThrowStmt>...
 Matches Objective-C 
statements.
 
@@ -4716,8 +4724,8 @@ Narrowing Matchers
 
 
 
-MatcherOMPDefaultClause>isFirstPrivateKind
-Matches if the OpenMP 
``default`` clause has ``private`` kind
+MatcherOMPDefaultClause>isFirstPrivateKind
+Matches if the 
OpenMP ``default`` clause has ``firstprivate`` kind
 specified.
 
 Given
@@ -4729,12 +4737,12 @@ Narrowing Matchers
   #pragma omp parallel default(firstprivate)
 
 ``ompDefaultClause(isFirstPrivateKind())`` matches only
-``default(private)``.
+``default(firstprivate)``.
 
 
-MatcherOMPDefaultClause>isFirstPrivateKind
-Matches if the 
OpenMP ``default`` clause has ``firstprivate`` kind
-specified.
+
+MatcherOMPDefaultClause>isNoneKind
+Matches if the OpenMP 
``default`` clause has ``none`` kind specified.
 
 Given
 
@@ -4744,13 +4752,13 @@ Narrowing Matchers
   #pragma omp parallel default(private)
   #pragma omp parallel default(firstprivate)
 
-``ompDefaultClause(isFirstPrivateKind())`` matches only
-``default(firstprivate)``.
+``ompDefaultClause(isNoneKind())`` matches only ``default(none)``.
 
 
 
-MatcherOMPDefaultClause>isNoneKind
-Matches if the OpenMP 
``default`` clause has ``none`` kind specified.
+MatcherOMPDefaultClause>isPrivateKind
+Matches if the OpenMP 
``default`` clause has ``private`` kind
+specified.
 
 Given
 
@@ -4760,7 +4768,8 @@ Narrowing Matchers
   #pragma omp parallel default(private)
   #pragma omp parallel default(firstprivate)
 
-``ompDefaultClause(isNoneKind())`` matches only ``default(none)``.
+``ompDefaultClause(isPrivateKind())`` matches only
+``default(private)``.
 
 
 
@@ -7411,8 +7420,9 @@ AST Traversal Matchers
 
 
 
-MatcherClassTemplateSpecializationDecl>forEachTemplateArgumentMatcherTemplateArgument>
 InnerMatcher
-Matches 
classTemplateSpecialization, templateSpecializationType and functionDecl nodes 
where the template argument matches the inner matcher.
+MatcherClassTemplateSpecializationDecl>forEachTemplateArgumentclang::ast_matchers::MatcherTemplateArgument>
 InnerMatcher
+Matches 
classTemplateSpecialization, templateSpecializationType and
+functionDecl nodes where the template argument matches the inner matcher.
 This matcher may produce multiple matches.
 
 Given
@@ -7427,10 +7437,8 @@ AST Traversal Matchers
 
   bool B = false;
   f(R, B);
-
 templateSpecializationType(forEachTemplateArgument(isExpr(expr(
   matches twice, with expr() matching 'R * 2' and 'R * 4'
-
 functionDecl(forEachTemplateArgument(refersToType(builtin

[clang-tools-extra] 95a9299 - Adds the NSDateFormatter checker to clang-tidy

2022-08-02 Thread Rashmi Mudduluru via cfe-commits

Author: Rashmi Mudduluru
Date: 2022-08-02T13:57:44-07:00
New Revision: 95a92995d45fc6fada43ecd91eba3e7aea90487a

URL: 
https://github.com/llvm/llvm-project/commit/95a92995d45fc6fada43ecd91eba3e7aea90487a
DIFF: 
https://github.com/llvm/llvm-project/commit/95a92995d45fc6fada43ecd91eba3e7aea90487a.diff

LOG: Adds the NSDateFormatter checker to clang-tidy

Differential Revision: https://reviews.llvm.org/D126097

Added: 
clang-tools-extra/clang-tidy/objc/NSDateFormatterCheck.cpp
clang-tools-extra/clang-tidy/objc/NSDateFormatterCheck.h
clang-tools-extra/docs/clang-tidy/checks/objc/nsdate-formatter.rst
clang-tools-extra/test/clang-tidy/checkers/objc/nsdate-formatter.m

Modified: 
clang-tools-extra/clang-tidy/objc/CMakeLists.txt
clang-tools-extra/clang-tidy/objc/ObjCTidyModule.cpp
clang-tools-extra/docs/clang-tidy/checks/list.rst

Removed: 




diff  --git a/clang-tools-extra/clang-tidy/objc/CMakeLists.txt 
b/clang-tools-extra/clang-tidy/objc/CMakeLists.txt
index 1129c6aa729f..bdd125c97cc0 100644
--- a/clang-tools-extra/clang-tidy/objc/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/objc/CMakeLists.txt
@@ -10,6 +10,7 @@ add_clang_library(clangTidyObjCModule
   ForbiddenSubclassingCheck.cpp
   MissingHashCheck.cpp
   NSInvocationArgumentLifetimeCheck.cpp
+  NSDateFormatterCheck.cpp
   ObjCTidyModule.cpp
   PropertyDeclarationCheck.cpp
   SuperSelfCheck.cpp

diff  --git a/clang-tools-extra/clang-tidy/objc/NSDateFormatterCheck.cpp 
b/clang-tools-extra/clang-tidy/objc/NSDateFormatterCheck.cpp
new file mode 100644
index ..fdc837704a69
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/objc/NSDateFormatterCheck.cpp
@@ -0,0 +1,116 @@
+//===--- NSDateFormatterCheck.cpp - clang-tidy 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+
+#include "NSDateFormatterCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace objc {
+
+void NSDateFormatterCheck::registerMatchers(MatchFinder *Finder) {
+  // Adding matchers.
+
+  Finder->addMatcher(
+  objcMessageExpr(hasSelector("setDateFormat:"),
+  hasReceiverType(asString("NSDateFormatter *")),
+  hasArgument(0, ignoringImpCasts(
+ 
objcStringLiteral().bind("str_lit",
+  this);
+}
+
+static char ValidDatePatternChars[] = {
+'G', 'y', 'Y', 'u', 'U', 'r', 'Q', 'q', 'M', 'L', 'I', 'w', 'W', 'd',
+'D', 'F', 'g', 'E', 'e', 'c', 'a', 'b', 'B', 'h', 'H', 'K', 'k', 'j',
+'J', 'C', 'm', 's', 'S', 'A', 'z', 'Z', 'O', 'v', 'V', 'X', 'x'};
+
+// Checks if the string pattern used as a date format specifier is valid.
+// A string pattern is valid if all the letters(a-z, A-Z) in it belong to the
+// set of reserved characters. See:
+// https://www.unicode.org/reports/tr35/tr35.html#Invalid_Patterns
+bool isValidDatePattern(StringRef Pattern) {
+  for (auto &PatternChar : Pattern) {
+if (isalpha(PatternChar)) {
+  if (std::find(std::begin(ValidDatePatternChars),
+std::end(ValidDatePatternChars),
+PatternChar) == std::end(ValidDatePatternChars)) {
+return false;
+  }
+}
+  }
+  return true;
+}
+
+// Checks if the string pattern used as a date format specifier contains
+// any incorrect pattern and reports it as a warning.
+// See: 
http://www.unicode.org/reports/tr35/tr35-dates.html#Date_Format_Patterns
+void NSDateFormatterCheck::check(const MatchFinder::MatchResult &Result) {
+  // Callback implementation.
+  const auto *StrExpr = Result.Nodes.getNodeAs("str_lit");
+  const StringLiteral *SL = cast(StrExpr)->getString();
+  StringRef SR = SL->getString();
+
+  if (!isValidDatePattern(SR)) {
+diag(StrExpr->getExprLoc(), "invalid date format specifier");
+  }
+
+  if (SR.contains('y') && SR.contains('w') && !SR.contains('Y')) {
+diag(StrExpr->getExprLoc(),
+ "use of calendar year (y) with week of the year (w); "
+ "did you mean to use week-year (Y) instead?");
+  }
+  if (SR.contains('F')) {
+if (!(SR.contains('e') || SR.contains('E'))) {
+  diag(StrExpr->getExprLoc(),
+   "day of week in month (F) used without day of the week (e or E); "
+   "did you forget e (or E) in the format string?");
+}
+if (!SR.contains('M')) {
+  diag(StrExpr->getExprLoc(),
+   "day of week in month (F) used without the month (M); "
+   "did you forget M in the format string?");
+}
+  }
+  if (SR.contains('W') && !S

[clang-tools-extra] 13bc713 - fixes clang-tidy/checks/list.rst: a line was accidentally removed in 95a92995d45fc6fada43ecd91eba3e7aea90487a

2022-08-05 Thread Rashmi Mudduluru via cfe-commits

Author: Rashmi Mudduluru
Date: 2022-08-05T12:36:03-07:00
New Revision: 13bc71310920dced155328e25aa382dc2bb1ef9f

URL: 
https://github.com/llvm/llvm-project/commit/13bc71310920dced155328e25aa382dc2bb1ef9f
DIFF: 
https://github.com/llvm/llvm-project/commit/13bc71310920dced155328e25aa382dc2bb1ef9f.diff

LOG: fixes clang-tidy/checks/list.rst: a line was accidentally removed in 
95a92995d45fc6fada43ecd91eba3e7aea90487a

Added: 


Modified: 
clang-tools-extra/docs/clang-tidy/checks/list.rst

Removed: 




diff  --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst 
b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index b72e3ca69c39d..a7c6247ab96bf 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -239,6 +239,7 @@ Clang-Tidy Checks
`llvmlibc-implementation-in-namespace 
`_,
`llvmlibc-restrict-system-libc-headers 
`_, "Yes"
`misc-confusable-identifiers `_,
+   `misc-const-correctness `_, "Yes"
`misc-definitions-in-headers `_, "Yes"
`misc-misleading-bidirectional `_,
`misc-misleading-identifier `_,



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] ce42082 - [Analyzer] Re-enables trustnonnullchecker_test.m

2022-02-10 Thread Rashmi Mudduluru via cfe-commits

Author: Rashmi Mudduluru
Date: 2022-02-10T18:52:48-08:00
New Revision: ce420820c815e806bab9c5f17cb3b829a616548a

URL: 
https://github.com/llvm/llvm-project/commit/ce420820c815e806bab9c5f17cb3b829a616548a
DIFF: 
https://github.com/llvm/llvm-project/commit/ce420820c815e806bab9c5f17cb3b829a616548a.diff

LOG: [Analyzer] Re-enables trustnonnullchecker_test.m

Differential review: https://reviews.llvm.org/D119270

Added: 


Modified: 
clang/test/Analysis/trustnonnullchecker_test.m

Removed: 




diff  --git a/clang/test/Analysis/trustnonnullchecker_test.m 
b/clang/test/Analysis/trustnonnullchecker_test.m
index 81eac863d5eb..4240502cbbdd 100644
--- a/clang/test/Analysis/trustnonnullchecker_test.m
+++ b/clang/test/Analysis/trustnonnullchecker_test.m
@@ -1,6 +1,3 @@
-// Temporarily disabling the test, it failes the "system is over-constrained"
-// assertion in *non* optimized builds.
-// REQUIRES: rdar44992170
 // RUN: %clang_analyze_cc1 -fblocks -analyze 
-analyzer-checker=core,nullability,apiModeling,debug.ExprInspection  -verify %s
 
 #include "Inputs/system-header-simulator-for-nullability.h"



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] 572e2cd - Reverting ce420820c815e806bab9c5f17cb3b829a616548a because it fails expensive checks

2022-02-16 Thread Rashmi Mudduluru via cfe-commits

Author: Rashmi Mudduluru
Date: 2022-02-16T09:25:53-08:00
New Revision: 572e2cd56a43429bdbc88c886e260b5facff9048

URL: 
https://github.com/llvm/llvm-project/commit/572e2cd56a43429bdbc88c886e260b5facff9048
DIFF: 
https://github.com/llvm/llvm-project/commit/572e2cd56a43429bdbc88c886e260b5facff9048.diff

LOG: Reverting ce420820c815e806bab9c5f17cb3b829a616548a because it fails 
expensive checks

Added: 


Modified: 
clang/test/Analysis/trustnonnullchecker_test.m

Removed: 




diff  --git a/clang/test/Analysis/trustnonnullchecker_test.m 
b/clang/test/Analysis/trustnonnullchecker_test.m
index 5e09c4f6dde21..cb0c1cdcab61a 100644
--- a/clang/test/Analysis/trustnonnullchecker_test.m
+++ b/clang/test/Analysis/trustnonnullchecker_test.m
@@ -1,3 +1,6 @@
+// Temporarily disabling the test, it failes the "system is over-constrained" 
(part of expensive checks)
+// assertion in *non* optimized builds.
+// REQUIRES: rdar44992170
 // RUN: %clang_analyze_cc1 -fblocks -analyze 
-analyzer-checker=core,nullability,apiModeling,debug.ExprInspection  -verify %s
 
 #include "Inputs/system-header-simulator-for-nullability.h"



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] acc3cc6 - [-Wunsafe-buffer-usage] Introduce the unsafe_buffer_usage attribute

2023-01-31 Thread Rashmi Mudduluru via cfe-commits

Author: Rashmi Mudduluru
Date: 2023-01-31T11:43:34-08:00
New Revision: acc3cc69e4d1c8e199fde51798a5a2a6edb35796

URL: 
https://github.com/llvm/llvm-project/commit/acc3cc69e4d1c8e199fde51798a5a2a6edb35796
DIFF: 
https://github.com/llvm/llvm-project/commit/acc3cc69e4d1c8e199fde51798a5a2a6edb35796.diff

LOG: [-Wunsafe-buffer-usage] Introduce the unsafe_buffer_usage attribute

Differential Revision: https://reviews.llvm.org/D138940

Added: 
clang/test/SemaCXX/attr-unsafe-buffer-usage.cpp
clang/test/SemaCXX/warn-unsafe-buffer-usage-function-attr.cpp

Modified: 
clang/docs/ReleaseNotes.rst
clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
clang/include/clang/Basic/Attr.td
clang/include/clang/Basic/AttrDocs.td
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/lib/Analysis/UnsafeBufferUsage.cpp
clang/lib/Sema/AnalysisBasedWarnings.cpp
clang/lib/Sema/SemaDeclAttr.cpp
clang/test/Misc/pragma-attribute-supported-attributes-list.test

Removed: 




diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 0a1197044a71a..c6139252e0c34 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -89,6 +89,11 @@ New Pragmas in Clang
 Attribute Changes in Clang
 --
 
+Introduced a new function attribute ``__attribute__((unsafe_buffer_usage))``
+to be worn by functions containing buffer operations that could cause out of
+bounds memory accesses. It emits warnings at call sites to such functions when
+the flag ``-Wunsafe-buffer-usage`` is enabled.
+
 Windows Support
 ---
 

diff  --git 
a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def 
b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
index d10d95e5b1ba7..78889da32b3b4 100644
--- a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
+++ b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
@@ -29,6 +29,7 @@ WARNING_GADGET(Increment)
 WARNING_GADGET(Decrement)
 WARNING_GADGET(ArraySubscript)
 WARNING_GADGET(PointerArithmetic)
+WARNING_GADGET(UnsafeBufferUsageAttr)
 
 #undef FIXABLE_GADGET
 #undef WARNING_GADGET

diff  --git a/clang/include/clang/Basic/Attr.td 
b/clang/include/clang/Basic/Attr.td
index d449a2fe7f8f7..fc2c7f7e37f45 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -3966,6 +3966,12 @@ def ReleaseHandle : InheritableParamAttr {
   let Documentation = [ReleaseHandleDocs];
 }
 
+def UnsafeBufferUsage : InheritableAttr {
+  let Spellings = [Clang<"unsafe_buffer_usage">];
+  let Subjects = SubjectList<[Function]>;
+  let Documentation = [UnsafeBufferUsageDocs];
+}
+
 def DiagnoseAsBuiltin : InheritableAttr {
   let Spellings = [Clang<"diagnose_as_builtin">];
   let Args = [DeclArgument,

diff  --git a/clang/include/clang/Basic/AttrDocs.td 
b/clang/include/clang/Basic/AttrDocs.td
index 6d7a3ffd2d52c..b0b11e85ab6ad 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -6274,6 +6274,82 @@ attribute requires a string literal argument to identify 
the handle being releas
   }];
 }
 
+def UnsafeBufferUsageDocs : Documentation {
+  let Content = [{
+The attribute ``[[clang::unsafe_buffer_usage]]`` should be placed on functions
+that need to be avoided as they are prone to buffer overflows. It is designed 
to
+work together with the off-by-default compiler warning 
``-Wunsafe-buffer-usage``
+to help codebases transition away from raw pointer based buffer management,
+in favor of safer abstractions such as C++20 ``std::span``. The attribute 
causes
+``-Wunsafe-buffer-usage`` to warn on every use of the function, and it may
+enable ``-Wunsafe-buffer-usage`` to emit automatic fix-it hints
+which would help the user replace such unsafe functions with safe
+alternatives, though the attribute can be used even when the fix can't be 
automated.
+
+The attribute does not suppress ``-Wunsafe-buffer-usage`` inside the function
+to which it is attached. These warnings still need to be addressed.
+
+The attribute is warranted even if the only way a function can overflow
+the buffer is by violating the function's preconditions. For example, it
+would make sense to put the attribute on function ``foo()`` below because
+passing an incorrect size parameter would cause a buffer overflow:
+
+.. code-block:: c++
+  [[clang::unsafe_buffer_usage]]
+  void foo(int *buf, size_t size) {
+for (size_t i = 0; i < size; ++i) {
+  buf[i] = i;
+}
+  }
+
+The attribute is NOT warranted when the function uses safe abstractions,
+assuming that these abstractions weren't misused outside the function.
+For example, function ``bar()`` below doesn't need the attribute,
+because assuming that the container ``buf`` is well-formed (has size that
+fits the original buffer it refers to), overflow cannot occur:
+
+.. code-block:: c++
+

[clang] fe93da2 - [-Wunsafe-buffer-usage] Emit warnings about unsafe operations on arrays

2023-01-17 Thread Rashmi Mudduluru via cfe-commits

Author: Rashmi Mudduluru
Date: 2023-01-17T16:30:13-08:00
New Revision: fe93da22aa7bd57e277571cd692c7c0cc51c0478

URL: 
https://github.com/llvm/llvm-project/commit/fe93da22aa7bd57e277571cd692c7c0cc51c0478
DIFF: 
https://github.com/llvm/llvm-project/commit/fe93da22aa7bd57e277571cd692c7c0cc51c0478.diff

LOG: [-Wunsafe-buffer-usage] Emit warnings about unsafe operations on arrays

Differential Revision: https://reviews.llvm.org/D141725/new/

Added: 


Modified: 
clang/lib/Analysis/UnsafeBufferUsage.cpp
clang/test/SemaCXX/warn-unsafe-buffer-usage.cpp

Removed: 




diff  --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp 
b/clang/lib/Analysis/UnsafeBufferUsage.cpp
index 97f81368273e9..fa72d20bea6fe 100644
--- a/clang/lib/Analysis/UnsafeBufferUsage.cpp
+++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp
@@ -133,6 +133,10 @@ static auto hasPointerType() {
 return hasType(hasCanonicalType(pointerType()));
 }
 
+static auto hasArrayType() {
+return hasType(hasCanonicalType(arrayType()));
+}
+
 namespace {
 /// Gadget is an individual operation in the code that may be of interest to
 /// this analysis. Each (non-abstract) subclass corresponds to a specific
@@ -292,9 +296,13 @@ class ArraySubscriptGadget : public WarningGadget {
   static Matcher matcher() {
 // FIXME: What if the index is integer literal 0? Should this be
 // a safe gadget in this case?
-return 
stmt(arraySubscriptExpr(hasBase(ignoringParenImpCasts(hasPointerType())),
-   unless(hasIndex(integerLiteral(equals(0)
-.bind(ArraySubscrTag));
+  // clang-format off
+  return stmt(arraySubscriptExpr(
+hasBase(ignoringParenImpCasts(
+  anyOf(hasPointerType(), hasArrayType(,
+unless(hasIndex(integerLiteral(equals(0)
+.bind(ArraySubscrTag));
+  // clang-format on
   }
 
   const ArraySubscriptExpr *getBaseStmt() const override { return ASE; }
@@ -516,7 +524,8 @@ static std::tuple findGadg
 #include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
 // In parallel, match all DeclRefExprs so that to find out
 // whether there are any uncovered by gadgets.
-declRefExpr(hasPointerType(), to(varDecl())).bind("any_dre"),
+declRefExpr(anyOf(hasPointerType(), hasArrayType()),
+to(varDecl())).bind("any_dre"),
 // Also match DeclStmts because we'll need them when fixing
 // their underlying VarDecls that otherwise don't have
 // any backreferences to DeclStmts.

diff  --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage.cpp 
b/clang/test/SemaCXX/warn-unsafe-buffer-usage.cpp
index 476ec73c4f744..87831334746aa 100644
--- a/clang/test/SemaCXX/warn-unsafe-buffer-usage.cpp
+++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage.cpp
@@ -49,11 +49,10 @@ void testArraySubscripts(int *p, int **pp) {
 
   int a[10], b[10][10];
 
-  // Not to warn subscripts on arrays
-  foo(a[1], 1[a],
-  b[3][4],
-  4[b][3],
-  4[3[b]]);
+  foo(a[1], 1[a], // expected-warning2{{unchecked operation on raw buffer in 
expression}}
+  b[3][4],  // expected-warning2{{unchecked operation on raw buffer in 
expression}}
+  4[b][3],  // expected-warning2{{unchecked operation on raw buffer in 
expression}}
+  4[3[b]]); // expected-warning2{{unchecked operation on raw buffer in 
expression}}
 
   // Not to warn when index is zero
   foo(p[0], pp[0][0], 0[0[pp]], 0[pp][0],
@@ -96,8 +95,7 @@ void testQualifiedParameters(const int * p, const int * const 
q,
   foo(p[1], 1[p], p[-1],   // expected-warning3{{unchecked operation on raw 
buffer in expression}}
   q[1], 1[q], q[-1],   // expected-warning3{{unchecked operation on raw 
buffer in expression}}
   a[1],// expected-warning{{unchecked operation on raw 
buffer in expression}} `a` is of pointer type
-  b[1][2], // expected-warning{{unchecked operation on raw 
buffer in expression}} `b[1]` is of array type
-  c[1] // `c` is of array type
+  b[1][2]  // expected-warning2{{unchecked operation on raw 
buffer in expression}} `b[1]` is of array type
   );
 }
 
@@ -116,27 +114,27 @@ T_t funRetT();
 T_t * funRetTStar();
 
 void testStructMembers(struct T * sp, struct T s, T_t * sp2, T_t s2) {
-  foo(sp->a[1],
-  sp->b[1], // expected-warning{{unchecked operation on raw buffer in 
expression}}
-  sp->c.a[1],
-  sp->c.b[1],   // expected-warning{{unchecked operation on raw buffer in 
expression}}
-  s.a[1],
-  s.b[1],   // expected-warning{{unchecked operation on raw buffer in 
expression}}
-  s.c.a[1],
-  s.c.b[1], // expected-warning{{unchecked operation on raw buffer in 
expression}}
-  sp2->a[1],
-  sp2->b[1],// expected-warning{{unchecked operation on raw buffer in 
expression}}
-  sp2->c.a[1],
-  sp2

[clang] 87b8c85 - [-Wunsafe-bugger-usage] Clean tests: remove nondeterministic ordering

2023-09-19 Thread Rashmi Mudduluru via cfe-commits

Author: Rashmi Mudduluru
Date: 2023-09-19T14:20:45-07:00
New Revision: 87b8c85bba5298fea657b71eb7c75aeb1afa446d

URL: 
https://github.com/llvm/llvm-project/commit/87b8c85bba5298fea657b71eb7c75aeb1afa446d
DIFF: 
https://github.com/llvm/llvm-project/commit/87b8c85bba5298fea657b71eb7c75aeb1afa446d.diff

LOG: [-Wunsafe-bugger-usage] Clean tests: remove nondeterministic ordering

Differential Review: https://reviews.llvm.org/D158553

Added: 


Modified: 

clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-deref-simple-ptr-arith.cpp
clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-local-var-span.cpp
clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-pointer-deref.cpp
clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-pre-increment.cpp
clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-unevaluated-context.cpp
clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-fixits-test.cpp
clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-ptr-init-fixits.cpp
clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-ptr-init.cpp
clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-uuc-fixits.cpp
clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-uuc.cpp
clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-warnings.cpp
clang/test/SemaCXX/warn-unsafe-buffer-usage-pragma-fixit.cpp
clang/test/SemaCXX/warn-unsafe-buffer-usage-source-ranges.cpp

Removed: 




diff  --git 
a/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-deref-simple-ptr-arith.cpp 
b/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-deref-simple-ptr-arith.cpp
index 90cfa6842fae8c8..a4a09a0afed595f 100644
--- 
a/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-deref-simple-ptr-arith.cpp
+++ 
b/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-deref-simple-ptr-arith.cpp
@@ -10,169 +10,169 @@
 
 void basic() {
   int *ptr;
-// CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span 
ptr"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span ptr"
   *(ptr+5)=1;
-// CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:5}:""
-// CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:8-[[@LINE-2]]:9}:"["
-// CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:11}:"]"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:5}:""
+// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:8-[[@LINE-2]]:9}:"["
+// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:11}:"]"
 }
 
 // The weird preceding semicolon ensures that we preserve that range intact.
 void char_ranges() {
   int *p;
-  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:9}:"std::span 
p"
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:9}:"std::span p"
 
   ;* ( p + 5 ) = 1;
-  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:4-[[@LINE-1]]:8}:""
-  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:9-[[@LINE-2]]:12}:"["
-  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:13-[[@LINE-3]]:15}:"]"
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:4-[[@LINE-1]]:8}:""
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:9-[[@LINE-2]]:12}:"["
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:13-[[@LINE-3]]:15}:"]"
 
   ;*   (p+5)= 1;
-  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:4-[[@LINE-1]]:9}:""
-  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:10-[[@LINE-2]]:11}:"["
-  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:12-[[@LINE-3]]:13}:"]"
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:4-[[@LINE-1]]:9}:""
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:10-[[@LINE-2]]:11}:"["
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:12-[[@LINE-3]]:13}:"]"
 
   ;*(   p+5)= 1;
-  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:4-[[@LINE-1]]:9}:""
-  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:10-[[@LINE-2]]:11}:"["
-  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:12-[[@LINE-3]]:13}:"]"
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:4-[[@LINE-1]]:9}:""
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:10-[[@LINE-2]]:11}:"["
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:12-[[@LINE-3]]:13}:"]"
 
   ;*(   p+5)= 1;
-  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:4-[[@LINE-1]]:9}:""
-  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:10-[[@LINE-2]]:11}:"["
-  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:12-[[@LINE-3]]:13}:"]"
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:4-[[@LINE-1]]:9}:""
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:10-[[@LINE-2]]:11}:"["
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:12-[[@LINE-3]]:13}:"]"
 
   ;*( p   +5)= 1;
-  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:4-[[@LINE-1]]:7}:""
-  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:8-[[@LINE-2]]:12}:"["
-  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:13-[[@LINE-3]]:14}:"]"
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:4-[[@LINE-1]]:7}:""
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:8-[[@LINE-2]]:12}:"["
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:13-[[@LINE-3]]:14}:"]"
 
   ;*(p+   5)= 1;
-  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:4-[[@LINE-1]]:6}:""
-  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:7-[[@LINE-2]]:11}:"

[clang] 3ea673a - [clang][docs] Update LibASTMatchersReference.html

2023-07-18 Thread Rashmi Mudduluru via cfe-commits

Author: Rashmi Mudduluru
Date: 2023-07-18T15:27:59-07:00
New Revision: 3ea673a97b0583affc22345b9d62e863ba36b3d8

URL: 
https://github.com/llvm/llvm-project/commit/3ea673a97b0583affc22345b9d62e863ba36b3d8
DIFF: 
https://github.com/llvm/llvm-project/commit/3ea673a97b0583affc22345b9d62e863ba36b3d8.diff

LOG: [clang][docs] Update LibASTMatchersReference.html

Differential Revision: https://reviews.llvm.org/D155304

Added: 


Modified: 
clang/docs/LibASTMatchersReference.html

Removed: 




diff  --git a/clang/docs/LibASTMatchersReference.html 
b/clang/docs/LibASTMatchersReference.html
index e6b8c771f1a394..bde8ac7de52a73 100644
--- a/clang/docs/LibASTMatchersReference.html
+++ b/clang/docs/LibASTMatchersReference.html
@@ -1455,6 +1455,16 @@ Node Matchers
 
 
 
+MatcherStmt>coroutineBodyStmtMatcherCoroutineBodyStmt>...
+Matches coroutine 
body statements.
+
+coroutineBodyStmt() matches the coroutine below
+  generator gen() {
+co_return;
+  }
+
+
+
 MatcherStmt>coyieldExprMatcherCoyieldExpr>...
 Matches co_yield 
expressions.
 
@@ -3037,10 +3047,11 @@ Narrowing Matchers
 
 
 MatcherCXXConstructExpr>argumentCountAtLeastunsigned 
N
-Checks that a 
call expression or a constructor call expression has
-at least the specified number of arguments (including absent default 
arguments).
+Checks that a 
call expression or a constructor call expression has at least
+the specified number of arguments (including absent default arguments).
 
-Example matches f(0, 0) and g(0, 0, 0) (matcher = 
callExpr(argumentCountAtLeast(2)))
+Example matches f(0, 0) and g(0, 0, 0)
+(matcher = callExpr(argumentCountAtLeast(2)))
   void f(int x, int y);
   void g(int x, int y, int z);
   f(0, 0);
@@ -3706,10 +3717,11 @@ Narrowing Matchers
 
 
 MatcherCXXUnresolvedConstructExpr>argumentCountAtLeastunsigned 
N
-Checks that a 
call expression or a constructor call expression has
-at least the specified number of arguments (including absent default 
arguments).
+Checks that a 
call expression or a constructor call expression has at least
+the specified number of arguments (including absent default arguments).
 
-Example matches f(0, 0) and g(0, 0, 0) (matcher = 
callExpr(argumentCountAtLeast(2)))
+Example matches f(0, 0) and g(0, 0, 0)
+(matcher = callExpr(argumentCountAtLeast(2)))
   void f(int x, int y);
   void g(int x, int y, int z);
   f(0, 0);
@@ -3728,10 +3740,11 @@ Narrowing Matchers
 
 
 MatcherCallExpr>argumentCountAtLeastunsigned 
N
-Checks that a 
call expression or a constructor call expression has
-at least the specified number of arguments (including absent default 
arguments).
+Checks that a 
call expression or a constructor call expression has at least
+the specified number of arguments (including absent default arguments).
 
-Example matches f(0, 0) and g(0, 0, 0) (matcher = 
callExpr(argumentCountAtLeast(2)))
+Example matches f(0, 0) and g(0, 0, 0)
+(matcher = callExpr(argumentCountAtLeast(2)))
   void f(int x, int y);
   void g(int x, int y, int z);
   f(0, 0);
@@ -4897,10 +4910,11 @@ Narrowing Matchers
 
 
 MatcherObjCMessageExpr>argumentCountAtLeastunsigned 
N
-Checks that a 
call expression or a constructor call expression has
-at least the specified number of arguments (including absent default 
arguments).
+Checks that a 
call expression or a constructor call expression has at least
+the specified number of arguments (including absent default arguments).
 
-Example matches f(0, 0) and g(0, 0, 0) (matcher = 
callExpr(argumentCountAtLeast(2)))
+Example matches f(0, 0) and g(0, 0, 0)
+(matcher = callExpr(argumentCountAtLeast(2)))
   void f(int x, int y);
   void g(int x, int y, int z);
   f(0, 0);
@@ -6795,9 +6809,10 @@ AST Traversal Matchers
 
 
 MatcherCXXForRangeStmt>hasBodyMatcherStmt> 
InnerMatcher
-Matches a 'for', 'while', 
'do' statement or a function definition that has
-a given body. Note that in case of functions this matcher only matches the
-definition itself and not the other declarations of the same function.
+Matches a 'for', 'while', 
'while' statement or a function or coroutine
+definition that has a given body. Note that in case of functions or
+coroutines this matcher only matches the definition itself and not the
+other declarations of the same function o

[clang] 1e62587 - [clang][docs] Defensively turn off exception behavior in dump_ast_matchers.py

2023-07-18 Thread Rashmi Mudduluru via cfe-commits

Author: Rashmi Mudduluru
Date: 2023-07-18T15:36:09-07:00
New Revision: 1e62587a48a33b3bf5939e1eef2fd4e41b7e75f6

URL: 
https://github.com/llvm/llvm-project/commit/1e62587a48a33b3bf5939e1eef2fd4e41b7e75f6
DIFF: 
https://github.com/llvm/llvm-project/commit/1e62587a48a33b3bf5939e1eef2fd4e41b7e75f6.diff

LOG: [clang][docs] Defensively turn off exception behavior in 
dump_ast_matchers.py

Differential Revision: https://reviews.llvm.org/D155134

Added: 


Modified: 
clang/docs/tools/dump_ast_matchers.py

Removed: 




diff  --git a/clang/docs/tools/dump_ast_matchers.py 
b/clang/docs/tools/dump_ast_matchers.py
index 8ac3c2166d4231..cc7024d1627b97 100755
--- a/clang/docs/tools/dump_ast_matchers.py
+++ b/clang/docs/tools/dump_ast_matchers.py
@@ -15,7 +15,8 @@
 try:
 CLASS_INDEX_PAGE = urlopen(CLASS_INDEX_PAGE_URL).read().decode("utf-8")
 except Exception as e:
-raise Exception("Unable to get %s: %s" % (CLASS_INDEX_PAGE_URL, e))
+CLASS_INDEX_PAGE = None
+print("Unable to get %s: %s" % (CLASS_INDEX_PAGE_URL, e))
 
 MATCHERS_FILE = "../../include/clang/ASTMatchers/ASTMatchers.h"
 
@@ -58,7 +59,10 @@ def link_if_exists(m):
 url = "https://clang.llvm.org/doxygen/classclang_1_1%s.html"; % name
 if url not in doxygen_probes:
 search_str = 'href="classclang_1_1%s.html"' % name
-doxygen_probes[url] = search_str in CLASS_INDEX_PAGE
+if CLASS_INDEX_PAGE is not None:
+doxygen_probes[url] = search_str in CLASS_INDEX_PAGE
+else:
+doxygen_probes[url] = True
 if not doxygen_probes[url]:
 print("Did not find %s in class index page" % name)
 if doxygen_probes[url]:
@@ -186,7 +190,7 @@ def act_on_decl(declaration, comment, allowed_types):
 """
 if declaration.strip():
 
-if re.match(r"^\s?(#|namespace|using)", declaration):
+if re.match(r"^\s?(#|namespace|using|template  
using|})", declaration):
 return
 
 # Node matchers are defined by writing:



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] 27c1033 - [WIP][-Wunsafe-buffer-usage] Handle lambda expressions within a method.

2023-07-20 Thread Rashmi Mudduluru via cfe-commits

Author: Rashmi Mudduluru
Date: 2023-07-20T10:00:16-07:00
New Revision: 27c10337831c94ef59f8790f6ca1c3d1b66b4494

URL: 
https://github.com/llvm/llvm-project/commit/27c10337831c94ef59f8790f6ca1c3d1b66b4494
DIFF: 
https://github.com/llvm/llvm-project/commit/27c10337831c94ef59f8790f6ca1c3d1b66b4494.diff

LOG: [WIP][-Wunsafe-buffer-usage] Handle lambda expressions within a method.

Differential Revision: https://reviews.llvm.org/D150386

Added: 


Modified: 
clang/docs/LibASTMatchersReference.html
clang/docs/ReleaseNotes.rst
clang/include/clang/ASTMatchers/ASTMatchers.h
clang/lib/ASTMatchers/ASTMatchersInternal.cpp
clang/lib/ASTMatchers/Dynamic/Registry.cpp
clang/lib/Analysis/UnsafeBufferUsage.cpp
clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-pointer-access.cpp
clang/test/SemaCXX/warn-unsafe-buffer-usage.cpp

Removed: 




diff  --git a/clang/docs/LibASTMatchersReference.html 
b/clang/docs/LibASTMatchersReference.html
index bde8ac7de52a73..b4f282fbf43816 100644
--- a/clang/docs/LibASTMatchersReference.html
+++ b/clang/docs/LibASTMatchersReference.html
@@ -1257,6 +1257,43 @@ Node Matchers
 
 
 
+MatcherStmt>arrayInitIndexExprMatcherArrayInitIndexExpr>...
+The 
arrayInitIndexExpr consists of two subexpressions: a common expression
+(the source array) that is evaluated once up-front, and a per-element 
initializer
+that runs once for each array element. Within the per-element initializer,
+the current index may be obtained via an ArrayInitIndexExpr.
+
+Given
+  void testStructBinding() {
+int a[2] = {1, 2};
+auto [x, y] = a;
+  }
+arrayInitIndexExpr() matches the array index that implicitly iterates
+over the array `a` to copy each element to the anonymous array
+that backs the structured binding `[x, y]` elements of which are
+referred to by their aliases `x` and `y`.
+
+
+
+MatcherStmt>arrayInitLoopExprMatcherArrayInitLoopExpr>...
+Matches a loop 
initializing the elements of an array in a number of contexts:
+ * in the implicit copy/move constructor for a class with an array member
+ * when a lambda-expression captures an array by value
+ * when a decomposition declaration decomposes an array
+
+Given
+  void testLambdaCapture() {
+int a[10];
+auto Lam1 = [a]() {
+  return;
+};
+  }
+arrayInitLoopExpr() matches the implicit loop that initializes each element of
+the implicit array field inside the lambda object, that represents the array 
`a`
+captured by value.
+
+
+
 MatcherStmt>arraySubscriptExprMatcherArraySubscriptExpr>...
 Matches array 
subscript expressions.
 

diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index ef1cc898c21f6d..f1d098ef02f41d 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -943,6 +943,8 @@ AST Matchers
 
 - The ``hasBody`` matcher now matches coroutine body nodes in
   ``CoroutineBodyStmts``.
+  
+- Add ``arrayInitIndexExpr`` and ``arrayInitLoopExpr`` matchers.
 
 clang-format
 

diff  --git a/clang/include/clang/ASTMatchers/ASTMatchers.h 
b/clang/include/clang/ASTMatchers/ASTMatchers.h
index b698365f949bfa..a9313139226ca4 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchers.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -1971,6 +1971,45 @@ extern const internal::VariadicDynCastAllOfMatcher
 extern const internal::VariadicDynCastAllOfMatcher
 cxxNoexceptExpr;
 
+/// Matches a loop initializing the elements of an array in a number of 
contexts:
+///  * in the implicit copy/move constructor for a class with an array member
+///  * when a lambda-expression captures an array by value
+///  * when a decomposition declaration decomposes an array
+///
+/// Given
+/// \code
+///   void testLambdaCapture() {
+/// int a[10];
+/// auto Lam1 = [a]() {
+///   return;
+/// };
+///   }
+/// \endcode
+/// arrayInitLoopExpr() matches the implicit loop that initializes each 
element of
+/// the implicit array field inside the lambda object, that represents the 
array `a`
+/// captured by value.
+extern const internal::VariadicDynCastAllOfMatcher
+arrayInitLoopExpr;
+
+/// The arrayInitIndexExpr consists of two subexpressions: a common expression
+/// (the source array) that is evaluated once up-front, and a per-element 
initializer
+/// that runs once for each array element. Within the per-element initializer,
+/// the current index may be obtained via an ArrayInitIndexExpr.
+///
+/// Given
+/// \code
+///   void testStructBinding() {
+/// int a[2] = {1, 2};
+/// 

[clang] 070358e - [-Wunsafe-buffer-usage] Fix a fallthrough case in UPCStandalonePointer getFixits

2023-07-25 Thread Rashmi Mudduluru via cfe-commits

Author: Rashmi Mudduluru
Date: 2023-07-25T13:40:33-07:00
New Revision: 070358ec92350c13b0b6c60fbb03bf35a7a00251

URL: 
https://github.com/llvm/llvm-project/commit/070358ec92350c13b0b6c60fbb03bf35a7a00251
DIFF: 
https://github.com/llvm/llvm-project/commit/070358ec92350c13b0b6c60fbb03bf35a7a00251.diff

LOG: [-Wunsafe-buffer-usage] Fix a fallthrough case in UPCStandalonePointer 
getFixits

Differential Revision: https://reviews.llvm.org/D155526

Added: 
clang/test/SemaCXX/warn-unsafe-buffer-usage-test-unreachable.cpp

Modified: 
clang/lib/Analysis/UnsafeBufferUsage.cpp

Removed: 




diff  --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp 
b/clang/lib/Analysis/UnsafeBufferUsage.cpp
index 5cde60cefdf065..78f180447eef6f 100644
--- a/clang/lib/Analysis/UnsafeBufferUsage.cpp
+++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp
@@ -1512,8 +1512,8 @@ PointerDereferenceGadget::getFixits(const Strategy &S) 
const {
 FixItHint::CreateInsertion(
 (*EndOfOperand).getLocWithOffset(1), "[0]")}};
 }
+break;
   }
-[[fallthrough]];
   case Strategy::Kind::Iterator:
   case Strategy::Kind::Array:
   case Strategy::Kind::Vector:
@@ -1541,8 +1541,9 @@ std::optional 
UPCStandalonePointerGadget::getFixits(const Strategy &S
   if (EndOfOperand)
 return FixItList{{FixItHint::CreateInsertion(
 *EndOfOperand, ".data()")}};
+  // FIXME: Points inside a macro expansion.
+  break;
 }
-  [[fallthrough]];
 case Strategy::Kind::Wontfix:
 case Strategy::Kind::Iterator:
 case Strategy::Kind::Array:

diff  --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-test-unreachable.cpp 
b/clang/test/SemaCXX/warn-unsafe-buffer-usage-test-unreachable.cpp
new file mode 100644
index 00..844311c3a51a58
--- /dev/null
+++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-test-unreachable.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage 
-fsafe-buffer-usage-suggestions -verify %s
+
+// expected-no-diagnostics
+
+typedef unsigned __darwin_size_t;
+typedef __darwin_size_t size_t;
+ #define bzero(s, n) __builtin_bzero(s, n)
+void __nosan_bzero(void *dst, size_t sz) { bzero(dst, sz); }



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] a6ae740 - [-Wunsafe-buffer-usage] Add a facility for debugging low fixit coverage

2023-07-26 Thread Rashmi Mudduluru via cfe-commits

Author: Rashmi Mudduluru
Date: 2023-07-26T17:07:36-07:00
New Revision: a6ae740e743a2241f7104c13152cd0a0582765c5

URL: 
https://github.com/llvm/llvm-project/commit/a6ae740e743a2241f7104c13152cd0a0582765c5
DIFF: 
https://github.com/llvm/llvm-project/commit/a6ae740e743a2241f7104c13152cd0a0582765c5.diff

LOG: [-Wunsafe-buffer-usage] Add a facility for debugging low fixit coverage

Differential Revision: https://reviews.llvm.org/D154880

Added: 
clang/test/SemaCXX/warn-unsafe-buffer-usage-debug.cpp

Modified: 
clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/lib/Analysis/UnsafeBufferUsage.cpp
clang/lib/Sema/AnalysisBasedWarnings.cpp

Removed: 




diff  --git a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h 
b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h
index 6766ba8ec2..13f28076c6f4d7 100644
--- a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h
+++ b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h
@@ -16,6 +16,7 @@
 
 #include "clang/AST/Decl.h"
 #include "clang/AST/Stmt.h"
+#include "llvm/Support/Debug.h"
 
 namespace clang {
 
@@ -24,6 +25,18 @@ using DefMapTy = llvm::DenseMap>;
 /// The interface that lets the caller handle unsafe buffer usage analysis
 /// results by overriding this class's handle... methods.
 class UnsafeBufferUsageHandler {
+#ifndef NDEBUG
+public:
+  // A self-debugging facility that you can use to notify the user when
+  // suggestions or fixits are incomplete.
+  // Uses std::function to avoid computing the message when it won't
+  // actually be displayed.
+  using DebugNote = std::pair;
+  using DebugNoteList = std::vector;
+  using DebugNoteByVar = std::map;
+  DebugNoteByVar DebugNotesByVar;
+#endif
+
 public:
   UnsafeBufferUsageHandler() = default;
   virtual ~UnsafeBufferUsageHandler() = default;
@@ -43,6 +56,26 @@ class UnsafeBufferUsageHandler {
  const DefMapTy &VarGrpMap,
  FixItList &&Fixes) = 0;
 
+#ifndef NDEBUG
+public:
+  bool areDebugNotesRequested() {
+DEBUG_WITH_TYPE("SafeBuffers", return true);
+return false;
+  }
+
+  void addDebugNoteForVar(const VarDecl *VD, SourceLocation Loc,
+  std::string Text) {
+if (areDebugNotesRequested())
+  DebugNotesByVar[VD].push_back(std::make_pair(Loc, Text));
+  }
+
+  void clearDebugNotes() {
+if (areDebugNotesRequested())
+  DebugNotesByVar.clear();
+  }
+#endif
+
+public:
   /// Returns a reference to the `Preprocessor`:
   virtual bool isSafeBufferOptOut(const SourceLocation &Loc) const = 0;
 

diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index c88f25209fc0fa..b531babf0449c4 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -11872,6 +11872,12 @@ def note_unsafe_buffer_variable_fixit_group : Note<
   "change type of %0 to '%select{std::span|std::array|std::span::iterator}1' 
to preserve bounds information%select{|, and change %2 to 
'%select{std::span|std::array|std::span::iterator}1' to propagate bounds 
information between them}3">;
 def note_safe_buffer_usage_suggestions_disabled : Note<
   "pass -fsafe-buffer-usage-suggestions to receive code hardening 
suggestions">;
+#ifndef NDEBUG
+// Not a user-facing diagnostic. Useful for debugging false negatives in
+// -fsafe-buffer-usage-suggestions (i.e. lack of -Wunsafe-buffer-usage fixits).
+def note_safe_buffer_debug_mode : Note<"safe buffers debug: %0">;
+#endif
+
 def err_loongarch_builtin_requires_la32 : Error<
   "this builtin requires target: loongarch32">;
 

diff  --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp 
b/clang/lib/Analysis/UnsafeBufferUsage.cpp
index 7b1c5107a7e049..781dc13c898d22 100644
--- a/clang/lib/Analysis/UnsafeBufferUsage.cpp
+++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp
@@ -316,6 +316,15 @@ class Gadget {
 
   Kind getKind() const { return K; }
 
+#ifndef NDEBUG
+  StringRef getDebugName() const {
+switch (K) {
+#define GADGET(x) case Kind::x: return #x;
+#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
+}
+  }
+#endif
+
   virtual bool isWarningGadget() const = 0;
   virtual const Stmt *getBaseStmt() const = 0;
 
@@ -565,7 +574,11 @@ class PointerInitGadget : public FixableGadget {
 
   virtual std::optional getFixits(const Strategy &S) const override;
 
-  virtual const Stmt *getBaseStmt() const override { return nullptr; }
+  virtual const Stmt *getBaseStmt() const override {
+// FIXME: This needs to be the entire DeclStmt, assuming that this method
+// makes sense at all on a FixableGadget.
+return PtrInitRHS;
+  }
 
   virtual DeclUseList getClaimedVarUseSites() const override {
 return DeclUseList{PtrInitRHS};
@@ -613,7 +626,11 @

[clang] cf1c64b - [-Wunsafe-buffer-usage] Replace assert that declarations are always found

2023-08-15 Thread Rashmi Mudduluru via cfe-commits

Author: Rashmi Mudduluru
Date: 2023-08-15T15:41:56-07:00
New Revision: cf1c64b94d94105f61e308e57eb963b722d22d77

URL: 
https://github.com/llvm/llvm-project/commit/cf1c64b94d94105f61e308e57eb963b722d22d77
DIFF: 
https://github.com/llvm/llvm-project/commit/cf1c64b94d94105f61e308e57eb963b722d22d77.diff

LOG: [-Wunsafe-buffer-usage] Replace assert that declarations are always found

Differential Revision: https://reviews.llvm.org/D157018

Added: 


Modified: 
clang/lib/Analysis/UnsafeBufferUsage.cpp
clang/test/SemaCXX/warn-unsafe-buffer-usage-debug.cpp

Removed: 




diff  --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp 
b/clang/lib/Analysis/UnsafeBufferUsage.cpp
index 6f9f5f5e7ee7f2..87087686171347 100644
--- a/clang/lib/Analysis/UnsafeBufferUsage.cpp
+++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp
@@ -888,7 +888,8 @@ class DeclUseTracker {
 
   const DeclStmt *lookupDecl(const VarDecl *VD) const {
 auto It = Defs.find(VD);
-assert(It != Defs.end() && "Definition never discovered!");
+if (It == Defs.end())
+  return nullptr;
 return It->second;
   }
 };
@@ -2053,7 +2054,10 @@ static FixItList fixVariableWithSpan(const VarDecl *VD,
  ASTContext &Ctx,
  UnsafeBufferUsageHandler &Handler) {
   const DeclStmt *DS = Tracker.lookupDecl(VD);
-  assert(DS && "Fixing non-local variables not implemented yet!");
+  if (!DS) {
+DEBUG_NOTE_DECL_FAIL(VD, " : variables declared this way not implemented 
yet");
+return {};
+  }
   if (!DS->isSingleDecl()) {
 // FIXME: to support handling multiple `VarDecl`s in a single `DeclStmt`
 DEBUG_NOTE_DECL_FAIL(VD, " : multiple VarDecls");

diff  --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-debug.cpp 
b/clang/test/SemaCXX/warn-unsafe-buffer-usage-debug.cpp
index 79031cdb7691d3..f0f9a52cc3d0c9 100644
--- a/clang/test/SemaCXX/warn-unsafe-buffer-usage-debug.cpp
+++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-debug.cpp
@@ -66,3 +66,15 @@ void implied_unclaimed_var(int *b) {  // 
expected-warning{{'b' is an unsafe poin
   b++;  // expected-note{{used in pointer arithmetic here}} \
 // debug-note{{safe buffers debug: failed to produce fixit for 'b' : 
has an unclaimed use}}
 }
+
+int *a = new int[3];  // expected-warning{{'a' is an unsafe pointer used for 
buffer access}} \
+// debug-note{{safe buffers debug: failed to produce fixit for 'a' : neither 
local nor a parameter}}
+void test_globals() {
+  a[7] = 4;  // expected-note{{used in buffer access here}}
+}
+
+void test_decomp_decl() {
+  int a[2] = {1, 2};
+  auto [x, y] = a;
+  x = 9;
+}



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] 2afcda6 - [-Wunsafe-buffer-usage] Fix assertion failure in case of BindingDecl

2023-08-17 Thread Rashmi Mudduluru via cfe-commits

Author: Rashmi Mudduluru
Date: 2023-08-17T16:18:38-07:00
New Revision: 2afcda693acba8d63887a6bb0605038b1563c64c

URL: 
https://github.com/llvm/llvm-project/commit/2afcda693acba8d63887a6bb0605038b1563c64c
DIFF: 
https://github.com/llvm/llvm-project/commit/2afcda693acba8d63887a6bb0605038b1563c64c.diff

LOG: [-Wunsafe-buffer-usage] Fix assertion failure in case of BindingDecl

Differential Revision: https://reviews.llvm.org/D158112#inline-1530312

Added: 


Modified: 
clang/lib/Analysis/UnsafeBufferUsage.cpp
clang/test/SemaCXX/warn-unsafe-buffer-usage-debug.cpp

Removed: 




diff  --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp 
b/clang/lib/Analysis/UnsafeBufferUsage.cpp
index 41820c80da6b4b..2c36d78e60c89b 100644
--- a/clang/lib/Analysis/UnsafeBufferUsage.cpp
+++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp
@@ -380,6 +380,10 @@ class FixableGadget : public Gadget {
   }
 };
 
+static auto toSupportedVariable() {
+  return to(varDecl());
+}
+
 using FixableGadgetList = std::vector>;
 using WarningGadgetList = std::vector>;
 
@@ -566,7 +570,8 @@ class PointerInitGadget : public FixableGadget {
   static Matcher matcher() {
 auto PtrInitStmt = declStmt(hasSingleDecl(varDecl(
  hasInitializer(ignoringImpCasts(declRefExpr(
-  hasPointerType()).
+  hasPointerType(),
+toSupportedVariable()).
   bind(PointerInitRHSTag.
   bind(PointerInitLHSTag)));
 
@@ -616,10 +621,10 @@ class PointerAssignmentGadget : public FixableGadget {
   static Matcher matcher() {
 auto PtrAssignExpr = binaryOperator(allOf(hasOperatorName("="),
   hasRHS(ignoringParenImpCasts(declRefExpr(hasPointerType(),
-   to(varDecl())).
+   toSupportedVariable()).
bind(PointerAssignRHSTag))),
hasLHS(declRefExpr(hasPointerType(),
-  to(varDecl())).
+  toSupportedVariable()).
   bind(PointerAssignLHSTag;
 
 return stmt(isInUnspecifiedUntypedContext(PtrAssignExpr));
@@ -691,7 +696,8 @@ class ULCArraySubscriptGadget : public FixableGadget {
   static Matcher matcher() {
 auto ArrayOrPtr = anyOf(hasPointerType(), hasArrayType());
 auto BaseIsArrayOrPtrDRE =
-hasBase(ignoringParenImpCasts(declRefExpr(ArrayOrPtr)));
+hasBase(ignoringParenImpCasts(declRefExpr(ArrayOrPtr,
+  toSupportedVariable(;
 auto Target =
 arraySubscriptExpr(BaseIsArrayOrPtrDRE).bind(ULCArraySubscriptTag);
 
@@ -733,7 +739,8 @@ class UPCStandalonePointerGadget : public FixableGadget {
   static Matcher matcher() {
 auto ArrayOrPtr = anyOf(hasPointerType(), hasArrayType());
 auto target = expr(
-ignoringParenImpCasts(declRefExpr(allOf(ArrayOrPtr, 
to(varDecl(.bind(DeclRefExprTag)));
+ignoringParenImpCasts(declRefExpr(allOf(ArrayOrPtr, 
+  toSupportedVariable())).bind(DeclRefExprTag)));
 return stmt(isInUnspecifiedPointerContext(target));
   }
 
@@ -769,7 +776,7 @@ class PointerDereferenceGadget : public FixableGadget {
 unaryOperator(
 hasOperatorName("*"),
 has(expr(ignoringParenImpCasts(
-declRefExpr(to(varDecl())).bind(BaseDeclRefExprTag)
+declRefExpr(toSupportedVariable()).bind(BaseDeclRefExprTag)
 .bind(OperatorTag);
 
 return expr(isInUnspecifiedLvalueContext(Target));
@@ -809,7 +816,8 @@ class UPCAddressofArraySubscriptGadget : public 
FixableGadget {
 return expr(isInUnspecifiedPointerContext(expr(ignoringImpCasts(
 unaryOperator(hasOperatorName("&"),
   hasUnaryOperand(arraySubscriptExpr(
-  hasBase(ignoringParenImpCasts(declRefExpr())
+  hasBase(ignoringParenImpCasts(declRefExpr(
+  toSupportedVariable()))
 .bind(UPCAddressofArraySubscriptTag);
   }
 
@@ -961,7 +969,8 @@ class UPCPreIncrementGadget : public FixableGadget {
 // things right.
 return stmt(isInUnspecifiedPointerContext(expr(ignoringImpCasts(

unaryOperator(isPreInc(),
-   
  hasUnaryOperand(declRefExpr())
+   
  hasUnaryOperand(d

[clang] db3dced - [-Wunsafe-buffer-usage] Handle pointer initializations for grouping related variables

2023-06-21 Thread Rashmi Mudduluru via cfe-commits

Author: Rashmi Mudduluru
Date: 2023-06-21T15:54:09-07:00
New Revision: db3dcedb9cedcec4a9570fda7406490c642df8ae

URL: 
https://github.com/llvm/llvm-project/commit/db3dcedb9cedcec4a9570fda7406490c642df8ae
DIFF: 
https://github.com/llvm/llvm-project/commit/db3dcedb9cedcec4a9570fda7406490c642df8ae.diff

LOG: [-Wunsafe-buffer-usage] Handle pointer initializations for grouping 
related variables

Differential Revision: https://reviews.llvm.org/D150489

Added: 
clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-ptr-init-fixits.cpp
clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-ptr-init.cpp

Modified: 
clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
clang/lib/Analysis/UnsafeBufferUsage.cpp
clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-uuc-fixits.cpp
clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-uuc.cpp
clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-warnings.cpp

Removed: 




diff  --git 
a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def 
b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
index 57d9dcc5bdcb7..ff687a0d178bd 100644
--- a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
+++ b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
@@ -37,6 +37,7 @@ FIXABLE_GADGET(UPCAddressofArraySubscript) // '&DRE[any]' in 
an Unspecified Poin
 FIXABLE_GADGET(UPCStandalonePointer)
 FIXABLE_GADGET(UPCPreIncrement)// '++Ptr' in an Unspecified 
Pointer Context
 FIXABLE_GADGET(PointerAssignment)
+FIXABLE_GADGET(PointerInit)
 
 #undef FIXABLE_GADGET
 #undef WARNING_GADGET

diff  --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp 
b/clang/lib/Analysis/UnsafeBufferUsage.cpp
index 49229a6b56c1c..aa29fb45726a8 100644
--- a/clang/lib/Analysis/UnsafeBufferUsage.cpp
+++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp
@@ -533,23 +533,66 @@ class PointerArithmeticGadget : public WarningGadget {
   // FIXME: this gadge will need a fix-it
 };
 
+/// A pointer initialization expression of the form:
+///  \code
+///  int *p = q;
+///  \endcode
+class PointerInitGadget : public FixableGadget {
+private:
+  static constexpr const char *const PointerInitLHSTag = "ptrInitLHS";
+  static constexpr const char *const PointerInitRHSTag = "ptrInitRHS";
+  const VarDecl * PtrInitLHS; // the LHS pointer expression in `PI`
+  const DeclRefExpr * PtrInitRHS; // the RHS pointer expression in `PI`
+
+public:
+  PointerInitGadget(const MatchFinder::MatchResult &Result)
+  : FixableGadget(Kind::PointerInit),
+PtrInitLHS(Result.Nodes.getNodeAs(PointerInitLHSTag)),
+PtrInitRHS(Result.Nodes.getNodeAs(PointerInitRHSTag)) {}
+
+  static bool classof(const Gadget *G) {
+return G->getKind() == Kind::PointerInit;
+  }
+
+  static Matcher matcher() {
+auto PtrInitStmt = declStmt(hasSingleDecl(varDecl(
+ hasInitializer(ignoringImpCasts(declRefExpr(
+  hasPointerType()).
+  bind(PointerInitRHSTag.
+  bind(PointerInitLHSTag)));
+
+return stmt(PtrInitStmt);
+  }
+
+  virtual std::optional getFixits(const Strategy &S) const override;
+
+  virtual const Stmt *getBaseStmt() const override { return nullptr; }
+
+  virtual DeclUseList getClaimedVarUseSites() const override {
+return DeclUseList{PtrInitRHS};
+  }
+
+  virtual std::optional>
+  getStrategyImplications() const override {
+  return std::make_pair(PtrInitLHS,
+cast(PtrInitRHS->getDecl()));
+  }
+};
+
 /// A pointer assignment expression of the form:
 ///  \code
 ///  p = q;
 ///  \endcode
 class PointerAssignmentGadget : public FixableGadget {
 private:
-  static constexpr const char *const PointerAssignmentTag = "ptrAssign";
   static constexpr const char *const PointerAssignLHSTag = "ptrLHS";
   static constexpr const char *const PointerAssignRHSTag = "ptrRHS";
-  const BinaryOperator *PA;// pointer arithmetic expression
   const DeclRefExpr * PtrLHS; // the LHS pointer expression in `PA`
   const DeclRefExpr * PtrRHS; // the RHS pointer expression in `PA`
 
 public:
   PointerAssignmentGadget(const MatchFinder::MatchResult &Result)
   : FixableGadget(Kind::PointerAssignment),
-PA(Result.Nodes.getNodeAs(PointerAssignmentTag)),
 PtrLHS(Result.Nodes.getNodeAs(PointerAssignLHSTag)),
 PtrRHS(Result.Nodes.getNodeAs(PointerAssignRHSTag)) {}
 
@@ -566,13 +609,12 @@ class PointerAssignmentGadget : public FixableGadget {
   to(varDecl())).
   bind(PointerAssignLHSTag;
 
-//FIXME: Handle declarations at assignments
 return stmt(isInUnspecifiedUntypedContext(PtrAssignExpr));
   }
   
   v

[clang] ee6b08e - [-Wunsafe-buffer-usage] Group variables associated by pointer assignments

2023-05-24 Thread Rashmi Mudduluru via cfe-commits

Author: Rashmi Mudduluru
Date: 2023-05-24T16:20:55-07:00
New Revision: ee6b08e99375fc48d1e5848704a66c2e8e57eb3b

URL: 
https://github.com/llvm/llvm-project/commit/ee6b08e99375fc48d1e5848704a66c2e8e57eb3b
DIFF: 
https://github.com/llvm/llvm-project/commit/ee6b08e99375fc48d1e5848704a66c2e8e57eb3b.diff

LOG: [-Wunsafe-buffer-usage] Group variables associated by pointer assignments

Differential Revision: https://reviews.llvm.org/D145739

Added: 
clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-fixits-test.cpp
clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-uuc-fixits.cpp
clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-uuc.cpp
clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-warnings.cpp

Modified: 
clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h
clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/lib/Analysis/UnsafeBufferUsage.cpp
clang/lib/Sema/AnalysisBasedWarnings.cpp

Removed: 




diff  --git a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h 
b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h
index 10635e8f3a29f..617bc7c77c565 100644
--- a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h
+++ b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h
@@ -19,6 +19,8 @@
 
 namespace clang {
 
+using DefMapTy = llvm::DenseMap>;
+
 /// The interface that lets the caller handle unsafe buffer usage analysis
 /// results by overriding this class's handle... methods.
 class UnsafeBufferUsageHandler {
@@ -34,9 +36,12 @@ class UnsafeBufferUsageHandler {
   virtual void handleUnsafeOperation(const Stmt *Operation,
  bool IsRelatedToDecl) = 0;
 
-  /// Invoked when a fix is suggested against a variable.
-  virtual void handleFixableVariable(const VarDecl *Variable,
- FixItList &&List) = 0;
+  /// Invoked when a fix is suggested against a variable. This function groups
+  /// all variables that must be fixed together (i.e their types must be 
changed to the
+  /// same target type to prevent type mismatches) into a single fixit.
+  virtual void handleUnsafeVariableGroup(const VarDecl *Variable,
+ const DefMapTy &VarGrpMap,
+ FixItList &&Fixes) = 0;
 
   /// Returns a reference to the `Preprocessor`:
   virtual bool isSafeBufferOptOut(const SourceLocation &Loc) const = 0;

diff  --git 
a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def 
b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
index a112b6d105025..57d9dcc5bdcb7 100644
--- a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
+++ b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
@@ -36,6 +36,7 @@ FIXABLE_GADGET(PointerDereference)
 FIXABLE_GADGET(UPCAddressofArraySubscript) // '&DRE[any]' in an Unspecified 
Pointer Context
 FIXABLE_GADGET(UPCStandalonePointer)
 FIXABLE_GADGET(UPCPreIncrement)// '++Ptr' in an Unspecified 
Pointer Context
+FIXABLE_GADGET(PointerAssignment)
 
 #undef FIXABLE_GADGET
 #undef WARNING_GADGET

diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index f203ac6c2a84e..a777d43f1468f 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -11822,8 +11822,8 @@ def warn_unsafe_buffer_operation : Warning<
   InGroup, DefaultIgnore;
 def note_unsafe_buffer_operation : Note<
   "used%select{| in pointer arithmetic| in buffer access}0 here">;
-def note_unsafe_buffer_variable_fixit : Note<
-  "change type of '%0' to '%select{std::span|std::array|std::span::iterator}1' 
to preserve bounds information">;
+def note_unsafe_buffer_variable_fixit_group : Note<
+  "change type of %0 to '%select{std::span|std::array|std::span::iterator}1' 
to preserve bounds information%select{|, and change %2 to 
'%select{std::span|std::array|std::span::iterator}1' to propagate bounds 
information between them}3">;
 def note_safe_buffer_usage_suggestions_disabled : Note<
   "pass -fsafe-buffer-usage-suggestions to receive code hardening 
suggestions">;
 def err_loongarch_builtin_requires_la32 : Error<

diff  --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp 
b/clang/lib/Analysis/UnsafeBufferUsage.cpp
index 87e3ec90dbf2f..c9cc4ccbfb5d5 100644
--- a/clang/lib/Analysis/UnsafeBufferUsage.cpp
+++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp
@@ -16,6 +16,7 @@
 #include 
 #include 
 #include 
+#include 
 
 using namespace llvm;
 using namespace clang;
@@ -256,6 +257,29 @@ isInUnspecifiedPointerContext(internal::Matcher 
InnerMatcher) {
   // FIXME: any more cases? (UPC excludes the RHS of an assignment.  For now we
   // don't have to check that.)
 }
+
+// Returns a matcher 

[clang] 171dfc5 - [-Wunsafe-buffer-usage] Group variables associated by pointer assignments

2023-05-25 Thread Rashmi Mudduluru via cfe-commits

Author: Rashmi Mudduluru
Date: 2023-05-25T11:31:27-07:00
New Revision: 171dfc5462a23b7e8ace31f4d9206b972b38ffbc

URL: 
https://github.com/llvm/llvm-project/commit/171dfc5462a23b7e8ace31f4d9206b972b38ffbc
DIFF: 
https://github.com/llvm/llvm-project/commit/171dfc5462a23b7e8ace31f4d9206b972b38ffbc.diff

LOG: [-Wunsafe-buffer-usage] Group variables associated by pointer assignments

Differential Revision: https://reviews.llvm.org/D145739

Added: 
clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-fixits-test.cpp
clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-uuc-fixits.cpp
clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-uuc.cpp
clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-warnings.cpp

Modified: 
clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h
clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/lib/Analysis/UnsafeBufferUsage.cpp
clang/lib/Sema/AnalysisBasedWarnings.cpp

Removed: 




diff  --git a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h 
b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h
index 10635e8f3a29f..617bc7c77c565 100644
--- a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h
+++ b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h
@@ -19,6 +19,8 @@
 
 namespace clang {
 
+using DefMapTy = llvm::DenseMap>;
+
 /// The interface that lets the caller handle unsafe buffer usage analysis
 /// results by overriding this class's handle... methods.
 class UnsafeBufferUsageHandler {
@@ -34,9 +36,12 @@ class UnsafeBufferUsageHandler {
   virtual void handleUnsafeOperation(const Stmt *Operation,
  bool IsRelatedToDecl) = 0;
 
-  /// Invoked when a fix is suggested against a variable.
-  virtual void handleFixableVariable(const VarDecl *Variable,
- FixItList &&List) = 0;
+  /// Invoked when a fix is suggested against a variable. This function groups
+  /// all variables that must be fixed together (i.e their types must be 
changed to the
+  /// same target type to prevent type mismatches) into a single fixit.
+  virtual void handleUnsafeVariableGroup(const VarDecl *Variable,
+ const DefMapTy &VarGrpMap,
+ FixItList &&Fixes) = 0;
 
   /// Returns a reference to the `Preprocessor`:
   virtual bool isSafeBufferOptOut(const SourceLocation &Loc) const = 0;

diff  --git 
a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def 
b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
index a112b6d105025..57d9dcc5bdcb7 100644
--- a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
+++ b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
@@ -36,6 +36,7 @@ FIXABLE_GADGET(PointerDereference)
 FIXABLE_GADGET(UPCAddressofArraySubscript) // '&DRE[any]' in an Unspecified 
Pointer Context
 FIXABLE_GADGET(UPCStandalonePointer)
 FIXABLE_GADGET(UPCPreIncrement)// '++Ptr' in an Unspecified 
Pointer Context
+FIXABLE_GADGET(PointerAssignment)
 
 #undef FIXABLE_GADGET
 #undef WARNING_GADGET

diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index f203ac6c2a84e..a777d43f1468f 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -11822,8 +11822,8 @@ def warn_unsafe_buffer_operation : Warning<
   InGroup, DefaultIgnore;
 def note_unsafe_buffer_operation : Note<
   "used%select{| in pointer arithmetic| in buffer access}0 here">;
-def note_unsafe_buffer_variable_fixit : Note<
-  "change type of '%0' to '%select{std::span|std::array|std::span::iterator}1' 
to preserve bounds information">;
+def note_unsafe_buffer_variable_fixit_group : Note<
+  "change type of %0 to '%select{std::span|std::array|std::span::iterator}1' 
to preserve bounds information%select{|, and change %2 to 
'%select{std::span|std::array|std::span::iterator}1' to propagate bounds 
information between them}3">;
 def note_safe_buffer_usage_suggestions_disabled : Note<
   "pass -fsafe-buffer-usage-suggestions to receive code hardening 
suggestions">;
 def err_loongarch_builtin_requires_la32 : Error<

diff  --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp 
b/clang/lib/Analysis/UnsafeBufferUsage.cpp
index 87e3ec90dbf2f..c9cc4ccbfb5d5 100644
--- a/clang/lib/Analysis/UnsafeBufferUsage.cpp
+++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp
@@ -16,6 +16,7 @@
 #include 
 #include 
 #include 
+#include 
 
 using namespace llvm;
 using namespace clang;
@@ -256,6 +257,29 @@ isInUnspecifiedPointerContext(internal::Matcher 
InnerMatcher) {
   // FIXME: any more cases? (UPC excludes the RHS of an assignment.  For now we
   // don't have to check that.)
 }
+
+// Returns a matcher 

[clang] d1ae844 - [-Wunsafe-buffer-usage] Do not emit fixits for C++ interfaces with C linkage

2023-06-16 Thread Rashmi Mudduluru via cfe-commits

Author: Rashmi Mudduluru
Date: 2023-06-16T13:28:34-07:00
New Revision: d1ae844dc2cc58bc762135d9500464c61d50f4f9

URL: 
https://github.com/llvm/llvm-project/commit/d1ae844dc2cc58bc762135d9500464c61d50f4f9
DIFF: 
https://github.com/llvm/llvm-project/commit/d1ae844dc2cc58bc762135d9500464c61d50f4f9.diff

LOG: [-Wunsafe-buffer-usage] Do not emit fixits for C++ interfaces with C 
linkage

Differential Revision: https://reviews.llvm.org/D153064

Added: 
clang/test/SemaCXX/warn-unsafe-buffer-usage-c-linkage.cpp

Modified: 
clang/lib/Analysis/UnsafeBufferUsage.cpp

Removed: 




diff  --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp 
b/clang/lib/Analysis/UnsafeBufferUsage.cpp
index 999b94a070368..49229a6b56c1c 100644
--- a/clang/lib/Analysis/UnsafeBufferUsage.cpp
+++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp
@@ -2139,6 +2139,18 @@ void clang::checkUnsafeBufferUsage(const Decl *D,
UnsafeBufferUsageHandler &Handler,
bool EmitSuggestions) {
   assert(D && D->getBody());
+  
+  // Do not emit fixit suggestions for functions declared in an
+  // extern "C" block.
+  if (const auto *FD = dyn_cast(D)) {
+  for (FunctionDecl *FReDecl : FD->redecls()) {
+  if (FReDecl->isExternC()) {
+EmitSuggestions = false;
+break;
+  }
+}
+  }
+  
   WarningGadgetSets UnsafeOps;
   FixableGadgetSets FixablesForAllVars;
 

diff  --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-c-linkage.cpp 
b/clang/test/SemaCXX/warn-unsafe-buffer-usage-c-linkage.cpp
new file mode 100644
index 0..6c134098f87df
--- /dev/null
+++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-c-linkage.cpp
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage 
-fsafe-buffer-usage-suggestions -verify %s
+
+extern "C" {
+void foo(int *ptr) {
+  ptr[5] = 10;  // expected-warning{{unsafe buffer access}}
+}
+
+void bar(int *ptr);
+
+struct c_struct {
+  char *name;
+};
+}
+
+void bar(int *ptr) {
+  ptr[5] = 10;  // expected-warning{{unsafe buffer access}}
+}
+
+void call_foo(int *p) {
+  foo(p);
+  struct c_struct str;
+  str.name[7] = 9;  // expected-warning{{unsafe buffer access}}
+  bar(p);
+}



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [alpha.webkit.UncountedLocalVarsChecker] Recursive functions are erroneously treated as non-trivial (PR #110973)

2024-10-17 Thread Rashmi Mudduluru via cfe-commits


@@ -289,3 +289,32 @@ void foo() {
 }
 
 } // namespace local_assignment_to_global
+
+namespace local_var_in_recursive_function {
+
+struct TreeNode {
+  Ref create() { return Ref(*new TreeNode); }
+
+  void ref() const { ++refCount; }
+  void deref() const {
+if (!--refCount)
+  delete this;
+  }
+
+  int recursiveCost();
+
+  int cost { 0 };
+  mutable unsigned refCount { 0 };
+  TreeNode* nextSibling { nullptr };
+  TreeNode* firstChild { nullptr };
+};
+
+int TreeNode::recursiveCost() {
+  // no warnings
+  unsigned totalCost = cost;
+  for (TreeNode* node = firstChild; node; node = node->nextSibling)
+totalCost += recursiveCost();
+  return totalCost;
+}
+
+} // namespace local_var_in_recursive_function

t-rasmud wrote:

Can we also have a test for a recursive function that isn't trivial? say, a 
recursive function calling a non-trivial method?

https://github.com/llvm/llvm-project/pull/110973
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [alpha.webkit.UncountedLocalVarsChecker] Recursive functions are erroneously treated as non-trivial (PR #110973)

2024-10-17 Thread Rashmi Mudduluru via cfe-commits

https://github.com/t-rasmud closed 
https://github.com/llvm/llvm-project/pull/110973
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [alpha.webkit.UncountedLocalVarsChecker] Recursive functions are erroneously treated as non-trivial (PR #110973)

2024-10-17 Thread Rashmi Mudduluru via cfe-commits

t-rasmud wrote:

LGTM!

https://github.com/llvm/llvm-project/pull/110973
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [alpha.webkit.UncountedLocalVarsChecker] Recursive functions are erroneously treated as non-trivial (PR #110973)

2024-10-17 Thread Rashmi Mudduluru via cfe-commits

https://github.com/t-rasmud reopened 
https://github.com/llvm/llvm-project/pull/110973
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [alpha.webkit.UncountedLocalVarsChecker] Recursive functions are erroneously treated as non-trivial (PR #110973)

2024-10-17 Thread Rashmi Mudduluru via cfe-commits

https://github.com/t-rasmud approved this pull request.


https://github.com/llvm/llvm-project/pull/110973
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WebKit Checkers] Make TrivialFunctionAnalysis recognize std::array::operator[] as trivial (PR #113377)

2024-10-22 Thread Rashmi Mudduluru via cfe-commits

https://github.com/t-rasmud created 
https://github.com/llvm/llvm-project/pull/113377

TFA wasn't recognizing `__libcpp_verbose_abort` as trivial causing 
`std::array::operator[]` also not being recongnized as trivial.

>From 9e21b0f2f0968a5f8810c797913318884dcc8c7b Mon Sep 17 00:00:00 2001
From: Rashmi Mudduluru 
Date: Tue, 22 Oct 2024 13:16:30 -0700
Subject: [PATCH] [WebKit Checkers] Make TrivialFunctionAnalysis recognize
 std::array::operator[] as trivial

TFA wasn't recognizing `__libcpp_verbose_abort` as trivial causing 
`std::array::operator[]` also not being recongnized as trivial.
---
 .../Checkers/WebKit/PtrTypesSemantics.cpp |  3 +-
 .../WebKit/uncounted-obj-arg-std-array.cpp| 33 +++
 2 files changed, 35 insertions(+), 1 deletion(-)
 create mode 100644 
clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg-std-array.cpp

diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
index e043806eadd6ac..71440e6d08a1c9 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
@@ -414,7 +414,8 @@ class TrivialFunctionAnalysisVisitor
 Name == "isMainThreadOrGCThread" || Name == "isMainRunLoop" ||
 Name == "isWebThread" || Name == "isUIThread" ||
 Name == "mayBeGCThread" || Name == "compilerFenceForCrash" ||
-Name == "bitwise_cast" || Name.find("__builtin") == 0)
+Name == "bitwise_cast" || Name.find("__builtin") == 0 ||
+Name == "__libcpp_verbose_abort")
   return true;
 
 return IsFunctionTrivial(Callee);
diff --git 
a/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg-std-array.cpp 
b/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg-std-array.cpp
new file mode 100644
index 00..43c76c0b0793a8
--- /dev/null
+++ b/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg-std-array.cpp
@@ -0,0 +1,33 @@
+// RUN: %clang_analyze_cc1 
-analyzer-checker=alpha.webkit.UncountedCallArgsChecker -verify %s
+// expected-no-diagnostics
+
+#include "mock-types.h"
+
+using size_t = __typeof(sizeof(int));
+namespace std{
+template 
+class array {
+  T elements[N];
+  
+  public:
+  T& operator[](unsigned i) { return elements[i]; }
+  constexpr const T* data() const noexcept {
+ return elements;
+  }
+
+};
+}
+
+class ArrayClass {
+public:
+typedef std::array, 4> Matrix;
+double e() { return matrix[3][0]; }
+Matrix matrix;
+};
+
+class AnotherClass {
+Ref matrix;
+void test() {
+  double val[] = { matrix->e(), matrix->e() };
+}
+};

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [alpha.webkit.UncountedLocalVarsChecker] Warn the use of a raw pointer/reference when the guardian variable gets mutated. (PR #113859)

2024-10-28 Thread Rashmi Mudduluru via cfe-commits


@@ -48,6 +48,64 @@ bool isRefcountedStringsHack(const VarDecl *V) {
   return false;
 }
 
+struct GuardianVisitor : public RecursiveASTVisitor {
+  using Base = RecursiveASTVisitor;
+
+  const VarDecl *Guardian{nullptr};
+
+public:
+  explicit GuardianVisitor(const VarDecl *Guardian) : Guardian(Guardian) {
+assert(Guardian);
+  }
+
+  bool VisitBinaryOperator(const BinaryOperator *BO) {
+if (BO->isAssignmentOp()) {
+  if (auto *VarRef = dyn_cast(BO->getLHS())) {
+if (VarRef->getDecl() == Guardian)
+  return false;
+  }
+}
+return true;
+  }
+
+  bool VisitCXXConstructExpr(const CXXConstructExpr *CE) {
+if (auto *Ctor = CE->getConstructor()) {
+  if (Ctor->isMoveConstructor() && CE->getNumArgs() == 1) {
+auto *Arg = CE->getArg(0)->IgnoreParenCasts();
+if (auto *VarRef = dyn_cast(Arg)) {
+  if (VarRef->getDecl() == Guardian)
+return false;
+}
+  }
+}
+return true;
+  }
+
+  bool VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE) {
+auto MethodName = safeGetName(MCE->getMethodDecl());
+if (MethodName == "swap" || MethodName == "leakRef" ||
+MethodName == "releaseNonNull") {
+  auto *ThisArg = MCE->getImplicitObjectArgument()->IgnoreParenCasts();
+  if (auto *VarRef = dyn_cast(ThisArg)) {
+if (VarRef->getDecl() == Guardian)
+  return false;
+  }
+}
+return true;
+  }
+
+  bool VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *OCE) {
+if (OCE->isAssignmentOp() && OCE->getNumArgs() == 2) {

t-rasmud wrote:

Is the check `OCE->getNumArgs() == 2` necessary here? What are the cases in 
which `CXXOperatorCallExpr` is an assignment op but has a different number of 
args?

https://github.com/llvm/llvm-project/pull/113859
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [alpha.webkit.UncountedLocalVarsChecker] Warn the use of a raw pointer/reference when the guardian variable gets mutated. (PR #113859)

2024-10-28 Thread Rashmi Mudduluru via cfe-commits


@@ -83,6 +83,65 @@ void foo7(RefCountable* obj) {
   bar.obj->method();
 }
 
+void foo8(RefCountable* obj) {
+  RefPtr foo;
+  {
+RefCountable *bar = foo.get();
+// expected-warning@-1{{Local variable 'bar' is uncounted and unsafe 
[alpha.webkit.UncountedLocalVarsChecker]}}
+foo = nullptr;
+bar->method();
+  }
+  RefPtr baz;
+  {
+RefCountable *bar = baz.get();
+// expected-warning@-1{{Local variable 'bar' is uncounted and unsafe 
[alpha.webkit.UncountedLocalVarsChecker]}}
+baz = obj;
+bar->method();
+  }
+  foo = nullptr;
+  {
+RefCountable *bar = foo.get();
+// No warning. It's okay to mutate RefPtr in an outer scope.
+bar->method();
+  }
+  foo = obj;
+  {
+RefCountable *bar = foo.get();
+// expected-warning@-1{{Local variable 'bar' is uncounted and unsafe 
[alpha.webkit.UncountedLocalVarsChecker]}}
+foo.releaseNonNull();
+bar->method();
+  }
+}
+
+void foo9(RefCountable& o) {
+  Ref guardian(o);
+  {
+RefCountable &bar = guardian.get();
+// expected-warning@-1{{Local variable 'bar' is uncounted and unsafe 
[alpha.webkit.UncountedLocalVarsChecker]}}
+guardian = o; // We don't detect that we're setting it to the same value.
+bar.method();
+  }
+  {
+RefCountable *bar = guardian.ptr();
+// expected-warning@-1{{Local variable 'bar' is uncounted and unsafe 
[alpha.webkit.UncountedLocalVarsChecker]}}
+Ref other(*bar); // We don't detect other has the same value 
as guardian.
+guardian.swap(other);
+bar->method();
+  }
+  {
+RefCountable *bar = guardian.ptr();
+// expected-warning@-1{{Local variable 'bar' is uncounted and unsafe 
[alpha.webkit.UncountedLocalVarsChecker]}}
+Ref other(static_cast&&>(guardian));
+bar->method();
+  }
+  {
+RefCountable *bar = guardian.ptr();
+// expected-warning@-1{{Local variable 'bar' is uncounted and unsafe 
[alpha.webkit.UncountedLocalVarsChecker]}}
+guardian.leakRef();
+bar->method();
+  }
+}

t-rasmud wrote:

Adding a test case would be great!

https://github.com/llvm/llvm-project/pull/113859
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [alpha.webkit.UncountedLocalVarsChecker] Warn the use of a raw pointer/reference when the guardian variable gets mutated. (PR #113859)

2024-10-28 Thread Rashmi Mudduluru via cfe-commits


@@ -83,6 +83,65 @@ void foo7(RefCountable* obj) {
   bar.obj->method();
 }
 
+void foo8(RefCountable* obj) {
+  RefPtr foo;
+  {
+RefCountable *bar = foo.get();
+// expected-warning@-1{{Local variable 'bar' is uncounted and unsafe 
[alpha.webkit.UncountedLocalVarsChecker]}}
+foo = nullptr;
+bar->method();
+  }
+  RefPtr baz;
+  {
+RefCountable *bar = baz.get();
+// expected-warning@-1{{Local variable 'bar' is uncounted and unsafe 
[alpha.webkit.UncountedLocalVarsChecker]}}
+baz = obj;
+bar->method();
+  }
+  foo = nullptr;
+  {
+RefCountable *bar = foo.get();
+// No warning. It's okay to mutate RefPtr in an outer scope.
+bar->method();
+  }
+  foo = obj;
+  {
+RefCountable *bar = foo.get();
+// expected-warning@-1{{Local variable 'bar' is uncounted and unsafe 
[alpha.webkit.UncountedLocalVarsChecker]}}
+foo.releaseNonNull();
+bar->method();
+  }
+}
+
+void foo9(RefCountable& o) {
+  Ref guardian(o);
+  {
+RefCountable &bar = guardian.get();
+// expected-warning@-1{{Local variable 'bar' is uncounted and unsafe 
[alpha.webkit.UncountedLocalVarsChecker]}}
+guardian = o; // We don't detect that we're setting it to the same value.
+bar.method();
+  }
+  {
+RefCountable *bar = guardian.ptr();
+// expected-warning@-1{{Local variable 'bar' is uncounted and unsafe 
[alpha.webkit.UncountedLocalVarsChecker]}}
+Ref other(*bar); // We don't detect other has the same value 
as guardian.
+guardian.swap(other);
+bar->method();
+  }
+  {
+RefCountable *bar = guardian.ptr();
+// expected-warning@-1{{Local variable 'bar' is uncounted and unsafe 
[alpha.webkit.UncountedLocalVarsChecker]}}
+Ref other(static_cast&&>(guardian));
+bar->method();
+  }
+  {
+RefCountable *bar = guardian.ptr();
+// expected-warning@-1{{Local variable 'bar' is uncounted and unsafe 
[alpha.webkit.UncountedLocalVarsChecker]}}
+guardian.leakRef();
+bar->method();
+  }
+}

t-rasmud wrote:

What is the expected behavior for conditional assignments?
For example:
```
{
RefCountable *bar = cond? foo.get() : nullptr;
 }
```
Should the checker produce a warning here?

https://github.com/llvm/llvm-project/pull/113859
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [alpha.webkit.UncountedLocalVarsChecker] Warn the use of a raw pointer/reference when the guardian variable gets mutated. (PR #113859)

2024-10-28 Thread Rashmi Mudduluru via cfe-commits


@@ -83,6 +83,77 @@ void foo7(RefCountable* obj) {
   bar.obj->method();
 }
 
+void foo8(RefCountable* obj) {
+  RefPtr foo;
+  {
+RefCountable *bar = foo.get();
+// expected-warning@-1{{Local variable 'bar' is uncounted and unsafe 
[alpha.webkit.UncountedLocalVarsChecker]}}
+foo = nullptr;
+bar->method();
+  }
+  RefPtr baz;
+  {
+RefCountable *bar = baz.get();
+// expected-warning@-1{{Local variable 'bar' is uncounted and unsafe 
[alpha.webkit.UncountedLocalVarsChecker]}}
+baz = obj;
+bar->method();
+  }
+  foo = nullptr;
+  {
+RefCountable *bar = foo.get();
+// No warning. It's okay to mutate RefPtr in an outer scope.
+bar->method();
+  }
+  foo = obj;
+  {
+RefCountable *bar = foo.get();
+// expected-warning@-1{{Local variable 'bar' is uncounted and unsafe 
[alpha.webkit.UncountedLocalVarsChecker]}}
+foo.releaseNonNull();
+bar->method();
+  }
+  {
+RefCountable *bar = foo.get();
+// expected-warning@-1{{Local variable 'bar' is uncounted and unsafe 
[alpha.webkit.UncountedLocalVarsChecker]}}
+foo = obj ? obj : nullptr;
+bar->method();
+  }
+}
+
+void foo9(RefCountable& o) {
+  Ref guardian(o);
+  {
+RefCountable &bar = guardian.get();
+// expected-warning@-1{{Local variable 'bar' is uncounted and unsafe 
[alpha.webkit.UncountedLocalVarsChecker]}}
+guardian = o; // We don't detect that we're setting it to the same value.
+bar.method();
+  }
+  {
+RefCountable *bar = guardian.ptr();
+// expected-warning@-1{{Local variable 'bar' is uncounted and unsafe 
[alpha.webkit.UncountedLocalVarsChecker]}}
+Ref other(*bar); // We don't detect other has the same value 
as guardian.
+guardian.swap(other);
+bar->method();
+  }
+  {
+RefCountable *bar = guardian.ptr();
+// expected-warning@-1{{Local variable 'bar' is uncounted and unsafe 
[alpha.webkit.UncountedLocalVarsChecker]}}
+Ref other(static_cast&&>(guardian));
+bar->method();
+  }
+  {
+RefCountable *bar = guardian.ptr();
+// expected-warning@-1{{Local variable 'bar' is uncounted and unsafe 
[alpha.webkit.UncountedLocalVarsChecker]}}
+guardian.leakRef();
+bar->method();
+  }
+  {
+RefCountable *bar = guardian.ptr();
+// expected-warning@-1{{Local variable 'bar' is uncounted and unsafe 
[alpha.webkit.UncountedLocalVarsChecker]}}
+guardian = o.trivial() ? o : *bar;

t-rasmud wrote:

Since `guardian` is mutated here, should we also have an `// expected-warning` 
on this line too?

https://github.com/llvm/llvm-project/pull/113859
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WebKit Checkers] Allow a guardian CheckedPtr/CheckedRef (PR #110222)

2024-10-24 Thread Rashmi Mudduluru via cfe-commits


@@ -56,7 +60,8 @@ bool tryToFindPtrOrigin(
   if (StopAtFirstRefCountedObj) {
 if (auto *ConversionFunc =
 dyn_cast_or_null(cast->getConversionFunction())) 
{
-  if (isCtorOfRefCounted(ConversionFunc))
+  if (isCtorOfRefCounted(ConversionFunc) ||
+  isCtorOfCheckedPtr(ConversionFunc))

t-rasmud wrote:

Could this also be refactored into a function (say `isSafeCtor`) like 
`isSafePtr`?

https://github.com/llvm/llvm-project/pull/110222
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WebKit Checkers] Allow a guardian CheckedPtr/CheckedRef (PR #110222)

2024-10-24 Thread Rashmi Mudduluru via cfe-commits


@@ -63,18 +63,29 @@ std::optional isUncounted(const clang::CXXRecordDecl* 
Class);
 /// class, false if not, std::nullopt if inconclusive.
 std::optional isUncountedPtr(const clang::QualType T);
 
-/// \returns true if Name is a RefPtr, Ref, or its variant, false if not.
-bool isRefType(const std::string &Name);
+/// \returns true if \p T is a RefPtr, Ref, CheckedPtr, CheckedRef, or its
+/// variant, false if not.
+bool isSafePtrType(const clang::QualType T);
 
 /// \returns true if \p F creates ref-countable object from uncounted 
parameter,
 /// false if not.
 bool isCtorOfRefCounted(const clang::FunctionDecl *F);
 
+/// \returns true if \p F creates ref-countable object from uncounted 
parameter,
+/// false if not.
+bool isCtorOfCheckedPtr(const clang::FunctionDecl *F);
+
+/// \returns true if \p Name is RefPtr, Ref, or its variant, false if not.
+bool isRefType(const std::string &Name);
+
+/// \returns true if \p Name is CheckedRef or CheckedPtr, false if not.
+bool isCheckedPtr(const std::string &Name);
+
 /// \returns true if \p T is RefPtr, Ref, or its variant, false if not.
 bool isRefType(const clang::QualType T);

t-rasmud wrote:

This is more of a question for me to understand: Is there a reason this 
overload of `isRefType` isn't modified to check for `CheckedPtr`, `CheckedRef`?

https://github.com/llvm/llvm-project/pull/110222
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WebKit Checkers] Make TrivialFunctionAnalysis recognize std::array::operator[] as trivial (PR #113377)

2024-10-24 Thread Rashmi Mudduluru via cfe-commits

https://github.com/t-rasmud updated 
https://github.com/llvm/llvm-project/pull/113377

>From 0374a38b9abff286048dd58067c360257ab96318 Mon Sep 17 00:00:00 2001
From: Rashmi Mudduluru 
Date: Tue, 22 Oct 2024 13:16:30 -0700
Subject: [PATCH] [WebKit Checkers] Make TrivialFunctionAnalysis recognize
 std::array::operator[] as trivial

TFA wasn't recognizing `__libcpp_verbose_abort` as trivial causing 
`std::array::operator[]` also not being recongnized as trivial.
---
 .../Checkers/WebKit/PtrTypesSemantics.cpp |  3 +-
 .../WebKit/uncounted-obj-arg-std-array.cpp| 39 +++
 .../Checkers/WebKit/uncounted-obj-arg.cpp |  6 +++
 3 files changed, 47 insertions(+), 1 deletion(-)
 create mode 100644 
clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg-std-array.cpp

diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
index e043806eadd6ac..71440e6d08a1c9 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
@@ -414,7 +414,8 @@ class TrivialFunctionAnalysisVisitor
 Name == "isMainThreadOrGCThread" || Name == "isMainRunLoop" ||
 Name == "isWebThread" || Name == "isUIThread" ||
 Name == "mayBeGCThread" || Name == "compilerFenceForCrash" ||
-Name == "bitwise_cast" || Name.find("__builtin") == 0)
+Name == "bitwise_cast" || Name.find("__builtin") == 0 ||
+Name == "__libcpp_verbose_abort")
   return true;
 
 return IsFunctionTrivial(Callee);
diff --git 
a/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg-std-array.cpp 
b/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg-std-array.cpp
new file mode 100644
index 00..ed28a64bba059c
--- /dev/null
+++ b/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg-std-array.cpp
@@ -0,0 +1,39 @@
+// RUN: %clang_analyze_cc1 
-analyzer-checker=alpha.webkit.UncountedCallArgsChecker -verify %s
+// expected-no-diagnostics
+
+#include "mock-types.h"
+
+void __libcpp_verbose_abort(const char *__format, ...);
+
+using size_t = __typeof(sizeof(int));
+namespace std{
+template 
+class array {
+  T elements[N];
+  
+  public:
+  T& operator[](unsigned i) {
+if (i >= N) {
+  __libcpp_verbose_abort("%s", "aborting");
+}
+return elements[i];
+  }
+};
+}
+
+class ArrayClass {
+public:
+  void ref() const;
+  void deref() const;
+  typedef std::array, 4> Matrix;
+  double e() { return matrix[3][0]; }
+  Matrix matrix;
+};
+
+class AnotherClass {
+  RefPtr matrix;
+  void test() {
+double val = { matrix->e()};
+  }
+};
+
diff --git a/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp 
b/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp
index 10da776f81575c..e1dacdd9e25b6d 100644
--- a/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp
+++ b/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp
@@ -238,6 +238,8 @@ class SomeType : public BaseType {
   using BaseType::BaseType;
 };
 
+void __libcpp_verbose_abort(const char *__format, ...);
+
 class RefCounted {
 public:
   void ref() const;
@@ -361,6 +363,9 @@ class RefCounted {
   void trivial62() { WTFReportBacktrace(); }
   SomeType trivial63() { return SomeType(0); }
   SomeType trivial64() { return SomeType(); }
+  void trivial65() {
+__libcpp_verbose_abort("%s", "aborting");
+  }
 
   static RefCounted& singleton() {
 static RefCounted s_RefCounted;
@@ -544,6 +549,7 @@ class UnrelatedClass {
 getFieldTrivial().trivial62(); // no-warning
 getFieldTrivial().trivial63(); // no-warning
 getFieldTrivial().trivial64(); // no-warning
+getFieldTrivial().trivial65(); // no-warning
 
 RefCounted::singleton().trivial18(); // no-warning
 RefCounted::singleton().someFunction(); // no-warning

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WebKit Checkers] Make TrivialFunctionAnalysis recognize std::array::operator[] as trivial (PR #113377)

2024-10-24 Thread Rashmi Mudduluru via cfe-commits

https://github.com/t-rasmud updated 
https://github.com/llvm/llvm-project/pull/113377

>From 9e21b0f2f0968a5f8810c797913318884dcc8c7b Mon Sep 17 00:00:00 2001
From: Rashmi Mudduluru 
Date: Tue, 22 Oct 2024 13:16:30 -0700
Subject: [PATCH 1/2] [WebKit Checkers] Make TrivialFunctionAnalysis recognize
 std::array::operator[] as trivial

TFA wasn't recognizing `__libcpp_verbose_abort` as trivial causing 
`std::array::operator[]` also not being recongnized as trivial.
---
 .../Checkers/WebKit/PtrTypesSemantics.cpp |  3 +-
 .../WebKit/uncounted-obj-arg-std-array.cpp| 33 +++
 2 files changed, 35 insertions(+), 1 deletion(-)
 create mode 100644 
clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg-std-array.cpp

diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
index e043806eadd6ac..71440e6d08a1c9 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
@@ -414,7 +414,8 @@ class TrivialFunctionAnalysisVisitor
 Name == "isMainThreadOrGCThread" || Name == "isMainRunLoop" ||
 Name == "isWebThread" || Name == "isUIThread" ||
 Name == "mayBeGCThread" || Name == "compilerFenceForCrash" ||
-Name == "bitwise_cast" || Name.find("__builtin") == 0)
+Name == "bitwise_cast" || Name.find("__builtin") == 0 ||
+Name == "__libcpp_verbose_abort")
   return true;
 
 return IsFunctionTrivial(Callee);
diff --git 
a/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg-std-array.cpp 
b/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg-std-array.cpp
new file mode 100644
index 00..43c76c0b0793a8
--- /dev/null
+++ b/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg-std-array.cpp
@@ -0,0 +1,33 @@
+// RUN: %clang_analyze_cc1 
-analyzer-checker=alpha.webkit.UncountedCallArgsChecker -verify %s
+// expected-no-diagnostics
+
+#include "mock-types.h"
+
+using size_t = __typeof(sizeof(int));
+namespace std{
+template 
+class array {
+  T elements[N];
+  
+  public:
+  T& operator[](unsigned i) { return elements[i]; }
+  constexpr const T* data() const noexcept {
+ return elements;
+  }
+
+};
+}
+
+class ArrayClass {
+public:
+typedef std::array, 4> Matrix;
+double e() { return matrix[3][0]; }
+Matrix matrix;
+};
+
+class AnotherClass {
+Ref matrix;
+void test() {
+  double val[] = { matrix->e(), matrix->e() };
+}
+};

>From a7d7b50159161a4d9ac85532d38ed14fdb841195 Mon Sep 17 00:00:00 2001
From: Rashmi Mudduluru 
Date: Thu, 24 Oct 2024 11:44:32 -0700
Subject: [PATCH 2/2] fix tests to call __libcpp_verbose_abort

---
 .../WebKit/uncounted-obj-arg-std-array.cpp| 28 +++
 .../Checkers/WebKit/uncounted-obj-arg.cpp |  7 +
 2 files changed, 24 insertions(+), 11 deletions(-)

diff --git 
a/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg-std-array.cpp 
b/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg-std-array.cpp
index 43c76c0b0793a8..ed28a64bba059c 100644
--- a/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg-std-array.cpp
+++ b/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg-std-array.cpp
@@ -3,6 +3,8 @@
 
 #include "mock-types.h"
 
+void __libcpp_verbose_abort(const char *__format, ...);
+
 using size_t = __typeof(sizeof(int));
 namespace std{
 template 
@@ -10,24 +12,28 @@ class array {
   T elements[N];
   
   public:
-  T& operator[](unsigned i) { return elements[i]; }
-  constexpr const T* data() const noexcept {
- return elements;
+  T& operator[](unsigned i) {
+if (i >= N) {
+  __libcpp_verbose_abort("%s", "aborting");
+}
+return elements[i];
   }
-
 };
 }
 
 class ArrayClass {
 public:
-typedef std::array, 4> Matrix;
-double e() { return matrix[3][0]; }
-Matrix matrix;
+  void ref() const;
+  void deref() const;
+  typedef std::array, 4> Matrix;
+  double e() { return matrix[3][0]; }
+  Matrix matrix;
 };
 
 class AnotherClass {
-Ref matrix;
-void test() {
-  double val[] = { matrix->e(), matrix->e() };
-}
+  RefPtr matrix;
+  void test() {
+double val = { matrix->e()};
+  }
 };
+
diff --git a/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp 
b/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp
index 10da776f81575c..2fe818a629cb82 100644
--- a/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp
+++ b/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp
@@ -238,6 +238,8 @@ class SomeType : public BaseType {
   using BaseType::BaseType;
 };
 
+void __libcpp_verbose_abort(const char *__format, ...);
+
 class RefCounted {
 public:
   void ref() const;
@@ -452,6 +454,10 @@ class RefCounted {
   unsigned nonTrivial23() { return DerivedNumber("123").value(); }
   SomeType nonTrivial24() { return SomeType("123"); }
 
+  void call_libcpp_verbose_abort() {
+  __libcpp_verbose_abort("%s", "aborting");
+}
+
   sta

[clang] [alpha.webkit.UncountedLocalVarsChecker] Warn the use of a raw pointer/reference when the guardian variable gets mutated. (PR #113859)

2024-10-29 Thread Rashmi Mudduluru via cfe-commits


@@ -83,6 +83,77 @@ void foo7(RefCountable* obj) {
   bar.obj->method();
 }
 
+void foo8(RefCountable* obj) {
+  RefPtr foo;
+  {
+RefCountable *bar = foo.get();
+// expected-warning@-1{{Local variable 'bar' is uncounted and unsafe 
[alpha.webkit.UncountedLocalVarsChecker]}}
+foo = nullptr;
+bar->method();
+  }
+  RefPtr baz;
+  {
+RefCountable *bar = baz.get();
+// expected-warning@-1{{Local variable 'bar' is uncounted and unsafe 
[alpha.webkit.UncountedLocalVarsChecker]}}
+baz = obj;
+bar->method();
+  }
+  foo = nullptr;
+  {
+RefCountable *bar = foo.get();
+// No warning. It's okay to mutate RefPtr in an outer scope.
+bar->method();
+  }
+  foo = obj;
+  {
+RefCountable *bar = foo.get();
+// expected-warning@-1{{Local variable 'bar' is uncounted and unsafe 
[alpha.webkit.UncountedLocalVarsChecker]}}
+foo.releaseNonNull();
+bar->method();
+  }
+  {
+RefCountable *bar = foo.get();
+// expected-warning@-1{{Local variable 'bar' is uncounted and unsafe 
[alpha.webkit.UncountedLocalVarsChecker]}}
+foo = obj ? obj : nullptr;
+bar->method();
+  }
+}
+
+void foo9(RefCountable& o) {
+  Ref guardian(o);
+  {
+RefCountable &bar = guardian.get();
+// expected-warning@-1{{Local variable 'bar' is uncounted and unsafe 
[alpha.webkit.UncountedLocalVarsChecker]}}
+guardian = o; // We don't detect that we're setting it to the same value.
+bar.method();
+  }
+  {
+RefCountable *bar = guardian.ptr();
+// expected-warning@-1{{Local variable 'bar' is uncounted and unsafe 
[alpha.webkit.UncountedLocalVarsChecker]}}
+Ref other(*bar); // We don't detect other has the same value 
as guardian.
+guardian.swap(other);
+bar->method();
+  }
+  {
+RefCountable *bar = guardian.ptr();
+// expected-warning@-1{{Local variable 'bar' is uncounted and unsafe 
[alpha.webkit.UncountedLocalVarsChecker]}}
+Ref other(static_cast&&>(guardian));
+bar->method();
+  }
+  {
+RefCountable *bar = guardian.ptr();
+// expected-warning@-1{{Local variable 'bar' is uncounted and unsafe 
[alpha.webkit.UncountedLocalVarsChecker]}}
+guardian.leakRef();
+bar->method();
+  }
+  {
+RefCountable *bar = guardian.ptr();
+// expected-warning@-1{{Local variable 'bar' is uncounted and unsafe 
[alpha.webkit.UncountedLocalVarsChecker]}}
+guardian = o.trivial() ? o : *bar;

t-rasmud wrote:

Ah ok, that makes sense. Thank you for the explanation. Can we have a test case 
where the warning is expected? Maybe the following?
```
{
RefCountable *bar = foo->trivial()? foo.get() : nullptr;
}
```

https://github.com/llvm/llvm-project/pull/113859
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Webkit Checkers] Introduce a Webkit checker for memory unsafe casts (PR #114606)

2024-11-05 Thread Rashmi Mudduluru via cfe-commits

https://github.com/t-rasmud updated 
https://github.com/llvm/llvm-project/pull/114606

>From cc19550fdbaca4b77e90de57c472a31a8c3f8293 Mon Sep 17 00:00:00 2001
From: Rashmi Mudduluru 
Date: Fri, 1 Nov 2024 14:10:50 -0700
Subject: [PATCH 1/2] [Webkit Checkers] Introduce a Webkit checker for memory
 unsafe casts

The checker warns all downcasts from a base type to a derived type.

rdar://137766829
---
 clang/docs/analyzer/checkers.rst  |  25 +++
 clang/docs/tools/clang-formatted-files.txt|   1 +
 .../clang/StaticAnalyzer/Checkers/Checkers.td |   4 +
 .../StaticAnalyzer/Checkers/CMakeLists.txt|   1 +
 .../WebKit/MemoryUnsafeCastChecker.cpp|  86 ++
 .../Checkers/WebKit/memory-unsafe-cast.cpp| 151 ++
 .../Checkers/WebKit/memory-unsafe-cast.mm |  29 
 7 files changed, 297 insertions(+)
 create mode 100644 
clang/lib/StaticAnalyzer/Checkers/WebKit/MemoryUnsafeCastChecker.cpp
 create mode 100644 clang/test/Analysis/Checkers/WebKit/memory-unsafe-cast.cpp
 create mode 100644 clang/test/Analysis/Checkers/WebKit/memory-unsafe-cast.mm

diff --git a/clang/docs/analyzer/checkers.rst b/clang/docs/analyzer/checkers.rst
index 87b03438e6e0b9..f01755ce7a236a 100644
--- a/clang/docs/analyzer/checkers.rst
+++ b/clang/docs/analyzer/checkers.rst
@@ -3452,6 +3452,31 @@ alpha.WebKit
 
 .. _alpha-webkit-NoUncheckedPtrMemberChecker:
 
+alpha.webkit.MemoryUnsafeCastChecker
+""
+Check for all casts from a base type to its derived type as these might be 
memory-unsafe.
+
+Example:
+
+.. code-block:: cpp
+
+class Base { };
+class Derived : public Base { };
+
+void f(Base* base) {
+Derived* derived = static_cast(base); // ERROR
+}
+
+For all cast operations (C-style casts, static_cast, reinterpret_cast, 
dynamic_cast), if the source type a `Base*` and the destination type is 
`Derived*`, where `Derived` inherits from `Base`, the static analyzer should 
signal an error.
+
+This applies to:
+
+- C structs, C++ structs and classes, and Objective-C classes and protocols.
+- Pointers and references.
+- Inside template instantiations and macro expansions that are visible to the 
compiler.
+
+For types like this, instead of using built in casts, the programmer will use 
helper functions that internally perform the appropriate type check and disable 
static analysis.
+
 alpha.webkit.NoUncheckedPtrMemberChecker
 
 Raw pointers and references to an object which supports CheckedPtr or 
CheckedRef can't be used as class members. Only CheckedPtr, CheckedRef, RefPtr, 
or Ref are allowed.
diff --git a/clang/docs/tools/clang-formatted-files.txt 
b/clang/docs/tools/clang-formatted-files.txt
index 67ff085144f4de..74ab155d6174fd 100644
--- a/clang/docs/tools/clang-formatted-files.txt
+++ b/clang/docs/tools/clang-formatted-files.txt
@@ -537,6 +537,7 @@ 
clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
 clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp
 clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.h
 clang/lib/StaticAnalyzer/Checkers/WebKit/DiagOutputUtils.h
+clang/lib/StaticAnalyzer/Checkers/WebKit/MemoryUnsafeCastChecker.cpp
 clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
 clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
 clang/lib/StaticAnalyzer/Checkers/WebKit/RefCntblBaseVirtualDtorChecker.cpp
diff --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td 
b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
index 9a6b35c1b9f774..445379e88ab9e3 100644
--- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -1752,6 +1752,10 @@ def UncountedLambdaCapturesChecker : 
Checker<"UncountedLambdaCapturesChecker">,
 
 let ParentPackage = WebKitAlpha in {
 
+def MemoryUnsafeCastChecker : Checker<"MemoryUnsafeCastChecker">,
+  HelpText<"Check for memory unsafe casts from base type to derived type.">,
+  Documentation;
+
 def NoUncheckedPtrMemberChecker : Checker<"NoUncheckedPtrMemberChecker">,
   HelpText<"Check for no unchecked member variables.">,
   Documentation;
diff --git a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt 
b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
index 62aa5ff7f002a9..7e987740f9ee2d 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
+++ b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
@@ -132,6 +132,7 @@ add_clang_library(clangStaticAnalyzerCheckers
   VirtualCallChecker.cpp
   WebKit/RawPtrRefMemberChecker.cpp
   WebKit/ASTUtils.cpp
+  WebKit/MemoryUnsafeCastChecker.cpp
   WebKit/PtrTypesSemantics.cpp
   WebKit/RefCntblBaseVirtualDtorChecker.cpp
   WebKit/UncountedCallArgsChecker.cpp
diff --git 
a/clang/lib/StaticAnalyzer/Checkers/WebKit/MemoryUnsafeCastChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/MemoryUnsafeCastChecker.cpp
new file mode 100644
index 00..05a5f89d28c8fe
--- /dev/null
+++ b/clang/lib/StaticAnal

[clang] [Webkit Checkers] Introduce a Webkit checker for memory unsafe casts (PR #114606)

2024-11-05 Thread Rashmi Mudduluru via cfe-commits


@@ -0,0 +1,86 @@
+//===- MemoryUnsafeCastChecker.cpp -*- C++ -*-==//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+// This file defines MemoryUnsafeCast checker, which checks for casts from a
+// base type to a derived type.
+//===--===//
+
+#include "clang/AST/ASTContext.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/CheckerContext.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+class MemoryUnsafeCastChecker : public Checker> {

t-rasmud wrote:

Good point! I've update the patch to make the checker path-insensitive.

https://github.com/llvm/llvm-project/pull/114606
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [webkit.UncountedLambdaCapturesChecker] Ignore trivial functions and [[clang::noescape]]. (PR #113845)

2024-10-30 Thread Rashmi Mudduluru via cfe-commits

https://github.com/t-rasmud approved this pull request.

I have a couple of small nits that I left as comments. Otherwise LGTM!
Also, thank you for writing detailed explanations in your PR descriptions, they 
help me catch up to your code quickly.

https://github.com/llvm/llvm-project/pull/113845
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [webkit.UncountedLambdaCapturesChecker] Ignore trivial functions and [[clang::noescape]]. (PR #113845)

2024-10-30 Thread Rashmi Mudduluru via cfe-commits


@@ -45,8 +49,62 @@ class UncountedLambdaCapturesChecker
   bool shouldVisitTemplateInstantiations() const { return true; }
   bool shouldVisitImplicitCode() const { return false; }
 
-  bool VisitLambdaExpr(LambdaExpr *L) {
-Checker->visitLambdaExpr(L);
+  bool VisitDeclRefExpr(DeclRefExpr *DRE) {
+if (DeclRefExprsToIgnore.contains(DRE))
+  return true;
+if (auto *VD = dyn_cast_or_null(DRE->getDecl())) {
+  auto *Init = VD->getInit()->IgnoreParenCasts();
+  if (auto *L = dyn_cast_or_null(Init)) {
+Checker->visitLambdaExpr(L);
+return true;
+  }
+}
+return true;

t-rasmud wrote:

Is the return value in both the true and the false cases of the branch supposed 
to be `true`?

https://github.com/llvm/llvm-project/pull/113845
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [webkit.UncountedLambdaCapturesChecker] Ignore trivial functions and [[clang::noescape]]. (PR #113845)

2024-10-30 Thread Rashmi Mudduluru via cfe-commits

https://github.com/t-rasmud edited 
https://github.com/llvm/llvm-project/pull/113845
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [webkit.UncountedLambdaCapturesChecker] Ignore trivial functions and [[clang::noescape]]. (PR #113845)

2024-10-30 Thread Rashmi Mudduluru via cfe-commits


@@ -45,8 +49,62 @@ class UncountedLambdaCapturesChecker
   bool shouldVisitTemplateInstantiations() const { return true; }
   bool shouldVisitImplicitCode() const { return false; }
 
-  bool VisitLambdaExpr(LambdaExpr *L) {
-Checker->visitLambdaExpr(L);
+  bool VisitDeclRefExpr(DeclRefExpr *DRE) {
+if (DeclRefExprsToIgnore.contains(DRE))
+  return true;
+if (auto *VD = dyn_cast_or_null(DRE->getDecl())) {

t-rasmud wrote:

Would be great if we can continue the "early return coding style" like in the 2 
lines above:
```
auto *VD = dyn_cast_or_null(DRE->getDecl());
if (!VD)
return false;
```
Same comment for the following lines and for code in `VisitCallExpr`

https://github.com/llvm/llvm-project/pull/113845
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Webkit Checkers] Introduce a Webkit checker for memory unsafe casts (PR #114606)

2024-11-01 Thread Rashmi Mudduluru via cfe-commits

https://github.com/t-rasmud created 
https://github.com/llvm/llvm-project/pull/114606

This PR introduces a new checker `[alpha.webkit.MemoryUnsafeCastChecker]` that 
warns all downcasts from a base type to a derived type.

rdar://137766829

>From cc19550fdbaca4b77e90de57c472a31a8c3f8293 Mon Sep 17 00:00:00 2001
From: Rashmi Mudduluru 
Date: Fri, 1 Nov 2024 14:10:50 -0700
Subject: [PATCH] [Webkit Checkers] Introduce a Webkit checker for memory
 unsafe casts

The checker warns all downcasts from a base type to a derived type.

rdar://137766829
---
 clang/docs/analyzer/checkers.rst  |  25 +++
 clang/docs/tools/clang-formatted-files.txt|   1 +
 .../clang/StaticAnalyzer/Checkers/Checkers.td |   4 +
 .../StaticAnalyzer/Checkers/CMakeLists.txt|   1 +
 .../WebKit/MemoryUnsafeCastChecker.cpp|  86 ++
 .../Checkers/WebKit/memory-unsafe-cast.cpp| 151 ++
 .../Checkers/WebKit/memory-unsafe-cast.mm |  29 
 7 files changed, 297 insertions(+)
 create mode 100644 
clang/lib/StaticAnalyzer/Checkers/WebKit/MemoryUnsafeCastChecker.cpp
 create mode 100644 clang/test/Analysis/Checkers/WebKit/memory-unsafe-cast.cpp
 create mode 100644 clang/test/Analysis/Checkers/WebKit/memory-unsafe-cast.mm

diff --git a/clang/docs/analyzer/checkers.rst b/clang/docs/analyzer/checkers.rst
index 87b03438e6e0b9..f01755ce7a236a 100644
--- a/clang/docs/analyzer/checkers.rst
+++ b/clang/docs/analyzer/checkers.rst
@@ -3452,6 +3452,31 @@ alpha.WebKit
 
 .. _alpha-webkit-NoUncheckedPtrMemberChecker:
 
+alpha.webkit.MemoryUnsafeCastChecker
+""
+Check for all casts from a base type to its derived type as these might be 
memory-unsafe.
+
+Example:
+
+.. code-block:: cpp
+
+class Base { };
+class Derived : public Base { };
+
+void f(Base* base) {
+Derived* derived = static_cast(base); // ERROR
+}
+
+For all cast operations (C-style casts, static_cast, reinterpret_cast, 
dynamic_cast), if the source type a `Base*` and the destination type is 
`Derived*`, where `Derived` inherits from `Base`, the static analyzer should 
signal an error.
+
+This applies to:
+
+- C structs, C++ structs and classes, and Objective-C classes and protocols.
+- Pointers and references.
+- Inside template instantiations and macro expansions that are visible to the 
compiler.
+
+For types like this, instead of using built in casts, the programmer will use 
helper functions that internally perform the appropriate type check and disable 
static analysis.
+
 alpha.webkit.NoUncheckedPtrMemberChecker
 
 Raw pointers and references to an object which supports CheckedPtr or 
CheckedRef can't be used as class members. Only CheckedPtr, CheckedRef, RefPtr, 
or Ref are allowed.
diff --git a/clang/docs/tools/clang-formatted-files.txt 
b/clang/docs/tools/clang-formatted-files.txt
index 67ff085144f4de..74ab155d6174fd 100644
--- a/clang/docs/tools/clang-formatted-files.txt
+++ b/clang/docs/tools/clang-formatted-files.txt
@@ -537,6 +537,7 @@ 
clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
 clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp
 clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.h
 clang/lib/StaticAnalyzer/Checkers/WebKit/DiagOutputUtils.h
+clang/lib/StaticAnalyzer/Checkers/WebKit/MemoryUnsafeCastChecker.cpp
 clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
 clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
 clang/lib/StaticAnalyzer/Checkers/WebKit/RefCntblBaseVirtualDtorChecker.cpp
diff --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td 
b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
index 9a6b35c1b9f774..445379e88ab9e3 100644
--- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -1752,6 +1752,10 @@ def UncountedLambdaCapturesChecker : 
Checker<"UncountedLambdaCapturesChecker">,
 
 let ParentPackage = WebKitAlpha in {
 
+def MemoryUnsafeCastChecker : Checker<"MemoryUnsafeCastChecker">,
+  HelpText<"Check for memory unsafe casts from base type to derived type.">,
+  Documentation;
+
 def NoUncheckedPtrMemberChecker : Checker<"NoUncheckedPtrMemberChecker">,
   HelpText<"Check for no unchecked member variables.">,
   Documentation;
diff --git a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt 
b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
index 62aa5ff7f002a9..7e987740f9ee2d 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
+++ b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
@@ -132,6 +132,7 @@ add_clang_library(clangStaticAnalyzerCheckers
   VirtualCallChecker.cpp
   WebKit/RawPtrRefMemberChecker.cpp
   WebKit/ASTUtils.cpp
+  WebKit/MemoryUnsafeCastChecker.cpp
   WebKit/PtrTypesSemantics.cpp
   WebKit/RefCntblBaseVirtualDtorChecker.cpp
   WebKit/UncountedCallArgsChecker.cpp
diff --git 
a/clang/lib/StaticAnalyzer/Checkers/WebKit/MemoryUnsafeCastChecker.cpp 
b/clang/lib/Static

[clang] [WebKit Checkers] Make TrivialFunctionAnalysis recognize std::array::operator[] as trivial (PR #113377)

2024-10-25 Thread Rashmi Mudduluru via cfe-commits

https://github.com/t-rasmud updated 
https://github.com/llvm/llvm-project/pull/113377

>From 9e21b0f2f0968a5f8810c797913318884dcc8c7b Mon Sep 17 00:00:00 2001
From: Rashmi Mudduluru 
Date: Tue, 22 Oct 2024 13:16:30 -0700
Subject: [PATCH 1/3] [WebKit Checkers] Make TrivialFunctionAnalysis recognize
 std::array::operator[] as trivial

TFA wasn't recognizing `__libcpp_verbose_abort` as trivial causing 
`std::array::operator[]` also not being recongnized as trivial.
---
 .../Checkers/WebKit/PtrTypesSemantics.cpp |  3 +-
 .../WebKit/uncounted-obj-arg-std-array.cpp| 33 +++
 2 files changed, 35 insertions(+), 1 deletion(-)
 create mode 100644 
clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg-std-array.cpp

diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
index e043806eadd6ac..71440e6d08a1c9 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
@@ -414,7 +414,8 @@ class TrivialFunctionAnalysisVisitor
 Name == "isMainThreadOrGCThread" || Name == "isMainRunLoop" ||
 Name == "isWebThread" || Name == "isUIThread" ||
 Name == "mayBeGCThread" || Name == "compilerFenceForCrash" ||
-Name == "bitwise_cast" || Name.find("__builtin") == 0)
+Name == "bitwise_cast" || Name.find("__builtin") == 0 ||
+Name == "__libcpp_verbose_abort")
   return true;
 
 return IsFunctionTrivial(Callee);
diff --git 
a/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg-std-array.cpp 
b/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg-std-array.cpp
new file mode 100644
index 00..43c76c0b0793a8
--- /dev/null
+++ b/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg-std-array.cpp
@@ -0,0 +1,33 @@
+// RUN: %clang_analyze_cc1 
-analyzer-checker=alpha.webkit.UncountedCallArgsChecker -verify %s
+// expected-no-diagnostics
+
+#include "mock-types.h"
+
+using size_t = __typeof(sizeof(int));
+namespace std{
+template 
+class array {
+  T elements[N];
+  
+  public:
+  T& operator[](unsigned i) { return elements[i]; }
+  constexpr const T* data() const noexcept {
+ return elements;
+  }
+
+};
+}
+
+class ArrayClass {
+public:
+typedef std::array, 4> Matrix;
+double e() { return matrix[3][0]; }
+Matrix matrix;
+};
+
+class AnotherClass {
+Ref matrix;
+void test() {
+  double val[] = { matrix->e(), matrix->e() };
+}
+};

>From a7d7b50159161a4d9ac85532d38ed14fdb841195 Mon Sep 17 00:00:00 2001
From: Rashmi Mudduluru 
Date: Thu, 24 Oct 2024 11:44:32 -0700
Subject: [PATCH 2/3] fix tests to call __libcpp_verbose_abort

---
 .../WebKit/uncounted-obj-arg-std-array.cpp| 28 +++
 .../Checkers/WebKit/uncounted-obj-arg.cpp |  7 +
 2 files changed, 24 insertions(+), 11 deletions(-)

diff --git 
a/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg-std-array.cpp 
b/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg-std-array.cpp
index 43c76c0b0793a8..ed28a64bba059c 100644
--- a/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg-std-array.cpp
+++ b/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg-std-array.cpp
@@ -3,6 +3,8 @@
 
 #include "mock-types.h"
 
+void __libcpp_verbose_abort(const char *__format, ...);
+
 using size_t = __typeof(sizeof(int));
 namespace std{
 template 
@@ -10,24 +12,28 @@ class array {
   T elements[N];
   
   public:
-  T& operator[](unsigned i) { return elements[i]; }
-  constexpr const T* data() const noexcept {
- return elements;
+  T& operator[](unsigned i) {
+if (i >= N) {
+  __libcpp_verbose_abort("%s", "aborting");
+}
+return elements[i];
   }
-
 };
 }
 
 class ArrayClass {
 public:
-typedef std::array, 4> Matrix;
-double e() { return matrix[3][0]; }
-Matrix matrix;
+  void ref() const;
+  void deref() const;
+  typedef std::array, 4> Matrix;
+  double e() { return matrix[3][0]; }
+  Matrix matrix;
 };
 
 class AnotherClass {
-Ref matrix;
-void test() {
-  double val[] = { matrix->e(), matrix->e() };
-}
+  RefPtr matrix;
+  void test() {
+double val = { matrix->e()};
+  }
 };
+
diff --git a/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp 
b/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp
index 10da776f81575c..2fe818a629cb82 100644
--- a/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp
+++ b/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp
@@ -238,6 +238,8 @@ class SomeType : public BaseType {
   using BaseType::BaseType;
 };
 
+void __libcpp_verbose_abort(const char *__format, ...);
+
 class RefCounted {
 public:
   void ref() const;
@@ -452,6 +454,10 @@ class RefCounted {
   unsigned nonTrivial23() { return DerivedNumber("123").value(); }
   SomeType nonTrivial24() { return SomeType("123"); }
 
+  void call_libcpp_verbose_abort() {
+  __libcpp_verbose_abort("%s", "aborting");
+}
+
   sta

[clang] [webkit.UncountedLambdaCapturesChecker] Ignore trivial functions and [[clang::noescape]]. (PR #114897)

2024-11-11 Thread Rashmi Mudduluru via cfe-commits


@@ -89,7 +182,25 @@ class UncountedLambdaCapturesChecker
 }
 
 printQuotedQualifiedName(Os, Capture.getCapturedVar());
-Os << " to uncounted type is unsafe.";
+Os << " to ref-counted / CheckedPtr capable type is unsafe.";
+
+PathDiagnosticLocation BSLoc(Capture.getLocation(), 
BR->getSourceManager());
+auto Report = std::make_unique(Bug, Os.str(), BSLoc);
+BR->emitReport(std::move(Report));
+  }
+
+  void reportBugOnThisPtr(const LambdaCapture &Capture) const {
+SmallString<100> Buf;
+llvm::raw_svector_ostream Os(Buf);
+
+if (Capture.isExplicit()) {
+  Os << "Captured ";
+} else {
+  Os << "Implicitly captured ";
+}
+
+Os << "raw-pointer 'this' to ref-counted / CheckedPtr capable type is "

t-rasmud wrote:

nit: Can this warning be better worded? `.. ref-counted (or CheckedPtr capable) 
type ...`? Or anything else that conveys that it's unsafe to capture 
raw-pointer to a ref-counted type or a "CheckedPtr capable" type.

https://github.com/llvm/llvm-project/pull/114897
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [webkit.UncountedLambdaCapturesChecker] Ignore trivial functions and [[clang::noescape]]. (PR #114897)

2024-11-11 Thread Rashmi Mudduluru via cfe-commits

https://github.com/t-rasmud approved this pull request.

LGTM! Left a couple nits, mainly about readability of the warning.

https://github.com/llvm/llvm-project/pull/114897
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [webkit.UncountedLambdaCapturesChecker] Ignore trivial functions and [[clang::noescape]]. (PR #114897)

2024-11-11 Thread Rashmi Mudduluru via cfe-commits

https://github.com/t-rasmud edited 
https://github.com/llvm/llvm-project/pull/114897
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [webkit.UncountedLambdaCapturesChecker] Ignore trivial functions and [[clang::noescape]]. (PR #114897)

2024-11-11 Thread Rashmi Mudduluru via cfe-commits


@@ -45,32 +52,118 @@ class UncountedLambdaCapturesChecker
   bool shouldVisitTemplateInstantiations() const { return true; }
   bool shouldVisitImplicitCode() const { return false; }
 
-  bool VisitLambdaExpr(LambdaExpr *L) {
-Checker->visitLambdaExpr(L);
+  bool TraverseCXXMethodDecl(CXXMethodDecl *CXXMD) {
+llvm::SaveAndRestore SavedDecl(ClsType);
+ClsType = CXXMD->getThisType();
+return Base::TraverseDecl(CXXMD);
+  }
+
+  bool shouldCheckThis() {
+auto result = !ClsType.isNull() ? isUnsafePtr(ClsType) : std::nullopt;
+return result && *result;
+  }
+
+  bool VisitDeclRefExpr(DeclRefExpr *DRE) {
+if (DeclRefExprsToIgnore.contains(DRE))
+  return true;
+auto *VD = dyn_cast_or_null(DRE->getDecl());
+if (!VD)
+  return true;
+auto *Init = VD->getInit();
+if (!Init)
+  return true;
+auto *L = dyn_cast_or_null(Init->IgnoreParenCasts());
+if (!L)
+  return true;
+Checker->visitLambdaExpr(L, shouldCheckThis());
 return true;
   }
+
+  // WTF::switchOn(T, F... f) is a variadic template function and couldn't
+  // be annotated with NOESCAPE. We hard code it here to workaround that.
+  bool shouldTreatAllArgAsNoEscape(FunctionDecl *Decl) {
+auto *NsDecl = Decl->getParent();
+if (!NsDecl || !isa(NsDecl))
+  return false;
+return safeGetName(NsDecl) == "WTF" && safeGetName(Decl) == "switchOn";
+  }
+
+  bool VisitCallExpr(CallExpr *CE) {
+checkCalleeLambda(CE);
+if (auto *Callee = CE->getDirectCallee()) {
+  bool TreatAllArgsAsNoEscape = shouldTreatAllArgAsNoEscape(Callee);
+  unsigned ArgIndex = 0;
+  for (auto *Param : Callee->parameters()) {
+if (ArgIndex >= CE->getNumArgs())
+  break;

t-rasmud wrote:

nit: Could we just `return true` instead of a `break` here?

https://github.com/llvm/llvm-project/pull/114897
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WebKit Checkers] Make TrivialFunctionAnalysis recognize std::array::operator[] as trivial (PR #113377)

2024-10-24 Thread Rashmi Mudduluru via cfe-commits

https://github.com/t-rasmud closed 
https://github.com/llvm/llvm-project/pull/113377
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WebKit Checkers] Allow a guardian CheckedPtr/CheckedRef (PR #110222)

2024-10-25 Thread Rashmi Mudduluru via cfe-commits

https://github.com/t-rasmud approved this pull request.

LGTM!

https://github.com/llvm/llvm-project/pull/110222
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] Introduce a new WebKit checker for a unchecked local variable (PR #113708)

2024-10-31 Thread Rashmi Mudduluru via cfe-commits


@@ -0,0 +1,342 @@
+// RUN: %clang_analyze_cc1 
-analyzer-checker=alpha.webkit.UncheckedLocalVarsChecker -verify %s
+
+#include "mock-types.h"
+#include "mock-system-header.h"
+
+void someFunction();
+
+namespace raw_ptr {
+void foo() {
+  CheckedObj *bar;
+  // FIXME: later on we might warn on uninitialized vars too
+}
+
+void bar(CheckedObj *) {}
+} // namespace raw_ptr
+
+namespace reference {
+void foo_ref() {
+  CheckedObj automatic;
+  CheckedObj &bar = automatic;
+  // expected-warning@-1{{Local variable 'bar' is unchecked and unsafe 
[alpha.webkit.UncheckedLocalVarsChecker]}}
+  someFunction();
+  bar.method();
+}
+
+void foo_ref_trivial() {
+  CheckedObj automatic;
+  CheckedObj &bar = automatic;
+}
+
+void bar_ref(CheckedObj &) {}
+} // namespace reference
+
+namespace guardian_scopes {
+void foo1() {
+  CheckedPtr foo;
+  { CheckedObj *bar = foo.get(); }
+}
+
+void foo2() {
+  CheckedPtr foo;
+  // missing embedded scope here
+  CheckedObj *bar = foo.get();
+  // expected-warning@-1{{Local variable 'bar' is unchecked and unsafe 
[alpha.webkit.UncheckedLocalVarsChecker]}}
+  someFunction();
+  bar->method();
+}
+
+void foo3() {
+  CheckedPtr foo;
+  {
+{ CheckedObj *bar = foo.get(); }
+  }
+}
+
+void foo4() {
+  {
+CheckedPtr foo;
+{ CheckedObj *bar = foo.get(); }
+  }
+}
+
+void foo5() {
+  CheckedPtr foo;
+  auto* bar = foo.get();
+  bar->trivial();
+}
+
+void foo6() {
+  CheckedPtr foo;
+  auto* bar = foo.get();
+  // expected-warning@-1{{Local variable 'bar' is unchecked and unsafe 
[alpha.webkit.UncheckedLocalVarsChecker]}}
+  bar->method();
+}
+
+struct SelfReferencingStruct {
+  SelfReferencingStruct* ptr;
+  CheckedObj* obj { nullptr };
+};
+
+void foo7(CheckedObj* obj) {
+  SelfReferencingStruct bar = { &bar, obj };
+  bar.obj->method();
+}
+
+} // namespace guardian_scopes
+
+namespace auto_keyword {
+class Foo {
+  CheckedObj *provide_ref_ctnbl();
+
+  void evil_func() {
+CheckedObj *bar = provide_ref_ctnbl();
+// expected-warning@-1{{Local variable 'bar' is unchecked and unsafe 
[alpha.webkit.UncheckedLocalVarsChecker]}}
+auto *baz = provide_ref_ctnbl();
+// expected-warning@-1{{Local variable 'baz' is unchecked and unsafe 
[alpha.webkit.UncheckedLocalVarsChecker]}}
+auto *baz2 = this->provide_ref_ctnbl();
+// expected-warning@-1{{Local variable 'baz2' is unchecked and unsafe 
[alpha.webkit.UncheckedLocalVarsChecker]}}
+[[clang::suppress]] auto *baz_suppressed = provide_ref_ctnbl(); // 
no-warning
+  }
+
+  void func() {
+CheckedObj *bar = provide_ref_ctnbl();
+// expected-warning@-1{{Local variable 'bar' is unchecked and unsafe 
[alpha.webkit.UncheckedLocalVarsChecker]}}
+if (bar)
+  bar->method();
+  }
+};
+} // namespace auto_keyword
+
+namespace guardian_casts {
+void foo1() {
+  CheckedPtr foo;
+  {
+CheckedObj *bar = downcast(foo.get());
+bar->method();
+  }
+  foo->method();
+}
+
+void foo2() {
+  CheckedPtr foo;
+  {
+CheckedObj *bar =
+static_cast(downcast(foo.get()));
+someFunction();
+  }
+}
+} // namespace guardian_casts
+
+namespace guardian_ref_conversion_operator {
+void foo() {
+  CheckedRef rc;
+  {
+CheckedObj &rr = rc;
+rr.method();
+someFunction();
+  }
+}
+} // namespace guardian_ref_conversion_operator
+
+namespace ignore_for_if {
+CheckedObj *provide_ref_ctnbl() { return nullptr; }
+
+void foo() {
+  // no warnings
+  if (CheckedObj *a = provide_ref_ctnbl())
+a->trivial();
+  for (CheckedObj *b = provide_ref_ctnbl(); b != nullptr;)
+b->trivial();
+  CheckedObj *array[1];
+  for (CheckedObj *c : array)
+c->trivial();
+  while (CheckedObj *d = provide_ref_ctnbl())
+d->trivial();
+  do {
+CheckedObj *e = provide_ref_ctnbl();
+e->trivial();
+  } while (1);
+  someFunction();
+}
+
+void bar() {
+  if (CheckedObj *a = provide_ref_ctnbl()) {
+// expected-warning@-1{{Local variable 'a' is unchecked and unsafe 
[alpha.webkit.UncheckedLocalVarsChecker]}}
+a->method();
+  }
+  for (CheckedObj *b = provide_ref_ctnbl(); b != nullptr;) {
+// expected-warning@-1{{Local variable 'b' is unchecked and unsafe 
[alpha.webkit.UncheckedLocalVarsChecker]}}
+b->method();
+  }
+  CheckedObj *array[1];
+  for (CheckedObj *c : array) {
+// expected-warning@-1{{Local variable 'c' is unchecked and unsafe 
[alpha.webkit.UncheckedLocalVarsChecker]}}
+c->method();
+  }
+
+  while (CheckedObj *d = provide_ref_ctnbl()) {
+// expected-warning@-1{{Local variable 'd' is unchecked and unsafe 
[alpha.webkit.UncheckedLocalVarsChecker]}}
+d->method();
+  }
+  do {
+CheckedObj *e = provide_ref_ctnbl();
+// expected-warning@-1{{Local variable 'e' is unchecked and unsafe 
[alpha.webkit.UncheckedLocalVarsChecker]}}
+e->method();
+  } while (1);
+  someFunction();
+}
+
+} // namespace ignore_for_if
+
+namespace ignore_system_headers {
+
+CheckedObj *provide_checkable();
+
+void system_header() {
+  localVar(provide_checkable);
+}

[clang] [llvm] Introduce a new WebKit checker for a unchecked local variable (PR #113708)

2024-10-31 Thread Rashmi Mudduluru via cfe-commits

https://github.com/t-rasmud approved this pull request.

LGTM!

https://github.com/llvm/llvm-project/pull/113708
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [alpha.webkit.UncountedLocalVarsChecker] Warn the use of a raw pointer/reference when the guardian variable gets mutated. (PR #113859)

2024-10-29 Thread Rashmi Mudduluru via cfe-commits

https://github.com/t-rasmud approved this pull request.

LGTM!

https://github.com/llvm/llvm-project/pull/113859
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Webkit Checkers] Introduce a Webkit checker for memory unsafe casts (PR #114606)

2024-11-07 Thread Rashmi Mudduluru via cfe-commits


@@ -27,3 +27,27 @@ -(void)testCasts:(BaseClass*)base {
   base = (BaseClass*)base;  // no warning
 }
 @end
+
+template 
+class WrappedObject
+{
+public:
+  T get() const { return mMetalObject; }
+  T mMetalObject = nullptr;
+};
+
+@protocol MTLCommandEncoder
+@end
+@protocol MTLRenderCommandEncoder
+@end
+class CommandEncoder : public WrappedObject> { };
+
+class RenderCommandEncoder final : public CommandEncoder
+{
+private:
+// Override CommandEncoder
+id get()
+{
+return static_cast>(CommandEncoder::get());

t-rasmud wrote:

Hmmm.. This is a reproducer for the crash when `BaseObjCPtrType` is an invalid 
type class and we just return in that case.

https://github.com/llvm/llvm-project/pull/114606
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Webkit Checkers] Introduce a Webkit checker for memory unsafe casts (PR #114606)

2024-11-07 Thread Rashmi Mudduluru via cfe-commits

https://github.com/t-rasmud updated 
https://github.com/llvm/llvm-project/pull/114606

>From cc19550fdbaca4b77e90de57c472a31a8c3f8293 Mon Sep 17 00:00:00 2001
From: Rashmi Mudduluru 
Date: Fri, 1 Nov 2024 14:10:50 -0700
Subject: [PATCH 1/5] [Webkit Checkers] Introduce a Webkit checker for memory
 unsafe casts

The checker warns all downcasts from a base type to a derived type.

rdar://137766829
---
 clang/docs/analyzer/checkers.rst  |  25 +++
 clang/docs/tools/clang-formatted-files.txt|   1 +
 .../clang/StaticAnalyzer/Checkers/Checkers.td |   4 +
 .../StaticAnalyzer/Checkers/CMakeLists.txt|   1 +
 .../WebKit/MemoryUnsafeCastChecker.cpp|  86 ++
 .../Checkers/WebKit/memory-unsafe-cast.cpp| 151 ++
 .../Checkers/WebKit/memory-unsafe-cast.mm |  29 
 7 files changed, 297 insertions(+)
 create mode 100644 
clang/lib/StaticAnalyzer/Checkers/WebKit/MemoryUnsafeCastChecker.cpp
 create mode 100644 clang/test/Analysis/Checkers/WebKit/memory-unsafe-cast.cpp
 create mode 100644 clang/test/Analysis/Checkers/WebKit/memory-unsafe-cast.mm

diff --git a/clang/docs/analyzer/checkers.rst b/clang/docs/analyzer/checkers.rst
index 87b03438e6e0b9..f01755ce7a236a 100644
--- a/clang/docs/analyzer/checkers.rst
+++ b/clang/docs/analyzer/checkers.rst
@@ -3452,6 +3452,31 @@ alpha.WebKit
 
 .. _alpha-webkit-NoUncheckedPtrMemberChecker:
 
+alpha.webkit.MemoryUnsafeCastChecker
+""
+Check for all casts from a base type to its derived type as these might be 
memory-unsafe.
+
+Example:
+
+.. code-block:: cpp
+
+class Base { };
+class Derived : public Base { };
+
+void f(Base* base) {
+Derived* derived = static_cast(base); // ERROR
+}
+
+For all cast operations (C-style casts, static_cast, reinterpret_cast, 
dynamic_cast), if the source type a `Base*` and the destination type is 
`Derived*`, where `Derived` inherits from `Base`, the static analyzer should 
signal an error.
+
+This applies to:
+
+- C structs, C++ structs and classes, and Objective-C classes and protocols.
+- Pointers and references.
+- Inside template instantiations and macro expansions that are visible to the 
compiler.
+
+For types like this, instead of using built in casts, the programmer will use 
helper functions that internally perform the appropriate type check and disable 
static analysis.
+
 alpha.webkit.NoUncheckedPtrMemberChecker
 
 Raw pointers and references to an object which supports CheckedPtr or 
CheckedRef can't be used as class members. Only CheckedPtr, CheckedRef, RefPtr, 
or Ref are allowed.
diff --git a/clang/docs/tools/clang-formatted-files.txt 
b/clang/docs/tools/clang-formatted-files.txt
index 67ff085144f4de..74ab155d6174fd 100644
--- a/clang/docs/tools/clang-formatted-files.txt
+++ b/clang/docs/tools/clang-formatted-files.txt
@@ -537,6 +537,7 @@ 
clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
 clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp
 clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.h
 clang/lib/StaticAnalyzer/Checkers/WebKit/DiagOutputUtils.h
+clang/lib/StaticAnalyzer/Checkers/WebKit/MemoryUnsafeCastChecker.cpp
 clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
 clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
 clang/lib/StaticAnalyzer/Checkers/WebKit/RefCntblBaseVirtualDtorChecker.cpp
diff --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td 
b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
index 9a6b35c1b9f774..445379e88ab9e3 100644
--- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -1752,6 +1752,10 @@ def UncountedLambdaCapturesChecker : 
Checker<"UncountedLambdaCapturesChecker">,
 
 let ParentPackage = WebKitAlpha in {
 
+def MemoryUnsafeCastChecker : Checker<"MemoryUnsafeCastChecker">,
+  HelpText<"Check for memory unsafe casts from base type to derived type.">,
+  Documentation;
+
 def NoUncheckedPtrMemberChecker : Checker<"NoUncheckedPtrMemberChecker">,
   HelpText<"Check for no unchecked member variables.">,
   Documentation;
diff --git a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt 
b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
index 62aa5ff7f002a9..7e987740f9ee2d 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
+++ b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
@@ -132,6 +132,7 @@ add_clang_library(clangStaticAnalyzerCheckers
   VirtualCallChecker.cpp
   WebKit/RawPtrRefMemberChecker.cpp
   WebKit/ASTUtils.cpp
+  WebKit/MemoryUnsafeCastChecker.cpp
   WebKit/PtrTypesSemantics.cpp
   WebKit/RefCntblBaseVirtualDtorChecker.cpp
   WebKit/UncountedCallArgsChecker.cpp
diff --git 
a/clang/lib/StaticAnalyzer/Checkers/WebKit/MemoryUnsafeCastChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/MemoryUnsafeCastChecker.cpp
new file mode 100644
index 00..05a5f89d28c8fe
--- /dev/null
+++ b/clang/lib/StaticAnal

[clang] [Webkit Checkers] Introduce a Webkit checker for memory unsafe casts (PR #114606)

2024-11-07 Thread Rashmi Mudduluru via cfe-commits


@@ -0,0 +1,117 @@
+//===- MemoryUnsafeCastChecker.cpp -*- C++ -*-==//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+// This file defines MemoryUnsafeCast checker, which checks for casts from a
+// base type to a derived type.
+//===--===//
+
+#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/Analysis/AnalysisDeclContext.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+class WalkAST : public StmtVisitor {
+  BugReporter &BR;
+  const CheckerBase *Checker;
+  AnalysisDeclContext* AC;
+  ASTContext &ASTC;
+
+public:
+  WalkAST(BugReporter &br, const CheckerBase *checker, AnalysisDeclContext *ac)
+  : BR(br), Checker(checker), AC(ac), ASTC(AC->getASTContext()) {}
+
+  // Statement visitor methods.
+  void VisitChildren(Stmt *S);
+  void VisitStmt(Stmt *S) { VisitChildren(S); }
+  void VisitCastExpr(CastExpr *CE);
+};
+} // end anonymous namespace
+
+void emitWarning(QualType FromType, QualType ToType,
+ AnalysisDeclContext *AC, BugReporter &BR,
+ const CheckerBase *Checker,
+ CastExpr *CE) {
+  std::string Diagnostics;
+  llvm::raw_string_ostream OS(Diagnostics);
+  OS << "Unsafe cast from base type '"
+ << FromType
+ << "' to derived type '"
+ << ToType
+ << "'",
+
+  BR.EmitBasicReport(
+AC->getDecl(),
+Checker,
+/*Name=*/"Memory unsafe cast",
+categories::SecurityError,
+Diagnostics,
+PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC),
+CE->getSourceRange());
+}
+
+namespace {
+class MemoryUnsafeCastChecker : public Checker {
+  BugType BT{this, ""};
+public:
+  void checkASTCodeBody(const Decl *D, AnalysisManager& Mgr,
+BugReporter &BR) const {
+WalkAST walker(BR, this, Mgr.getAnalysisDeclContext(D));

t-rasmud wrote:

Also, I did not find a way to chain `match CxxRecordDecl` in a way that can 
pull the type of the parent class and match it with the explicitly cast type. 
Are there examples/documentation for matching on base class for the current 
`cxxRecordDecl`?

https://github.com/llvm/llvm-project/pull/114606
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Webkit Checkers] Introduce a Webkit checker for memory unsafe casts (PR #114606)

2024-11-07 Thread Rashmi Mudduluru via cfe-commits

https://github.com/t-rasmud edited 
https://github.com/llvm/llvm-project/pull/114606
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Webkit Checkers] Introduce a Webkit checker for memory unsafe casts (PR #114606)

2024-11-06 Thread Rashmi Mudduluru via cfe-commits

https://github.com/t-rasmud updated 
https://github.com/llvm/llvm-project/pull/114606

>From cc19550fdbaca4b77e90de57c472a31a8c3f8293 Mon Sep 17 00:00:00 2001
From: Rashmi Mudduluru 
Date: Fri, 1 Nov 2024 14:10:50 -0700
Subject: [PATCH 1/3] [Webkit Checkers] Introduce a Webkit checker for memory
 unsafe casts

The checker warns all downcasts from a base type to a derived type.

rdar://137766829
---
 clang/docs/analyzer/checkers.rst  |  25 +++
 clang/docs/tools/clang-formatted-files.txt|   1 +
 .../clang/StaticAnalyzer/Checkers/Checkers.td |   4 +
 .../StaticAnalyzer/Checkers/CMakeLists.txt|   1 +
 .../WebKit/MemoryUnsafeCastChecker.cpp|  86 ++
 .../Checkers/WebKit/memory-unsafe-cast.cpp| 151 ++
 .../Checkers/WebKit/memory-unsafe-cast.mm |  29 
 7 files changed, 297 insertions(+)
 create mode 100644 
clang/lib/StaticAnalyzer/Checkers/WebKit/MemoryUnsafeCastChecker.cpp
 create mode 100644 clang/test/Analysis/Checkers/WebKit/memory-unsafe-cast.cpp
 create mode 100644 clang/test/Analysis/Checkers/WebKit/memory-unsafe-cast.mm

diff --git a/clang/docs/analyzer/checkers.rst b/clang/docs/analyzer/checkers.rst
index 87b03438e6e0b9..f01755ce7a236a 100644
--- a/clang/docs/analyzer/checkers.rst
+++ b/clang/docs/analyzer/checkers.rst
@@ -3452,6 +3452,31 @@ alpha.WebKit
 
 .. _alpha-webkit-NoUncheckedPtrMemberChecker:
 
+alpha.webkit.MemoryUnsafeCastChecker
+""
+Check for all casts from a base type to its derived type as these might be 
memory-unsafe.
+
+Example:
+
+.. code-block:: cpp
+
+class Base { };
+class Derived : public Base { };
+
+void f(Base* base) {
+Derived* derived = static_cast(base); // ERROR
+}
+
+For all cast operations (C-style casts, static_cast, reinterpret_cast, 
dynamic_cast), if the source type a `Base*` and the destination type is 
`Derived*`, where `Derived` inherits from `Base`, the static analyzer should 
signal an error.
+
+This applies to:
+
+- C structs, C++ structs and classes, and Objective-C classes and protocols.
+- Pointers and references.
+- Inside template instantiations and macro expansions that are visible to the 
compiler.
+
+For types like this, instead of using built in casts, the programmer will use 
helper functions that internally perform the appropriate type check and disable 
static analysis.
+
 alpha.webkit.NoUncheckedPtrMemberChecker
 
 Raw pointers and references to an object which supports CheckedPtr or 
CheckedRef can't be used as class members. Only CheckedPtr, CheckedRef, RefPtr, 
or Ref are allowed.
diff --git a/clang/docs/tools/clang-formatted-files.txt 
b/clang/docs/tools/clang-formatted-files.txt
index 67ff085144f4de..74ab155d6174fd 100644
--- a/clang/docs/tools/clang-formatted-files.txt
+++ b/clang/docs/tools/clang-formatted-files.txt
@@ -537,6 +537,7 @@ 
clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
 clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp
 clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.h
 clang/lib/StaticAnalyzer/Checkers/WebKit/DiagOutputUtils.h
+clang/lib/StaticAnalyzer/Checkers/WebKit/MemoryUnsafeCastChecker.cpp
 clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
 clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
 clang/lib/StaticAnalyzer/Checkers/WebKit/RefCntblBaseVirtualDtorChecker.cpp
diff --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td 
b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
index 9a6b35c1b9f774..445379e88ab9e3 100644
--- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -1752,6 +1752,10 @@ def UncountedLambdaCapturesChecker : 
Checker<"UncountedLambdaCapturesChecker">,
 
 let ParentPackage = WebKitAlpha in {
 
+def MemoryUnsafeCastChecker : Checker<"MemoryUnsafeCastChecker">,
+  HelpText<"Check for memory unsafe casts from base type to derived type.">,
+  Documentation;
+
 def NoUncheckedPtrMemberChecker : Checker<"NoUncheckedPtrMemberChecker">,
   HelpText<"Check for no unchecked member variables.">,
   Documentation;
diff --git a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt 
b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
index 62aa5ff7f002a9..7e987740f9ee2d 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
+++ b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
@@ -132,6 +132,7 @@ add_clang_library(clangStaticAnalyzerCheckers
   VirtualCallChecker.cpp
   WebKit/RawPtrRefMemberChecker.cpp
   WebKit/ASTUtils.cpp
+  WebKit/MemoryUnsafeCastChecker.cpp
   WebKit/PtrTypesSemantics.cpp
   WebKit/RefCntblBaseVirtualDtorChecker.cpp
   WebKit/UncountedCallArgsChecker.cpp
diff --git 
a/clang/lib/StaticAnalyzer/Checkers/WebKit/MemoryUnsafeCastChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/MemoryUnsafeCastChecker.cpp
new file mode 100644
index 00..05a5f89d28c8fe
--- /dev/null
+++ b/clang/lib/StaticAnal

[clang] [llvm] Introduce a new WebKit checker for a unchecked call arguments (#113708) (PR #114522)

2024-11-06 Thread Rashmi Mudduluru via cfe-commits

https://github.com/t-rasmud edited 
https://github.com/llvm/llvm-project/pull/114522
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] Introduce a new WebKit checker for a unchecked call arguments (#113708) (PR #114522)

2024-11-06 Thread Rashmi Mudduluru via cfe-commits

https://github.com/t-rasmud approved this pull request.

I had a couple clarifying questions, otherwise LGTM!

https://github.com/llvm/llvm-project/pull/114522
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] Introduce a new WebKit checker for a unchecked call arguments (#113708) (PR #114522)

2024-11-06 Thread Rashmi Mudduluru via cfe-commits


@@ -1,4 +1,4 @@
-//===- UncountedCallArgsChecker.cpp --*- C++ 
-*-==//
+//===- RawPtrRefCallArgsChecker.cpp --*- C++ 
-*-==//

t-rasmud wrote:

Would it make sense to have documentation for `RawPtrCallArgsChecker` in 
`checkers.rst`? Do you anticipate more generic checkers calling this checker 
besides `UncountedCallArgsChecker` and `UncheckedCallArgsChecker`?

https://github.com/llvm/llvm-project/pull/114522
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] Introduce a new WebKit checker for a unchecked call arguments (#113708) (PR #114522)

2024-11-06 Thread Rashmi Mudduluru via cfe-commits


@@ -55,10 +55,18 @@ bool isCheckedPtr(const clang::CXXRecordDecl *Class);
 /// not, std::nullopt if inconclusive.
 std::optional isUncounted(const clang::QualType T);
 
+/// \returns true if \p Class is CheckedPtr capable AND not checked, false if
+/// not, std::nullopt if inconclusive.
+std::optional isUnchecked(const clang::QualType T);

t-rasmud wrote:

I can't seem to find a reference to this overload of `isUnchecked`. Do you see 
a use of it in future?

https://github.com/llvm/llvm-project/pull/114522
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Webkit Checkers] Introduce a Webkit checker for memory unsafe casts (PR #114606)

2024-11-20 Thread Rashmi Mudduluru via cfe-commits

https://github.com/t-rasmud updated 
https://github.com/llvm/llvm-project/pull/114606

>From cc19550fdbaca4b77e90de57c472a31a8c3f8293 Mon Sep 17 00:00:00 2001
From: Rashmi Mudduluru 
Date: Fri, 1 Nov 2024 14:10:50 -0700
Subject: [PATCH 1/7] [Webkit Checkers] Introduce a Webkit checker for memory
 unsafe casts

The checker warns all downcasts from a base type to a derived type.

rdar://137766829
---
 clang/docs/analyzer/checkers.rst  |  25 +++
 clang/docs/tools/clang-formatted-files.txt|   1 +
 .../clang/StaticAnalyzer/Checkers/Checkers.td |   4 +
 .../StaticAnalyzer/Checkers/CMakeLists.txt|   1 +
 .../WebKit/MemoryUnsafeCastChecker.cpp|  86 ++
 .../Checkers/WebKit/memory-unsafe-cast.cpp| 151 ++
 .../Checkers/WebKit/memory-unsafe-cast.mm |  29 
 7 files changed, 297 insertions(+)
 create mode 100644 
clang/lib/StaticAnalyzer/Checkers/WebKit/MemoryUnsafeCastChecker.cpp
 create mode 100644 clang/test/Analysis/Checkers/WebKit/memory-unsafe-cast.cpp
 create mode 100644 clang/test/Analysis/Checkers/WebKit/memory-unsafe-cast.mm

diff --git a/clang/docs/analyzer/checkers.rst b/clang/docs/analyzer/checkers.rst
index 87b03438e6e0b9..f01755ce7a236a 100644
--- a/clang/docs/analyzer/checkers.rst
+++ b/clang/docs/analyzer/checkers.rst
@@ -3452,6 +3452,31 @@ alpha.WebKit
 
 .. _alpha-webkit-NoUncheckedPtrMemberChecker:
 
+alpha.webkit.MemoryUnsafeCastChecker
+""
+Check for all casts from a base type to its derived type as these might be 
memory-unsafe.
+
+Example:
+
+.. code-block:: cpp
+
+class Base { };
+class Derived : public Base { };
+
+void f(Base* base) {
+Derived* derived = static_cast(base); // ERROR
+}
+
+For all cast operations (C-style casts, static_cast, reinterpret_cast, 
dynamic_cast), if the source type a `Base*` and the destination type is 
`Derived*`, where `Derived` inherits from `Base`, the static analyzer should 
signal an error.
+
+This applies to:
+
+- C structs, C++ structs and classes, and Objective-C classes and protocols.
+- Pointers and references.
+- Inside template instantiations and macro expansions that are visible to the 
compiler.
+
+For types like this, instead of using built in casts, the programmer will use 
helper functions that internally perform the appropriate type check and disable 
static analysis.
+
 alpha.webkit.NoUncheckedPtrMemberChecker
 
 Raw pointers and references to an object which supports CheckedPtr or 
CheckedRef can't be used as class members. Only CheckedPtr, CheckedRef, RefPtr, 
or Ref are allowed.
diff --git a/clang/docs/tools/clang-formatted-files.txt 
b/clang/docs/tools/clang-formatted-files.txt
index 67ff085144f4de..74ab155d6174fd 100644
--- a/clang/docs/tools/clang-formatted-files.txt
+++ b/clang/docs/tools/clang-formatted-files.txt
@@ -537,6 +537,7 @@ 
clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
 clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp
 clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.h
 clang/lib/StaticAnalyzer/Checkers/WebKit/DiagOutputUtils.h
+clang/lib/StaticAnalyzer/Checkers/WebKit/MemoryUnsafeCastChecker.cpp
 clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
 clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
 clang/lib/StaticAnalyzer/Checkers/WebKit/RefCntblBaseVirtualDtorChecker.cpp
diff --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td 
b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
index 9a6b35c1b9f774..445379e88ab9e3 100644
--- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -1752,6 +1752,10 @@ def UncountedLambdaCapturesChecker : 
Checker<"UncountedLambdaCapturesChecker">,
 
 let ParentPackage = WebKitAlpha in {
 
+def MemoryUnsafeCastChecker : Checker<"MemoryUnsafeCastChecker">,
+  HelpText<"Check for memory unsafe casts from base type to derived type.">,
+  Documentation;
+
 def NoUncheckedPtrMemberChecker : Checker<"NoUncheckedPtrMemberChecker">,
   HelpText<"Check for no unchecked member variables.">,
   Documentation;
diff --git a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt 
b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
index 62aa5ff7f002a9..7e987740f9ee2d 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
+++ b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
@@ -132,6 +132,7 @@ add_clang_library(clangStaticAnalyzerCheckers
   VirtualCallChecker.cpp
   WebKit/RawPtrRefMemberChecker.cpp
   WebKit/ASTUtils.cpp
+  WebKit/MemoryUnsafeCastChecker.cpp
   WebKit/PtrTypesSemantics.cpp
   WebKit/RefCntblBaseVirtualDtorChecker.cpp
   WebKit/UncountedCallArgsChecker.cpp
diff --git 
a/clang/lib/StaticAnalyzer/Checkers/WebKit/MemoryUnsafeCastChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/MemoryUnsafeCastChecker.cpp
new file mode 100644
index 00..05a5f89d28c8fe
--- /dev/null
+++ b/clang/lib/StaticAnal

[clang] [ASTMatchers] AST matcher support for ObjC pointers (PR #117021)

2024-11-20 Thread Rashmi Mudduluru via cfe-commits

https://github.com/t-rasmud created 
https://github.com/llvm/llvm-project/pull/117021

Add `ObjCInterfaceDecl` to the list of types supported by the `hasType` and 
`hasDeclaration` matchers, `ObjCObjectPointerType` to the list of types 
supported by `pointee`.

>From 87ba2a10ca7435fdf6b5c47d2c1c97c1e188cfcd Mon Sep 17 00:00:00 2001
From: Rashmi Mudduluru 
Date: Tue, 19 Nov 2024 14:50:24 -0800
Subject: [PATCH] [ASTMatchers] AST matcher support for ObjC pointers

Add `ObjCInterfaceDecl` to the list of types supported by the `hasType` and 
`hasDeclaration` matchers,
`ObjCObjectPointerType` to the list of types supported by `pointee`.
---
 clang/include/clang/ASTMatchers/ASTMatchers.h |  5 +++--
 clang/include/clang/ASTMatchers/ASTMatchersInternal.h | 11 ++-
 clang/lib/ASTMatchers/ASTMatchersInternal.cpp |  2 +-
 .../ASTMatchers/ASTMatchersTraversalTest.cpp  |  7 +++
 4 files changed, 21 insertions(+), 4 deletions(-)

diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h 
b/clang/include/clang/ASTMatchers/ASTMatchers.h
index 4bcaa953a61af2..dc6d60a1bcd17f 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchers.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -4033,7 +4033,7 @@ AST_POLYMORPHIC_MATCHER_P_OVERLOAD(
 AST_POLYMORPHIC_MATCHER_P_OVERLOAD(
 hasType,
 AST_POLYMORPHIC_SUPPORTED_TYPES(Expr, FriendDecl, ValueDecl,
-CXXBaseSpecifier),
+CXXBaseSpecifier, ObjCInterfaceDecl),
 internal::Matcher, InnerMatcher, 1) {
   QualType QT = internal::getUnderlyingType(Node);
   if (!QT.isNull())
@@ -7434,7 +7434,8 @@ extern const AstTypeMatcher 
rValueReferenceType;
 AST_TYPELOC_TRAVERSE_MATCHER_DECL(
 pointee, getPointee,
 AST_POLYMORPHIC_SUPPORTED_TYPES(BlockPointerType, MemberPointerType,
-PointerType, ReferenceType));
+PointerType, ReferenceType,
+ObjCObjectPointerType));
 
 /// Matches typedef types.
 ///
diff --git a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h 
b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h
index ab8b146453e761..2c690275dab71f 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -161,6 +161,9 @@ inline QualType getUnderlyingType(const FriendDecl &Node) {
 inline QualType getUnderlyingType(const CXXBaseSpecifier &Node) {
   return Node.getType();
 }
+inline QualType getUnderlyingType(const ObjCInterfaceDecl &Node) {
+  return Node.getTypeForDecl()->getPointeeType();
+}
 
 /// Unifies obtaining a `TypeSourceInfo` from different node types.
 template  
{
 return matchesDecl(Node.getDecl(), Finder, Builder);
   }
 
+  bool matchesSpecialized(const ObjCInterfaceDecl &Node,
+  ASTMatchFinder *Finder,
+  BoundNodesTreeBuilder *Builder) const {
+return matchesDecl(Node.getCanonicalDecl(), Finder, Builder);
+  }
+
   /// Extracts the operator new of the new call and returns whether the
   /// inner matcher matches on it.
   bool matchesSpecialized(const CXXNewExpr &Node,
@@ -1213,7 +1222,7 @@ using HasDeclarationSupportedTypes =
  ElaboratedType, InjectedClassNameType, LabelStmt, AddrLabelExpr,
  MemberExpr, QualType, RecordType, TagType,
  TemplateSpecializationType, TemplateTypeParmType, TypedefType,
- UnresolvedUsingType, ObjCIvarRefExpr>;
+ UnresolvedUsingType, ObjCIvarRefExpr, ObjCInterfaceDecl>;
 
 /// A Matcher that allows binding the node it matches to an id.
 ///
diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp 
b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
index 46dd44e6f2b24f..8def98ff6dc328 100644
--- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -1097,7 +1097,7 @@ AST_TYPELOC_TRAVERSE_MATCHER_DEF(hasValueType,
 AST_TYPELOC_TRAVERSE_MATCHER_DEF(
 pointee,
 AST_POLYMORPHIC_SUPPORTED_TYPES(BlockPointerType, MemberPointerType,
-PointerType, ReferenceType));
+PointerType, ReferenceType, 
ObjCObjectPointerType));
 
 const internal::VariadicDynCastAllOfMatcher
 ompExecutableDirective;
diff --git a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp 
b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
index 1d18869a6b8afc..adf8749a642fc3 100644
--- a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
@@ -283,6 +283,13 @@ TEST(HasDeclaration, HasDeclarationOfTypeAlias) {
   hasDeclaration(typeAliasTemplateDecl();
 }
 
+TEST(HasDeclaration, HasDeclarationOfObjCInterface) {
+  EXPECT_TRUE(matchesObjC(
+  "@interface BaseClass @end void f() {BaseClass* b;}",
+  varDecl(hasType(objcObjectPointerTyp

[clang] [ASTMatchers] AST matcher support for ObjC pointers (PR #117021)

2024-11-20 Thread Rashmi Mudduluru via cfe-commits

https://github.com/t-rasmud updated 
https://github.com/llvm/llvm-project/pull/117021

>From 87ba2a10ca7435fdf6b5c47d2c1c97c1e188cfcd Mon Sep 17 00:00:00 2001
From: Rashmi Mudduluru 
Date: Tue, 19 Nov 2024 14:50:24 -0800
Subject: [PATCH 1/2] [ASTMatchers] AST matcher support for ObjC pointers

Add `ObjCInterfaceDecl` to the list of types supported by the `hasType` and 
`hasDeclaration` matchers,
`ObjCObjectPointerType` to the list of types supported by `pointee`.
---
 clang/include/clang/ASTMatchers/ASTMatchers.h |  5 +++--
 clang/include/clang/ASTMatchers/ASTMatchersInternal.h | 11 ++-
 clang/lib/ASTMatchers/ASTMatchersInternal.cpp |  2 +-
 .../ASTMatchers/ASTMatchersTraversalTest.cpp  |  7 +++
 4 files changed, 21 insertions(+), 4 deletions(-)

diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h 
b/clang/include/clang/ASTMatchers/ASTMatchers.h
index 4bcaa953a61af2..dc6d60a1bcd17f 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchers.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -4033,7 +4033,7 @@ AST_POLYMORPHIC_MATCHER_P_OVERLOAD(
 AST_POLYMORPHIC_MATCHER_P_OVERLOAD(
 hasType,
 AST_POLYMORPHIC_SUPPORTED_TYPES(Expr, FriendDecl, ValueDecl,
-CXXBaseSpecifier),
+CXXBaseSpecifier, ObjCInterfaceDecl),
 internal::Matcher, InnerMatcher, 1) {
   QualType QT = internal::getUnderlyingType(Node);
   if (!QT.isNull())
@@ -7434,7 +7434,8 @@ extern const AstTypeMatcher 
rValueReferenceType;
 AST_TYPELOC_TRAVERSE_MATCHER_DECL(
 pointee, getPointee,
 AST_POLYMORPHIC_SUPPORTED_TYPES(BlockPointerType, MemberPointerType,
-PointerType, ReferenceType));
+PointerType, ReferenceType,
+ObjCObjectPointerType));
 
 /// Matches typedef types.
 ///
diff --git a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h 
b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h
index ab8b146453e761..2c690275dab71f 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -161,6 +161,9 @@ inline QualType getUnderlyingType(const FriendDecl &Node) {
 inline QualType getUnderlyingType(const CXXBaseSpecifier &Node) {
   return Node.getType();
 }
+inline QualType getUnderlyingType(const ObjCInterfaceDecl &Node) {
+  return Node.getTypeForDecl()->getPointeeType();
+}
 
 /// Unifies obtaining a `TypeSourceInfo` from different node types.
 template  
{
 return matchesDecl(Node.getDecl(), Finder, Builder);
   }
 
+  bool matchesSpecialized(const ObjCInterfaceDecl &Node,
+  ASTMatchFinder *Finder,
+  BoundNodesTreeBuilder *Builder) const {
+return matchesDecl(Node.getCanonicalDecl(), Finder, Builder);
+  }
+
   /// Extracts the operator new of the new call and returns whether the
   /// inner matcher matches on it.
   bool matchesSpecialized(const CXXNewExpr &Node,
@@ -1213,7 +1222,7 @@ using HasDeclarationSupportedTypes =
  ElaboratedType, InjectedClassNameType, LabelStmt, AddrLabelExpr,
  MemberExpr, QualType, RecordType, TagType,
  TemplateSpecializationType, TemplateTypeParmType, TypedefType,
- UnresolvedUsingType, ObjCIvarRefExpr>;
+ UnresolvedUsingType, ObjCIvarRefExpr, ObjCInterfaceDecl>;
 
 /// A Matcher that allows binding the node it matches to an id.
 ///
diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp 
b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
index 46dd44e6f2b24f..8def98ff6dc328 100644
--- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -1097,7 +1097,7 @@ AST_TYPELOC_TRAVERSE_MATCHER_DEF(hasValueType,
 AST_TYPELOC_TRAVERSE_MATCHER_DEF(
 pointee,
 AST_POLYMORPHIC_SUPPORTED_TYPES(BlockPointerType, MemberPointerType,
-PointerType, ReferenceType));
+PointerType, ReferenceType, 
ObjCObjectPointerType));
 
 const internal::VariadicDynCastAllOfMatcher
 ompExecutableDirective;
diff --git a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp 
b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
index 1d18869a6b8afc..adf8749a642fc3 100644
--- a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
@@ -283,6 +283,13 @@ TEST(HasDeclaration, HasDeclarationOfTypeAlias) {
   hasDeclaration(typeAliasTemplateDecl();
 }
 
+TEST(HasDeclaration, HasDeclarationOfObjCInterface) {
+  EXPECT_TRUE(matchesObjC(
+  "@interface BaseClass @end void f() {BaseClass* b;}",
+  varDecl(hasType(objcObjectPointerType(pointee(hasDeclaration(
+  objcInterfaceDecl(;
+}
+
 TEST(HasUnqualifiedDesugaredType, DesugarsUsing) {
   EXPECT_TRUE(
   matches("struct A {}; usin

[clang] [Webkit Checkers] Treat const member variables as a safe origin (PR #115594)

2024-11-14 Thread Rashmi Mudduluru via cfe-commits

https://github.com/t-rasmud approved this pull request.

LGTM!

https://github.com/llvm/llvm-project/pull/115594
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WebKit checkers] Treat ref() and incrementCheckedPtrCount() as trivial (PR #115695)

2024-11-13 Thread Rashmi Mudduluru via cfe-commits

https://github.com/t-rasmud approved this pull request.

LGTM!

https://github.com/llvm/llvm-project/pull/115695
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Webkit Checkers] Treat const member variables as a safe origin (PR #115594)

2024-11-14 Thread Rashmi Mudduluru via cfe-commits


@@ -145,25 +145,36 @@ bool isCtorOfSafePtr(const clang::FunctionDecl *F) {
   return isCtorOfRefCounted(F) || isCtorOfCheckedPtr(F);
 }
 
-bool isSafePtrType(const clang::QualType T) {
+template 
+static bool isPtrOfType(const clang::QualType T, Predicate Pred) {
   QualType type = T;
   while (!type.isNull()) {
 if (auto *elaboratedT = type->getAs()) {
   type = elaboratedT->desugar();
   continue;
 }
 if (auto *specialT = type->getAs()) {
-  if (auto *decl = specialT->getTemplateName().getAsTemplateDecl()) {
-auto name = decl->getNameAsString();
-return isRefType(name) || isCheckedPtr(name);
-  }
+  if (auto *decl = specialT->getTemplateName().getAsTemplateDecl())
+return Pred(decl->getNameAsString());
   return false;
 }
 return false;
   }
   return false;
 }
 
+bool isSafePtrType(const clang::QualType T) {
+  return isPtrOfType(
+  T, [](auto Name) { return isRefType(Name) || isCheckedPtr(Name); });
+}
+
+bool isOwnerPtrType(const clang::QualType T) {
+  return isPtrOfType(T, [](auto Name) {
+return isRefType(Name) || isCheckedPtr(Name) || Name == "unique_ptr" ||
+   Name == "UniqueRef" || Name == "LazyUniqueRef";

t-rasmud wrote:

Out of curiosity: Is this (`UniqueRef` and `LazyUniqueRef`) the exhaustive list 
of additional Webkit defined pointer owner types(I'm assuming)? 

https://github.com/llvm/llvm-project/pull/115594
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Webkit Checkers] Treat const member variables as a safe origin (PR #115594)

2024-11-14 Thread Rashmi Mudduluru via cfe-commits


@@ -0,0 +1,66 @@
+// RUN: %clang_analyze_cc1 
-analyzer-checker=alpha.webkit.UncountedCallArgsChecker -verify %s
+
+#include "mock-types.h"
+
+namespace std {
+}
+
+namespace call_args_const_refptr_member {
+
+class Foo {
+public:
+  Foo();
+  void bar();
+
+private:
+  const RefPtr m_obj1;
+  RefPtr m_obj2;
+};
+
+void Foo::bar() {
+  m_obj1->method();
+  m_obj2->method();
+  // expected-warning@-1{{Call argument for 'this' parameter is uncounted and 
unsafe}}
+}
+
+} // namespace call_args_const_refptr_member
+
+namespace call_args_const_ref_member {
+
+class Foo {
+public:
+  Foo();
+  void bar();
+
+private:
+  const Ref m_obj1;
+  Ref m_obj2;
+};
+
+void Foo::bar() {
+  m_obj1->method();
+  m_obj2->method();
+  // expected-warning@-1{{Call argument for 'this' parameter is uncounted and 
unsafe}}
+}
+
+} // namespace call_args_const_ref_member
+
+namespace call_args_const_unique_ptr {
+
+class Foo {
+public:
+  Foo();
+  void bar();
+
+private:
+  const std::unique_ptr m_obj1;
+  std::unique_ptr m_obj2;
+};
+
+void Foo::bar() {
+  m_obj1->method();
+  m_obj2->method();
+  // expected-warning@-1{{Call argument for 'this' parameter is uncounted and 
unsafe}}
+}
+
+} // namespace call_args_const_unique_ptr

t-rasmud wrote:

Can we also add a test for `unique_ptr` or one of the other hardcoded safe 
types?

https://github.com/llvm/llvm-project/pull/115594
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Webkit Checkers] Treat const member variables as a safe origin (PR #115594)

2024-11-14 Thread Rashmi Mudduluru via cfe-commits


@@ -145,25 +145,36 @@ bool isCtorOfSafePtr(const clang::FunctionDecl *F) {
   return isCtorOfRefCounted(F) || isCtorOfCheckedPtr(F);
 }
 
-bool isSafePtrType(const clang::QualType T) {
+template 
+static bool isPtrOfType(const clang::QualType T, Predicate Pred) {
   QualType type = T;
   while (!type.isNull()) {
 if (auto *elaboratedT = type->getAs()) {
   type = elaboratedT->desugar();
   continue;
 }
 if (auto *specialT = type->getAs()) {
-  if (auto *decl = specialT->getTemplateName().getAsTemplateDecl()) {
-auto name = decl->getNameAsString();
-return isRefType(name) || isCheckedPtr(name);
-  }
+  if (auto *decl = specialT->getTemplateName().getAsTemplateDecl())

t-rasmud wrote:

Can we do an early return here instead of nested `if`s?

https://github.com/llvm/llvm-project/pull/115594
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Webkit Checkers] Introduce a Webkit checker for memory unsafe casts (PR #114606)

2024-12-02 Thread Rashmi Mudduluru via cfe-commits

https://github.com/t-rasmud updated 
https://github.com/llvm/llvm-project/pull/114606

>From cc19550fdbaca4b77e90de57c472a31a8c3f8293 Mon Sep 17 00:00:00 2001
From: Rashmi Mudduluru 
Date: Fri, 1 Nov 2024 14:10:50 -0700
Subject: [PATCH 01/10] [Webkit Checkers] Introduce a Webkit checker for memory
 unsafe casts

The checker warns all downcasts from a base type to a derived type.

rdar://137766829
---
 clang/docs/analyzer/checkers.rst  |  25 +++
 clang/docs/tools/clang-formatted-files.txt|   1 +
 .../clang/StaticAnalyzer/Checkers/Checkers.td |   4 +
 .../StaticAnalyzer/Checkers/CMakeLists.txt|   1 +
 .../WebKit/MemoryUnsafeCastChecker.cpp|  86 ++
 .../Checkers/WebKit/memory-unsafe-cast.cpp| 151 ++
 .../Checkers/WebKit/memory-unsafe-cast.mm |  29 
 7 files changed, 297 insertions(+)
 create mode 100644 
clang/lib/StaticAnalyzer/Checkers/WebKit/MemoryUnsafeCastChecker.cpp
 create mode 100644 clang/test/Analysis/Checkers/WebKit/memory-unsafe-cast.cpp
 create mode 100644 clang/test/Analysis/Checkers/WebKit/memory-unsafe-cast.mm

diff --git a/clang/docs/analyzer/checkers.rst b/clang/docs/analyzer/checkers.rst
index 87b03438e6e0b9..f01755ce7a236a 100644
--- a/clang/docs/analyzer/checkers.rst
+++ b/clang/docs/analyzer/checkers.rst
@@ -3452,6 +3452,31 @@ alpha.WebKit
 
 .. _alpha-webkit-NoUncheckedPtrMemberChecker:
 
+alpha.webkit.MemoryUnsafeCastChecker
+""
+Check for all casts from a base type to its derived type as these might be 
memory-unsafe.
+
+Example:
+
+.. code-block:: cpp
+
+class Base { };
+class Derived : public Base { };
+
+void f(Base* base) {
+Derived* derived = static_cast(base); // ERROR
+}
+
+For all cast operations (C-style casts, static_cast, reinterpret_cast, 
dynamic_cast), if the source type a `Base*` and the destination type is 
`Derived*`, where `Derived` inherits from `Base`, the static analyzer should 
signal an error.
+
+This applies to:
+
+- C structs, C++ structs and classes, and Objective-C classes and protocols.
+- Pointers and references.
+- Inside template instantiations and macro expansions that are visible to the 
compiler.
+
+For types like this, instead of using built in casts, the programmer will use 
helper functions that internally perform the appropriate type check and disable 
static analysis.
+
 alpha.webkit.NoUncheckedPtrMemberChecker
 
 Raw pointers and references to an object which supports CheckedPtr or 
CheckedRef can't be used as class members. Only CheckedPtr, CheckedRef, RefPtr, 
or Ref are allowed.
diff --git a/clang/docs/tools/clang-formatted-files.txt 
b/clang/docs/tools/clang-formatted-files.txt
index 67ff085144f4de..74ab155d6174fd 100644
--- a/clang/docs/tools/clang-formatted-files.txt
+++ b/clang/docs/tools/clang-formatted-files.txt
@@ -537,6 +537,7 @@ 
clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
 clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp
 clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.h
 clang/lib/StaticAnalyzer/Checkers/WebKit/DiagOutputUtils.h
+clang/lib/StaticAnalyzer/Checkers/WebKit/MemoryUnsafeCastChecker.cpp
 clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
 clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
 clang/lib/StaticAnalyzer/Checkers/WebKit/RefCntblBaseVirtualDtorChecker.cpp
diff --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td 
b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
index 9a6b35c1b9f774..445379e88ab9e3 100644
--- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -1752,6 +1752,10 @@ def UncountedLambdaCapturesChecker : 
Checker<"UncountedLambdaCapturesChecker">,
 
 let ParentPackage = WebKitAlpha in {
 
+def MemoryUnsafeCastChecker : Checker<"MemoryUnsafeCastChecker">,
+  HelpText<"Check for memory unsafe casts from base type to derived type.">,
+  Documentation;
+
 def NoUncheckedPtrMemberChecker : Checker<"NoUncheckedPtrMemberChecker">,
   HelpText<"Check for no unchecked member variables.">,
   Documentation;
diff --git a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt 
b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
index 62aa5ff7f002a9..7e987740f9ee2d 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
+++ b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
@@ -132,6 +132,7 @@ add_clang_library(clangStaticAnalyzerCheckers
   VirtualCallChecker.cpp
   WebKit/RawPtrRefMemberChecker.cpp
   WebKit/ASTUtils.cpp
+  WebKit/MemoryUnsafeCastChecker.cpp
   WebKit/PtrTypesSemantics.cpp
   WebKit/RefCntblBaseVirtualDtorChecker.cpp
   WebKit/UncountedCallArgsChecker.cpp
diff --git 
a/clang/lib/StaticAnalyzer/Checkers/WebKit/MemoryUnsafeCastChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/MemoryUnsafeCastChecker.cpp
new file mode 100644
index 00..05a5f89d28c8fe
--- /dev/null
+++ b/clang/lib/StaticAn

[clang] [ASTMatchers] AST matcher support for ObjC pointers (PR #117021)

2024-12-02 Thread Rashmi Mudduluru via cfe-commits

t-rasmud wrote:

Friendly @ping for approval/feedback.

https://github.com/llvm/llvm-project/pull/117021
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Webkit Checkers] Introduce a Webkit checker for memory unsafe casts (PR #114606)

2024-11-13 Thread Rashmi Mudduluru via cfe-commits


@@ -0,0 +1,117 @@
+//===- MemoryUnsafeCastChecker.cpp -*- C++ -*-==//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+// This file defines MemoryUnsafeCast checker, which checks for casts from a
+// base type to a derived type.
+//===--===//
+
+#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/Analysis/AnalysisDeclContext.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+class WalkAST : public StmtVisitor {
+  BugReporter &BR;
+  const CheckerBase *Checker;
+  AnalysisDeclContext* AC;
+  ASTContext &ASTC;
+
+public:
+  WalkAST(BugReporter &br, const CheckerBase *checker, AnalysisDeclContext *ac)
+  : BR(br), Checker(checker), AC(ac), ASTC(AC->getASTContext()) {}
+
+  // Statement visitor methods.
+  void VisitChildren(Stmt *S);
+  void VisitStmt(Stmt *S) { VisitChildren(S); }
+  void VisitCastExpr(CastExpr *CE);
+};
+} // end anonymous namespace
+
+void emitWarning(QualType FromType, QualType ToType,
+ AnalysisDeclContext *AC, BugReporter &BR,
+ const CheckerBase *Checker,
+ CastExpr *CE) {
+  std::string Diagnostics;
+  llvm::raw_string_ostream OS(Diagnostics);
+  OS << "Unsafe cast from base type '"
+ << FromType
+ << "' to derived type '"
+ << ToType
+ << "'",
+
+  BR.EmitBasicReport(
+AC->getDecl(),
+Checker,
+/*Name=*/"Memory unsafe cast",
+categories::SecurityError,
+Diagnostics,
+PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC),
+CE->getSourceRange());
+}
+
+namespace {
+class MemoryUnsafeCastChecker : public Checker {
+  BugType BT{this, ""};
+public:
+  void checkASTCodeBody(const Decl *D, AnalysisManager& Mgr,
+BugReporter &BR) const {
+WalkAST walker(BR, this, Mgr.getAnalysisDeclContext(D));

t-rasmud wrote:

I've updated the patch with AST matchers and added support for matching 
ObjectiveC pointers that was missing earlier.
@haoNoQ @rniwa @devincoughlin 

https://github.com/llvm/llvm-project/pull/114606
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Webkit Checkers] Introduce a Webkit checker for memory unsafe casts (PR #114606)

2024-11-13 Thread Rashmi Mudduluru via cfe-commits

https://github.com/t-rasmud updated 
https://github.com/llvm/llvm-project/pull/114606

>From cc19550fdbaca4b77e90de57c472a31a8c3f8293 Mon Sep 17 00:00:00 2001
From: Rashmi Mudduluru 
Date: Fri, 1 Nov 2024 14:10:50 -0700
Subject: [PATCH 1/6] [Webkit Checkers] Introduce a Webkit checker for memory
 unsafe casts

The checker warns all downcasts from a base type to a derived type.

rdar://137766829
---
 clang/docs/analyzer/checkers.rst  |  25 +++
 clang/docs/tools/clang-formatted-files.txt|   1 +
 .../clang/StaticAnalyzer/Checkers/Checkers.td |   4 +
 .../StaticAnalyzer/Checkers/CMakeLists.txt|   1 +
 .../WebKit/MemoryUnsafeCastChecker.cpp|  86 ++
 .../Checkers/WebKit/memory-unsafe-cast.cpp| 151 ++
 .../Checkers/WebKit/memory-unsafe-cast.mm |  29 
 7 files changed, 297 insertions(+)
 create mode 100644 
clang/lib/StaticAnalyzer/Checkers/WebKit/MemoryUnsafeCastChecker.cpp
 create mode 100644 clang/test/Analysis/Checkers/WebKit/memory-unsafe-cast.cpp
 create mode 100644 clang/test/Analysis/Checkers/WebKit/memory-unsafe-cast.mm

diff --git a/clang/docs/analyzer/checkers.rst b/clang/docs/analyzer/checkers.rst
index 87b03438e6e0b9..f01755ce7a236a 100644
--- a/clang/docs/analyzer/checkers.rst
+++ b/clang/docs/analyzer/checkers.rst
@@ -3452,6 +3452,31 @@ alpha.WebKit
 
 .. _alpha-webkit-NoUncheckedPtrMemberChecker:
 
+alpha.webkit.MemoryUnsafeCastChecker
+""
+Check for all casts from a base type to its derived type as these might be 
memory-unsafe.
+
+Example:
+
+.. code-block:: cpp
+
+class Base { };
+class Derived : public Base { };
+
+void f(Base* base) {
+Derived* derived = static_cast(base); // ERROR
+}
+
+For all cast operations (C-style casts, static_cast, reinterpret_cast, 
dynamic_cast), if the source type a `Base*` and the destination type is 
`Derived*`, where `Derived` inherits from `Base`, the static analyzer should 
signal an error.
+
+This applies to:
+
+- C structs, C++ structs and classes, and Objective-C classes and protocols.
+- Pointers and references.
+- Inside template instantiations and macro expansions that are visible to the 
compiler.
+
+For types like this, instead of using built in casts, the programmer will use 
helper functions that internally perform the appropriate type check and disable 
static analysis.
+
 alpha.webkit.NoUncheckedPtrMemberChecker
 
 Raw pointers and references to an object which supports CheckedPtr or 
CheckedRef can't be used as class members. Only CheckedPtr, CheckedRef, RefPtr, 
or Ref are allowed.
diff --git a/clang/docs/tools/clang-formatted-files.txt 
b/clang/docs/tools/clang-formatted-files.txt
index 67ff085144f4de..74ab155d6174fd 100644
--- a/clang/docs/tools/clang-formatted-files.txt
+++ b/clang/docs/tools/clang-formatted-files.txt
@@ -537,6 +537,7 @@ 
clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
 clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp
 clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.h
 clang/lib/StaticAnalyzer/Checkers/WebKit/DiagOutputUtils.h
+clang/lib/StaticAnalyzer/Checkers/WebKit/MemoryUnsafeCastChecker.cpp
 clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
 clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
 clang/lib/StaticAnalyzer/Checkers/WebKit/RefCntblBaseVirtualDtorChecker.cpp
diff --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td 
b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
index 9a6b35c1b9f774..445379e88ab9e3 100644
--- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -1752,6 +1752,10 @@ def UncountedLambdaCapturesChecker : 
Checker<"UncountedLambdaCapturesChecker">,
 
 let ParentPackage = WebKitAlpha in {
 
+def MemoryUnsafeCastChecker : Checker<"MemoryUnsafeCastChecker">,
+  HelpText<"Check for memory unsafe casts from base type to derived type.">,
+  Documentation;
+
 def NoUncheckedPtrMemberChecker : Checker<"NoUncheckedPtrMemberChecker">,
   HelpText<"Check for no unchecked member variables.">,
   Documentation;
diff --git a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt 
b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
index 62aa5ff7f002a9..7e987740f9ee2d 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
+++ b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
@@ -132,6 +132,7 @@ add_clang_library(clangStaticAnalyzerCheckers
   VirtualCallChecker.cpp
   WebKit/RawPtrRefMemberChecker.cpp
   WebKit/ASTUtils.cpp
+  WebKit/MemoryUnsafeCastChecker.cpp
   WebKit/PtrTypesSemantics.cpp
   WebKit/RefCntblBaseVirtualDtorChecker.cpp
   WebKit/UncountedCallArgsChecker.cpp
diff --git 
a/clang/lib/StaticAnalyzer/Checkers/WebKit/MemoryUnsafeCastChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/MemoryUnsafeCastChecker.cpp
new file mode 100644
index 00..05a5f89d28c8fe
--- /dev/null
+++ b/clang/lib/StaticAnal

[clang] [Webkit Checkers] Introduce a Webkit checker for memory unsafe casts (PR #114606)

2024-12-05 Thread Rashmi Mudduluru via cfe-commits

https://github.com/t-rasmud closed 
https://github.com/llvm/llvm-project/pull/114606
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [webkit.UncountedLambdaCapturesChecker] Fix a bug that the checker didn't take the object pointer into account. (PR #125662)

2025-02-04 Thread Rashmi Mudduluru via cfe-commits

https://github.com/t-rasmud approved this pull request.

LGTM!

https://github.com/llvm/llvm-project/pull/125662
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [webkit.UncountedLambdaCapturesChecker] Fix a regression that [[noescape]] on a member function no longer works. (PR #126016)

2025-02-06 Thread Rashmi Mudduluru via cfe-commits


@@ -63,6 +63,18 @@ template Function 
adopt(Detail::Callab
 return Function(impl, Function::Adopt);
 }
 
+template 
+class HashMap {
+public:
+  HashMap();
+  HashMap([[clang::noescape]] const Function&);

t-rasmud wrote:

Should we also have a similar test case for a non-member function?

https://github.com/llvm/llvm-project/pull/126016
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [webkit.UncountedLambdaCapturesChecker] Fix a regression that [[noescape]] on a member function no longer works. (PR #126016)

2025-02-06 Thread Rashmi Mudduluru via cfe-commits

https://github.com/t-rasmud approved this pull request.

LGTM!

https://github.com/llvm/llvm-project/pull/126016
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WebKit Checkers] Treat const Objective-C ivar as a safe origin (PR #126353)

2025-02-10 Thread Rashmi Mudduluru via cfe-commits


@@ -163,10 +163,13 @@ bool isConstOwnerPtrMemberExpr(const clang::Expr *E) {
 if (OCE->getOperator() == OO_Star && OCE->getNumArgs() == 1)
   E = OCE->getArg(0);
   }
-  auto *ME = dyn_cast(E);
-  if (!ME)
+  const ValueDecl *D = nullptr;
+  if (auto *ME = dyn_cast(E))
+D = ME->getMemberDecl();
+  else if (auto *IVR = dyn_cast(E))
+D = IVR->getDecl();
+  else
 return false;
-  auto *D = ME->getMemberDecl();
   if (!D)

t-rasmud wrote:

Is this check still needed? The `else` clause above should already return if D 
is a nullptr.

https://github.com/llvm/llvm-project/pull/126353
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WebKit Checkers] Treat const Objective-C ivar as a safe origin (PR #126353)

2025-02-10 Thread Rashmi Mudduluru via cfe-commits

https://github.com/t-rasmud deleted 
https://github.com/llvm/llvm-project/pull/126353
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WebKit Checkers] Treat const Objective-C ivar as a safe origin (PR #126353)

2025-02-10 Thread Rashmi Mudduluru via cfe-commits


@@ -163,10 +163,13 @@ bool isConstOwnerPtrMemberExpr(const clang::Expr *E) {
 if (OCE->getOperator() == OO_Star && OCE->getNumArgs() == 1)
   E = OCE->getArg(0);
   }
-  auto *ME = dyn_cast(E);
-  if (!ME)
+  const ValueDecl *D = nullptr;
+  if (auto *ME = dyn_cast(E))
+D = ME->getMemberDecl();
+  else if (auto *IVR = dyn_cast(E))
+D = IVR->getDecl();
+  else
 return false;
-  auto *D = ME->getMemberDecl();
   if (!D)

t-rasmud wrote:

Is this check still needed? The else clause above should already return if D is 
a nullptr.

https://github.com/llvm/llvm-project/pull/126353
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


  1   2   >