[PATCH] D154603: [analyzer][clangsa] Add new option to alpha.security.cert.InvalidPtrChecker

2023-09-29 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 abandoned this revision.
gamesh411 added a comment.

Moving this to GitHub as Phabricator is shutting down. Relevant PR here: 
https://github.com/llvm/llvm-project/pull/67663


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D154603/new/

https://reviews.llvm.org/D154603

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


[PATCH] D154603: [analyzer][clangsa] Add new option to alpha.security.cert.InvalidPtrChecker

2023-09-11 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 marked 2 inline comments as done.
gamesh411 added a comment.

@steakhal gentle ping


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D154603/new/

https://reviews.llvm.org/D154603

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


[PATCH] D154603: [analyzer][clangsa] Add new option to alpha.security.cert.InvalidPtrChecker

2023-09-11 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 updated this revision to Diff 556510.
gamesh411 added a comment.

- use std::string
- simplify tests


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D154603/new/

https://reviews.llvm.org/D154603

Files:
  clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
  clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp
  clang/test/Analysis/analyzer-config.c
  clang/test/Analysis/cert/env34-c-cert-examples.c
  clang/test/Analysis/cert/env34-c.c
  clang/test/Analysis/invalid-ptr-checker.c

Index: clang/test/Analysis/invalid-ptr-checker.c
===
--- /dev/null
+++ clang/test/Analysis/invalid-ptr-checker.c
@@ -0,0 +1,50 @@
+// RUN: %clang_analyze_cc1 \
+// RUN:  -analyzer-checker=alpha.security.cert.env.InvalidPtr \
+// RUN:  -analyzer-config alpha.security.cert.env.InvalidPtr:InvalidatingGetEnv=false \
+// RUN:  -analyzer-output=text -verify -Wno-unused %s
+//
+// RUN: %clang_analyze_cc1 \
+// RUN:  -analyzer-checker=alpha.security.cert.env.InvalidPtr \
+// RUN:  -analyzer-config \
+// RUN: alpha.security.cert.env.InvalidPtr:InvalidatingGetEnv=true \
+// RUN: -analyzer-output=text -verify=expected,pedantic -Wno-unused %s
+
+#include "Inputs/system-header-simulator.h"
+
+char *getenv(const char *name);
+int setenv(const char *name, const char *value, int overwrite);
+int strcmp(const char *, const char *);
+
+int custom_env_handler(const char **envp);
+
+void getenv_after_getenv(void) {
+  char *v1 = getenv("V1");
+  // pedantic-note@-1{{previous function call was here}}
+
+  char *v2 = getenv("V2");
+  // pedantic-note@-1{{'getenv' call may invalidate the result of the previous 'getenv'}}
+
+  strcmp(v1, v2);
+  // pedantic-warning@-1{{use of invalidated pointer 'v1' in a function call}}
+  // pedantic-note@-2{{use of invalidated pointer 'v1' in a function call}}
+}
+
+void setenv_after_getenv(void) {
+  char *v1 = getenv("VAR1");
+
+  setenv("VAR2", "...", 1);
+  // expected-note@-1{{'setenv' call may invalidate the environment returned by getenv}}
+
+  strcmp(v1, "");
+  // expected-warning@-1{{use of invalidated pointer 'v1' in a function call}}
+  // expected-note@-2{{use of invalidated pointer 'v1' in a function call}}
+}
+
+int main(int argc, const char *argv[], const char *envp[]) {
+  setenv("VAR", "...", 0);
+  // expected-note@-1 2 {{'setenv' call may invalidate the environment parameter of 'main'}}
+
+  *envp;
+  // expected-warning@-1 2 {{dereferencing an invalid pointer}}
+  // expected-note@-2 2 {{dereferencing an invalid pointer}}
+}
Index: clang/test/Analysis/cert/env34-c.c
===
--- clang/test/Analysis/cert/env34-c.c
+++ clang/test/Analysis/cert/env34-c.c
@@ -1,5 +1,6 @@
 // RUN: %clang_analyze_cc1 \
 // RUN:  -analyzer-checker=alpha.security.cert.env.InvalidPtr\
+// RUN:  -analyzer-config alpha.security.cert.env.InvalidPtr:InvalidatingGetEnv=true \
 // RUN:  -analyzer-output=text -verify -Wno-unused %s
 
 #include "../Inputs/system-header-simulator.h"
Index: clang/test/Analysis/cert/env34-c-cert-examples.c
===
--- clang/test/Analysis/cert/env34-c-cert-examples.c
+++ clang/test/Analysis/cert/env34-c-cert-examples.c
@@ -1,15 +1,49 @@
+// Default options.
 // RUN: %clang_analyze_cc1 \
 // RUN:  -analyzer-checker=core,alpha.security.cert.env.InvalidPtr \
 // RUN:  -verify -Wno-unused %s
+//
+// Test the laxer handling of getenv function (this is the default).
+// RUN: %clang_analyze_cc1 \
+// RUN:  -analyzer-checker=core,alpha.security.cert.env.InvalidPtr \
+// RUN:  -analyzer-config alpha.security.cert.env.InvalidPtr:InvalidatingGetEnv=false \
+// RUN:  -verify -Wno-unused %s
+//
+// Test the stricter handling of getenv function.
+// RUN: %clang_analyze_cc1 \
+// RUN:  -analyzer-checker=core,alpha.security.cert.env.InvalidPtr \
+// RUN:  -analyzer-config alpha.security.cert.env.InvalidPtr:InvalidatingGetEnv=true \
+// RUN:  -verify=pedantic -Wno-unused %s
 
 #include "../Inputs/system-header-simulator.h"
 char *getenv(const char *name);
+int setenv(const char *name, const char *value, int overwrite);
 int strcmp(const char*, const char*);
 char *strdup(const char*);
 void free(void *memblock);
 void *malloc(size_t size);
 
-void incorrect_usage(void) {
+void incorrect_usage_setenv_getenv_invalidation(void) {
+  char *tmpvar;
+  char *tempvar;
+
+  tmpvar = getenv("TMP");
+
+  if (!tmpvar)
+return;
+
+  setenv("TEMP", "", 1); //setenv can invalidate env
+
+  if (!tmpvar)
+return;
+
+  if (strcmp(tmpvar, "") == 0) { // body of strcmp is unknown
+// expected-warning@-1{{use of invalidated pointer 'tmpvar' in a function call}}
+// pedantic-warning@-2{{use of invalidated pointer 'tmpvar' in a function call}}
+  }
+}
+

[PATCH] D150647: [WIP][analyzer] Fix EnumCastOutOfRangeChecker C++17 handling

2023-09-11 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 abandoned this revision.
gamesh411 added a comment.

This is no longer relevant, as the fix already went in (D153954 
).


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D150647/new/

https://reviews.llvm.org/D150647

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


[PATCH] D154603: [analyzer][clangsa] Add new option to alpha.security.cert.InvalidPtrChecker

2023-08-23 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 added a comment.

In D154603#4609809 , @gamesh411 wrote:

> In D154603#4580609 , @steakhal 
> wrote:
>
>> I'm sorry starting the review of this one only now, but I'm quite booked.
>> Is it still relevant? If so, I'll continue.
>
> Yes, thanks for the effort!

I would like to go through with this option, and then I would like to fix the 
following issues with this checker as well:

- the previous function call notes could be more streamlined
- the notes of this checker are also shown when another checker hits those 
nodes with its report
  - for example taint checker giving a warning to `getenv` usage would also 
trigger the display of the 'previous function call was here' note here), this I 
would like to filter with bug category filters
  - code examples for this filtering are below
- try to consolidate the multiple warnings coming from this checker's 
`checkLocation` callback

category based filtering ( example from 
lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp:167 ):

  If (!BR.isInteresting(CallLocation) ||
BR.getBugType().getCategory() != categories::TaintedData) { //but this 
would be InvalidPtr BugType's category, namely memory_error
return "";
  }

or checker based filtering ( example from 
lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:397 )

  if (() != smartptr::getNullDereferenceBugType() || // this is a 
comparison of the address of a static bugtype
  !BR.isInteresting(ThisRegion))

This second one gives a more precise filtering, but the implementation-specific 
detail of storing the bugtype by reference is what seems to make this work, 
which I find hacky.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D154603/new/

https://reviews.llvm.org/D154603

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


[PATCH] D154603: [analyzer][clangsa] Add new option to alpha.security.cert.InvalidPtrChecker

2023-08-23 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 added a comment.

In D154603#4580609 , @steakhal wrote:

> I'm sorry starting the review of this one only now, but I'm quite booked.
> Is it still relevant? If so, I'll continue.

Yes thanks for the effort!
I would like to go through with this option, and then I would like to fix the 
following issues with this checker as well:

- the previous function call notes could be more streamlined
- the interesting notes are also shown, when another checker hits those nodes 
with its report (for example taint checker giving a warning for getenv would 
also trigger the display of the 'previous function call was here' note here), 
this I would like to filter with bug category filters
- try to consolidate the multiple warnings coming from this checkers 
checkLocation callback


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D154603/new/

https://reviews.llvm.org/D154603

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


[PATCH] D154603: [analyzer][clangsa] Add new option to alpha.security.cert.InvalidPtrChecker

2023-08-23 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 marked 8 inline comments as done.
gamesh411 added inline comments.



Comment at: clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp:116-117
+const NoteTag *Note =
+C.getNoteTag([Region, FunctionName, Message](PathSensitiveBugReport 
,
+ llvm::raw_ostream ) {
+  if (!BR.isInteresting(Region))

steakhal wrote:
> `FunctionName` and `Message` will dangle inside the NoteTag.
Good catch, thanks! Fixed this with a lambda capture initializer.



Comment at: clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp:125
 
-  const NoteTag *Note =
-  C.getNoteTag([SymbolicEnvPtrRegion, FunctionName](
-   PathSensitiveBugReport , llvm::raw_ostream ) {
-if (!BR.isInteresting(SymbolicEnvPtrRegion))
-  return;
-Out << '\'' << FunctionName
-<< "' call may invalidate the environment parameter of 'main'";
-  });
+  ExplodedNode *CurrentChainEnd = nullptr;
+

steakhal wrote:
> donat.nagy wrote:
> > Perhaps add a comment that clarifies that passing a `nullptr` as the 
> > ExplodedNode to `addTransition` is equivalent to specifying the current 
> > node. I remember this because I was studying its implementation recently, 
> > but I would've been surprised and suspicious otherwise.
> If `nullptr` is equivalent with `C.getPredecessor()` inside 
> `addTransition()`, why not simply initialize it to that value instead of to 
> `nullptr`?
I ended up using C.getPredecessor() instead of explaining; this seems a bit 
more intuitive (if such a thing even exists in CSA).



Comment at: clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp:218
+State->add(Call.getReturnValue().getAsRegion());
+   C.addTransition(State);
+  }

steakhal wrote:
> donat.nagy wrote:
> > I fear that this state transition will go "sideways" and the later state 
> > transitions (which add the note tags) will branch off instead of building 
> > onto this. IIUC calling `CheckerContext::addTransition` registers the 
> > transition without updating the "current ExplodedNode" field of 
> > `CheckerContext`, so you need to explicitly store and pass around the 
> > ExplodedNode returned by it if you want to build on it.
> > 
> > This is an ugly and counter-intuitive API, and I also ran into a very 
> > similar issue a few weeks ago (@Szelethus helped me).
> I think the usage here is correct.
(the line number of this comment desync-ed)
I agree, that the addTransition API is easy to misuse, and I would welcome a 
more streamlined approach.
I tried to pay attention to "build" the state and the Exploded Graph by always 
providing the Exploded Node (second parameter), and this seems fine.



Comment at: clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp:44
+  // environment variable buffer. This is implied in the standard, but in
+  // practice does not cause problems (in the commonly used environments).
+  bool InvalidatingGetEnv = false;

Reworded the message here



Comment at: clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp:48
+  // GetEnv can be treated invalidating and non-invalidating as well.
+  const CallDescription GetEnvCall{{"getenv"}, 1};
+

Hoisted here



Comment at: clang/test/Analysis/invalid-ptr-checker.c:51
+
+  *envp;
+  // expected-warning@-1 2 {{dereferencing an invalid pointer}}

This gives 2 warnings. One for subexpression `envp`, and one for the whole 
statement `*envp`. This is the current behaviour ( check 
clang/test/Analysis/cert/env31-c.c ), and this patch does not change it.
However, I would like to devise a solution for this in a different patch.
One option would be to make the error of this checker Fatal, so only one would 
appear, or refine the checkLocation callback to only consider one of these 2 
cases for reporting.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D154603/new/

https://reviews.llvm.org/D154603

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


[PATCH] D154603: [analyzer][clangsa] Add new option to alpha.security.cert.InvalidPtrChecker

2023-08-23 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 updated this revision to Diff 552676.
gamesh411 marked an inline comment as done.
gamesh411 added a comment.

rebased and squashed


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D154603/new/

https://reviews.llvm.org/D154603

Files:
  clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
  clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp
  clang/test/Analysis/analyzer-config.c
  clang/test/Analysis/cert/env34-c-cert-examples.c
  clang/test/Analysis/cert/env34-c.c
  clang/test/Analysis/invalid-ptr-checker.c

Index: clang/test/Analysis/invalid-ptr-checker.c
===
--- /dev/null
+++ clang/test/Analysis/invalid-ptr-checker.c
@@ -0,0 +1,56 @@
+// RUN: %clang_analyze_cc1 \
+// RUN:  -analyzer-checker=alpha.security.cert.env.InvalidPtr \
+// RUN:  -analyzer-config alpha.security.cert.env.InvalidPtr:InvalidatingGetEnv=false \
+// RUN:  -analyzer-output=text -verify -Wno-unused %s
+//
+// RUN: %clang_analyze_cc1 \
+// RUN:  -analyzer-checker=alpha.security.cert.env.InvalidPtr \
+// RUN:  -analyzer-config \
+// RUN: alpha.security.cert.env.InvalidPtr:InvalidatingGetEnv=true \
+// RUN: -analyzer-output=text -verify=pedantic -Wno-unused %s
+
+#include "Inputs/system-header-simulator.h"
+
+char *getenv(const char *name);
+int setenv(const char *name, const char *value, int overwrite);
+int strcmp(const char *, const char *);
+
+int custom_env_handler(const char **envp);
+
+void getenv_after_getenv(void) {
+  char *v1 = getenv("V1");
+  // pedantic-note@-1{{previous function call was here}}
+
+  char *v2 = getenv("V2");
+  // pedantic-note@-1{{'getenv' call may invalidate the result of the previous 'getenv'}}
+
+  strcmp(v1, v2);
+  // pedantic-warning@-1{{use of invalidated pointer 'v1' in a function call}}
+  // pedantic-note@-2{{use of invalidated pointer 'v1' in a function call}}
+}
+
+void setenv_after_getenv(void) {
+  char *v1 = getenv("VAR1");
+
+  setenv("VAR2", "...", 1);
+  // expected-note@-1{{'setenv' call may invalidate the environment returned by getenv}}
+  // pedantic-note@-2{{'setenv' call may invalidate the environment returned by getenv}}
+
+  strcmp(v1, "");
+  // expected-warning@-1{{use of invalidated pointer 'v1' in a function call}}
+  // expected-note@-2{{use of invalidated pointer 'v1' in a function call}}
+  // pedantic-warning@-3{{use of invalidated pointer 'v1' in a function call}}
+  // pedantic-note@-4{{use of invalidated pointer 'v1' in a function call}}
+}
+
+int main(int argc, const char *argv[], const char *envp[]) {
+  setenv("VAR", "...", 0);
+  // expected-note@-1 2 {{'setenv' call may invalidate the environment parameter of 'main'}}
+  // pedantic-note@-2 2 {{'setenv' call may invalidate the environment parameter of 'main'}}
+
+  *envp;
+  // expected-warning@-1 2 {{dereferencing an invalid pointer}}
+  // expected-note@-2 2 {{dereferencing an invalid pointer}}
+  // pedantic-warning@-3 2 {{dereferencing an invalid pointer}}
+  // pedantic-note@-4 2 {{dereferencing an invalid pointer}}
+}
Index: clang/test/Analysis/cert/env34-c.c
===
--- clang/test/Analysis/cert/env34-c.c
+++ clang/test/Analysis/cert/env34-c.c
@@ -1,5 +1,6 @@
 // RUN: %clang_analyze_cc1 \
 // RUN:  -analyzer-checker=alpha.security.cert.env.InvalidPtr\
+// RUN:  -analyzer-config alpha.security.cert.env.InvalidPtr:InvalidatingGetEnv=true \
 // RUN:  -analyzer-output=text -verify -Wno-unused %s
 
 #include "../Inputs/system-header-simulator.h"
Index: clang/test/Analysis/cert/env34-c-cert-examples.c
===
--- clang/test/Analysis/cert/env34-c-cert-examples.c
+++ clang/test/Analysis/cert/env34-c-cert-examples.c
@@ -1,15 +1,49 @@
+// Default options.
 // RUN: %clang_analyze_cc1 \
 // RUN:  -analyzer-checker=core,alpha.security.cert.env.InvalidPtr \
 // RUN:  -verify -Wno-unused %s
+//
+// Test the laxer handling of getenv function (this is the default).
+// RUN: %clang_analyze_cc1 \
+// RUN:  -analyzer-checker=core,alpha.security.cert.env.InvalidPtr \
+// RUN:  -analyzer-config alpha.security.cert.env.InvalidPtr:InvalidatingGetEnv=false \
+// RUN:  -verify -Wno-unused %s
+//
+// Test the stricter handling of getenv function.
+// RUN: %clang_analyze_cc1 \
+// RUN:  -analyzer-checker=core,alpha.security.cert.env.InvalidPtr \
+// RUN:  -analyzer-config alpha.security.cert.env.InvalidPtr:InvalidatingGetEnv=true \
+// RUN:  -verify=pedantic -Wno-unused %s
 
 #include "../Inputs/system-header-simulator.h"
 char *getenv(const char *name);
+int setenv(const char *name, const char *value, int overwrite);
 int strcmp(const char*, const char*);
 char *strdup(const char*);
 void free(void *memblock);
 void *malloc(size_t size);
 
-void incorrect_usage(void) {

[PATCH] D154603: [analyzer][clangsa] Add new option to alpha.security.cert.InvalidPtrChecker

2023-08-23 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 updated this revision to Diff 552670.
gamesh411 added a comment.

Add tests for checker option
Remove unnecessary const_cast
Only model a getenv call if there is a value to model
Use getPredecessor to better indicate what happens during EG building
Hoist GetEnvCall variable
Fix dangling strings in note generation


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D154603/new/

https://reviews.llvm.org/D154603

Files:
  clang/test/Analysis/cert/env34-c.c
  clang/test/Analysis/invalid-ptr-checker.c


Index: clang/test/Analysis/invalid-ptr-checker.c
===
--- /dev/null
+++ clang/test/Analysis/invalid-ptr-checker.c
@@ -0,0 +1,56 @@
+// RUN: %clang_analyze_cc1 \
+// RUN:  -analyzer-checker=alpha.security.cert.env.InvalidPtr \
+// RUN:  -analyzer-config 
alpha.security.cert.env.InvalidPtr:InvalidatingGetEnv=false \
+// RUN:  -analyzer-output=text -verify -Wno-unused %s
+//
+// RUN: %clang_analyze_cc1 \
+// RUN:  -analyzer-checker=alpha.security.cert.env.InvalidPtr \
+// RUN:  -analyzer-config \
+// RUN: alpha.security.cert.env.InvalidPtr:InvalidatingGetEnv=true \
+// RUN: -analyzer-output=text -verify=pedantic -Wno-unused %s
+
+#include "Inputs/system-header-simulator.h"
+
+char *getenv(const char *name);
+int setenv(const char *name, const char *value, int overwrite);
+int strcmp(const char *, const char *);
+
+int custom_env_handler(const char **envp);
+
+void getenv_after_getenv(void) {
+  char *v1 = getenv("V1");
+  // pedantic-note@-1{{previous function call was here}}
+
+  char *v2 = getenv("V2");
+  // pedantic-note@-1{{'getenv' call may invalidate the result of the previous 
'getenv'}}
+
+  strcmp(v1, v2);
+  // pedantic-warning@-1{{use of invalidated pointer 'v1' in a function call}}
+  // pedantic-note@-2{{use of invalidated pointer 'v1' in a function call}}
+}
+
+void setenv_after_getenv(void) {
+  char *v1 = getenv("VAR1");
+
+  setenv("VAR2", "...", 1);
+  // expected-note@-1{{'setenv' call may invalidate the environment returned 
by getenv}}
+  // pedantic-note@-2{{'setenv' call may invalidate the environment returned 
by getenv}}
+
+  strcmp(v1, "");
+  // expected-warning@-1{{use of invalidated pointer 'v1' in a function call}}
+  // expected-note@-2{{use of invalidated pointer 'v1' in a function call}}
+  // pedantic-warning@-3{{use of invalidated pointer 'v1' in a function call}}
+  // pedantic-note@-4{{use of invalidated pointer 'v1' in a function call}}
+}
+
+int main(int argc, const char *argv[], const char *envp[]) {
+  setenv("VAR", "...", 0);
+  // expected-note@-1 2 {{'setenv' call may invalidate the environment 
parameter of 'main'}}
+  // pedantic-note@-2 2 {{'setenv' call may invalidate the environment 
parameter of 'main'}}
+
+  *envp;
+  // expected-warning@-1 2 {{dereferencing an invalid pointer}}
+  // expected-note@-2 2 {{dereferencing an invalid pointer}}
+  // pedantic-warning@-3 2 {{dereferencing an invalid pointer}}
+  // pedantic-note@-4 2 {{dereferencing an invalid pointer}}
+}
Index: clang/test/Analysis/cert/env34-c.c
===
--- clang/test/Analysis/cert/env34-c.c
+++ clang/test/Analysis/cert/env34-c.c
@@ -2,10 +2,6 @@
 // RUN:  -analyzer-checker=alpha.security.cert.env.InvalidPtr\
 // RUN:  -analyzer-config 
alpha.security.cert.env.InvalidPtr:InvalidatingGetEnv=true \
 // RUN:  -analyzer-output=text -verify -Wno-unused %s
-//
-// TODO: write test cases that follow the pattern:
-//   "getenv -> store pointer -> setenv -> use stored pointer"
-//   and not rely solely on getenv as an invalidating function
 
 #include "../Inputs/system-header-simulator.h"
 char *getenv(const char *name);


Index: clang/test/Analysis/invalid-ptr-checker.c
===
--- /dev/null
+++ clang/test/Analysis/invalid-ptr-checker.c
@@ -0,0 +1,56 @@
+// RUN: %clang_analyze_cc1 \
+// RUN:  -analyzer-checker=alpha.security.cert.env.InvalidPtr \
+// RUN:  -analyzer-config alpha.security.cert.env.InvalidPtr:InvalidatingGetEnv=false \
+// RUN:  -analyzer-output=text -verify -Wno-unused %s
+//
+// RUN: %clang_analyze_cc1 \
+// RUN:  -analyzer-checker=alpha.security.cert.env.InvalidPtr \
+// RUN:  -analyzer-config \
+// RUN: alpha.security.cert.env.InvalidPtr:InvalidatingGetEnv=true \
+// RUN: -analyzer-output=text -verify=pedantic -Wno-unused %s
+
+#include "Inputs/system-header-simulator.h"
+
+char *getenv(const char *name);
+int setenv(const char *name, const char *value, int overwrite);
+int strcmp(const char *, const char *);
+
+int custom_env_handler(const char **envp);
+
+void getenv_after_getenv(void) {
+  char *v1 = getenv("V1");
+  // pedantic-note@-1{{previous function call was here}}
+
+  char *v2 = getenv("V2");
+  // pedantic-note@-1{{'getenv' call may invalidate the result of the previous 'getenv'}}
+
+  strcmp(v1, v2);
+  // pedantic-warning@-1{{use of 

[PATCH] D157104: [analyzer] Improve underflow handling in ArrayBoundV2

2023-08-10 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 accepted this revision.
gamesh411 added a comment.
This revision is now accepted and ready to land.

Seems like a straightforward extension, LGTM.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D157104/new/

https://reviews.llvm.org/D157104

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


[PATCH] D153954: [clang][analyzer] Fix empty enum handling in EnumCastOutOfRange checker

2023-08-09 Thread Endre Fülöp via Phabricator via cfe-commits
This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rG90c1f51c4b3e: [clang][analyzer] Fix empty enum handling in 
EnumCastOutOfRange checker (authored by gamesh411).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D153954/new/

https://reviews.llvm.org/D153954

Files:
  clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp
  clang/test/Analysis/enum-cast-out-of-range.cpp


Index: clang/test/Analysis/enum-cast-out-of-range.cpp
===
--- clang/test/Analysis/enum-cast-out-of-range.cpp
+++ clang/test/Analysis/enum-cast-out-of-range.cpp
@@ -198,3 +198,20 @@
   s.E = static_cast(4); // OK.
   s.E = static_cast(5); // expected-warning {{The 
value provided to the cast expression is not in the valid range of values for 
the enum}}
 }
+
+
+enum class empty_unspecified {};
+
+enum class empty_specified: char {};
+
+enum class empty_specified_unsigned: unsigned char {};
+
+void ignore_unused(...);
+
+void empty_enums_init_with_zero_should_not_warn() {
+  auto eu = static_cast(0); //should always be OK to zero 
initialize any enum
+  auto ef = static_cast(0);
+  auto efu = static_cast(0);
+
+  ignore_unused(eu, ef, efu);
+}
Index: clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp
@@ -129,6 +129,14 @@
   const EnumDecl *ED = T->castAs()->getDecl();
 
   EnumValueVector DeclValues = getDeclValuesForEnum(ED);
+
+  // If the declarator list is empty, bail out.
+  // Every initialization an enum with a fixed underlying type but without any
+  // enumerators would produce a warning if we were to continue at this point.
+  // The most notable example is std::byte in the C++17 standard library.
+  if (DeclValues.size() == 0)
+return;
+
   // Check if any of the enum values possibly match.
   bool PossibleValueMatch = llvm::any_of(
   DeclValues, ConstraintBasedEQEvaluator(C, *ValueToCast));


Index: clang/test/Analysis/enum-cast-out-of-range.cpp
===
--- clang/test/Analysis/enum-cast-out-of-range.cpp
+++ clang/test/Analysis/enum-cast-out-of-range.cpp
@@ -198,3 +198,20 @@
   s.E = static_cast(4); // OK.
   s.E = static_cast(5); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}}
 }
+
+
+enum class empty_unspecified {};
+
+enum class empty_specified: char {};
+
+enum class empty_specified_unsigned: unsigned char {};
+
+void ignore_unused(...);
+
+void empty_enums_init_with_zero_should_not_warn() {
+  auto eu = static_cast(0); //should always be OK to zero initialize any enum
+  auto ef = static_cast(0);
+  auto efu = static_cast(0);
+
+  ignore_unused(eu, ef, efu);
+}
Index: clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp
@@ -129,6 +129,14 @@
   const EnumDecl *ED = T->castAs()->getDecl();
 
   EnumValueVector DeclValues = getDeclValuesForEnum(ED);
+
+  // If the declarator list is empty, bail out.
+  // Every initialization an enum with a fixed underlying type but without any
+  // enumerators would produce a warning if we were to continue at this point.
+  // The most notable example is std::byte in the C++17 standard library.
+  if (DeclValues.size() == 0)
+return;
+
   // Check if any of the enum values possibly match.
   bool PossibleValueMatch = llvm::any_of(
   DeclValues, ConstraintBasedEQEvaluator(C, *ValueToCast));
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D153954: [clang][analyzer] Fix empty enum handling in EnumCastOutOfRange checker

2023-08-09 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 updated this revision to Diff 548593.
gamesh411 added a comment.

minor review fixups


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D153954/new/

https://reviews.llvm.org/D153954

Files:
  clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp
  clang/test/Analysis/enum-cast-out-of-range.cpp


Index: clang/test/Analysis/enum-cast-out-of-range.cpp
===
--- clang/test/Analysis/enum-cast-out-of-range.cpp
+++ clang/test/Analysis/enum-cast-out-of-range.cpp
@@ -198,3 +198,20 @@
   s.E = static_cast(4); // OK.
   s.E = static_cast(5); // expected-warning {{The 
value provided to the cast expression is not in the valid range of values for 
the enum}}
 }
+
+
+enum class empty_unspecified {};
+
+enum class empty_specified: char {};
+
+enum class empty_specified_unsigned: unsigned char {};
+
+void ignore_unused(...);
+
+void empty_enums_init_with_zero_should_not_warn() {
+  auto eu = static_cast(0); //should always be OK to zero 
initialize any enum
+  auto ef = static_cast(0);
+  auto efu = static_cast(0);
+
+  ignore_unused(eu, ef, efu);
+}
Index: clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp
@@ -129,6 +129,14 @@
   const EnumDecl *ED = T->castAs()->getDecl();
 
   EnumValueVector DeclValues = getDeclValuesForEnum(ED);
+
+  // If the declarator list is empty, bail out.
+  // Every initialization an enum with a fixed underlying type but without any
+  // enumerators would produce a warning if we were to continue at this point.
+  // The most notable example is std::byte in the C++17 standard library.
+  if (DeclValues.size() == 0)
+return;
+
   // Check if any of the enum values possibly match.
   bool PossibleValueMatch = llvm::any_of(
   DeclValues, ConstraintBasedEQEvaluator(C, *ValueToCast));


Index: clang/test/Analysis/enum-cast-out-of-range.cpp
===
--- clang/test/Analysis/enum-cast-out-of-range.cpp
+++ clang/test/Analysis/enum-cast-out-of-range.cpp
@@ -198,3 +198,20 @@
   s.E = static_cast(4); // OK.
   s.E = static_cast(5); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}}
 }
+
+
+enum class empty_unspecified {};
+
+enum class empty_specified: char {};
+
+enum class empty_specified_unsigned: unsigned char {};
+
+void ignore_unused(...);
+
+void empty_enums_init_with_zero_should_not_warn() {
+  auto eu = static_cast(0); //should always be OK to zero initialize any enum
+  auto ef = static_cast(0);
+  auto efu = static_cast(0);
+
+  ignore_unused(eu, ef, efu);
+}
Index: clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp
@@ -129,6 +129,14 @@
   const EnumDecl *ED = T->castAs()->getDecl();
 
   EnumValueVector DeclValues = getDeclValuesForEnum(ED);
+
+  // If the declarator list is empty, bail out.
+  // Every initialization an enum with a fixed underlying type but without any
+  // enumerators would produce a warning if we were to continue at this point.
+  // The most notable example is std::byte in the C++17 standard library.
+  if (DeclValues.size() == 0)
+return;
+
   // Check if any of the enum values possibly match.
   bool PossibleValueMatch = llvm::any_of(
   DeclValues, ConstraintBasedEQEvaluator(C, *ValueToCast));
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D156312: [analyzer] Upstream BitwiseShiftChecker

2023-07-31 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 added a comment.

I like this, especially, that the functionality of UBOR can be merged and 
extended in a much cleaner way (architecturally).




Comment at: clang/lib/StaticAnalyzer/Checkers/BitwiseShiftChecker.cpp:301-302
+  pluralSuffix(MaximalAllowedShift));
+R->addNote(LeftNote, PathDiagnosticLocation{LHS, Ctx.getSourceManager(),
+Ctx.getLocationContext()});
+Ctx.emitReport(std::move(R));

donat.nagy wrote:
> NoQ wrote:
> > Can we just append this to the warning? The `addNote()` is useful for notes 
> > that need to be placed in code outside of the execution path, but if it's 
> > always next to the warning, it probably doesn't make sense to display it 
> > separately.
> I didn't append this to the warning because I felt that the warning text is 
> already too long. (By the way, an earlier internal variant of this checker 
> produced two separate notes next to the warning message.)
> 
> I tweaked the messages of this checker before initiating this review, but I 
> feel that there's still some room for improvements. (E.g. in this particular 
> case perhaps we could omit some of the details that are not immediately 
> useful and could be manually calculated from other parts of the message...) 
Just a thought on simplifying the diagnostics a bit:

Warning: "Right operand is negative in left shift"
Note: "The result of left shift is undefined because the right operand is 
negative"
Shortened: "Undefined left shift due to negative right operand"

Warning: "Left shift by '34' overflows the capacity of 'int'"
Note: "The result of left shift is undefined because the right operand '34' is 
not smaller than 32, the capacity of 'int'"
Shortened: "Undefined left shift: '34' exceeds 'int' capacity (32 bits)"

The more complex notes are a bit sketchy, as relevant information can be lost, 
and the following solution is probably a bit too much, but could prove to be an 
inspiration:

Warning: "Left shift of '1024' overflows the capacity of 'int'"
CXX Note: "Left shift of '1024' is undefined because 'int' can hold only 32 
bits (including the sign bit), so some bits overflow"
CXX Note: "The value '1024' is represented by 11 bits, allowing at most 21 bits 
for bitshift"
C Note: "Left shift of '1024' is undefined because 'int' can hold only 31 bits 
(excluding the sign bit), so some bits overflow"
C Note: "The value '1024' is represented by 11 bits, allowing at most 20 bits 
for bitshift"

Shortened:
CXX Warning: "Undefined left shift: '1024' (11 bits) exceeds 'int' capacity (32 
bits, including sign)"
C Warning: "Undefined left shift: '1024' (11 bits) exceeds 'int' capacity (31 
bits, excluding sign)"


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D156312/new/

https://reviews.llvm.org/D156312

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


[PATCH] D153954: [WIP][clang][analyzer] Relax alpha.cplusplus.EnumCastOutOfRange checker

2023-07-24 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 marked 4 inline comments as done.
gamesh411 added a comment.

In D153954#4456713 , @shafik wrote:

> I did not look at this in detail but I don't think this approach is correct. 
> I fixed this for constant evaluation the other day and you can find the 
> details here: D130058 
>
> The test suite I wrote should be sufficient for you to validate your approach 
> against.

@shafik, @donat.nagy  Thanks for looking at this patch.
I have checked the linked improvements in Sema, and this initial modification 
would only lead to a ClangSA implementation of the same error-detection logic.
Due to symbolic execution, the set of potentially detectable errors is bigger, 
but this is maybe not the right place for this checker.

My goal is to improve the checker and eventually bring it out of alpha.

I see one main problem with this checker:

It does not support enums with fixed underlying type, namely `std::byte`, which 
is implemented like this:

  enum class byte: unsigned char {};

As `std::byte` has no enumerators, the checker would say any otherwise allowed 
non-default initialization of a std::byte instance is bad, i.e.:

  std::byte b {42}; // the checker gives a warning for this

Aside from this, in the `optin` package, there is a place for the current state 
of the checker (namely that only the value mentioned in the enumerator list are 
OK).
I will create a separate patch to move it out of alpha and into `optin` package.




Comment at: clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp:42
+class RangeBasedValueMatchEvaluator : ValueMatchEvaluator {
+  llvm::APSInt Min, Max;
 

steakhal wrote:
> I can see `llvm::APSInt` used a few places. Consider `using namespace llvm;`
Again, good point, I just abandoned the direction where many APSInt mentions 
are introduced, and the original only has 2 mentions of APSInt.



Comment at: 
clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp:65-69
+  if (TrueState && !FalseState) {
+Pred = C.addTransition(TrueState, Pred);
+  } else if (FalseState && !TrueState) {
+Pred = C.addTransition(FalseState, Pred);
+  }

steakhal wrote:
> Why do you fold the "Pred" ExplodedNode?
> I'd say, you probably didn't want to use `addTransition` here.
> Why don't you assume the subsequent assumptions and transition only once?
> 
> Anyway, I think it's better to have the `addTransition` closer to the outer 
> scope (where the error reporting is done), so that we can easily see how many 
> ways we branch off, etc.
Thanks! This is a very good point; I just changed the general direction of the 
checker, and this implementation is no longer touched by the change.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D153954/new/

https://reviews.llvm.org/D153954

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


[PATCH] D153954: [WIP][clang][analyzer] Relax alpha.cplusplus.EnumCastOutOfRange checker

2023-07-24 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 updated this revision to Diff 543413.
gamesh411 edited the summary of this revision.
gamesh411 added a comment.

The checker now retains the original detection logic, but only whitelists empty
enums.

As a future step the checker is moved into the optin package.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D153954/new/

https://reviews.llvm.org/D153954

Files:
  clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp
  clang/test/Analysis/enum-cast-out-of-range.cpp


Index: clang/test/Analysis/enum-cast-out-of-range.cpp
===
--- clang/test/Analysis/enum-cast-out-of-range.cpp
+++ clang/test/Analysis/enum-cast-out-of-range.cpp
@@ -198,3 +198,20 @@
   s.E = static_cast(4); // OK.
   s.E = static_cast(5); // expected-warning {{The 
value provided to the cast expression is not in the valid range of values for 
the enum}}
 }
+
+
+enum class empty_unfixed {};
+
+enum class empty_fixed: char {};
+
+enum class empty_fixed_unsigned: unsigned char {};
+
+void ignore_unused(...);
+
+void empty_enums_init_with_zero_should_not_warn() {
+  empty_unfixed eu = static_cast(0); //should always be OK to 
zero initialize any enum
+  empty_fixed ef = static_cast(0);
+  empty_fixed_unsigned efu = static_cast(0);
+
+  ignore_unused(eu, ef, efu);
+}
Index: clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp
@@ -129,6 +129,14 @@
   const EnumDecl *ED = T->castAs()->getDecl();
 
   EnumValueVector DeclValues = getDeclValuesForEnum(ED);
+
+  // If the declarator list is empty, bail out.
+  // Every initialization an enum with a fixed underlying type but without any
+  // enumerators would produce a warning if we were to continue at this point.
+  // The most notable example is std::byte in the C++17 standard library.
+  if (DeclValues.size() == 0)
+return;
+
   // Check if any of the enum values possibly match.
   bool PossibleValueMatch = llvm::any_of(
   DeclValues, ConstraintBasedEQEvaluator(C, *ValueToCast));


Index: clang/test/Analysis/enum-cast-out-of-range.cpp
===
--- clang/test/Analysis/enum-cast-out-of-range.cpp
+++ clang/test/Analysis/enum-cast-out-of-range.cpp
@@ -198,3 +198,20 @@
   s.E = static_cast(4); // OK.
   s.E = static_cast(5); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}}
 }
+
+
+enum class empty_unfixed {};
+
+enum class empty_fixed: char {};
+
+enum class empty_fixed_unsigned: unsigned char {};
+
+void ignore_unused(...);
+
+void empty_enums_init_with_zero_should_not_warn() {
+  empty_unfixed eu = static_cast(0); //should always be OK to zero initialize any enum
+  empty_fixed ef = static_cast(0);
+  empty_fixed_unsigned efu = static_cast(0);
+
+  ignore_unused(eu, ef, efu);
+}
Index: clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp
@@ -129,6 +129,14 @@
   const EnumDecl *ED = T->castAs()->getDecl();
 
   EnumValueVector DeclValues = getDeclValuesForEnum(ED);
+
+  // If the declarator list is empty, bail out.
+  // Every initialization an enum with a fixed underlying type but without any
+  // enumerators would produce a warning if we were to continue at this point.
+  // The most notable example is std::byte in the C++17 standard library.
+  if (DeclValues.size() == 0)
+return;
+
   // Check if any of the enum values possibly match.
   bool PossibleValueMatch = llvm::any_of(
   DeclValues, ConstraintBasedEQEvaluator(C, *ValueToCast));
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D154603: [analyzer][clangsa] Add new option to alpha.security.cert.InvalidPtrChecker

2023-07-06 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 added inline comments.



Comment at: clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp:95
 // Stores the region of the environment pointer of 'main' (if present).
-REGISTER_TRAIT_WITH_PROGRAMSTATE(EnvPtrRegion, const MemRegion *)
+REGISTER_TRAIT_WITH_PROGRAMSTATE(MainEnvPtrRegion, const MemRegion *)
+

The state modelling is refined to model the env region coming from the main 
function and the getenv calls.



Comment at: clang/test/Analysis/cert/env34-c.c:6
+//
+// TODO: write test cases that follow the pattern:
+//   "getenv -> store pointer -> setenv -> use stored pointer"

This test file is incomplete.
I would welcome suggestions here as to how to test this.
Should a new file be created for the config option with different test cases, 
or is this file to be extended?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D154603/new/

https://reviews.llvm.org/D154603

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


[PATCH] D154603: [analyzer][clangsa] Add new option to alpha.security.cert.InvalidPtrChecker

2023-07-06 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 created this revision.
Herald added subscribers: steakhal, manas, ASDenysPetrov, martong, dkrupp, 
donat.nagy, Szelethus, mikhail.ramalho, a.sidorin, szepet, baloghadamsoftware, 
xazax.hun.
Herald added a reviewer: Szelethus.
Herald added a reviewer: NoQ.
Herald added a project: All.
gamesh411 requested review of this revision.
Herald added subscribers: cfe-commits, wangpc.
Herald added a project: clang.

The invalidation of pointer pointers returned by subsequent calls to genenv is
suggested by the POSIX standard, but is too strict from a practical point of
view. A new checker option 'InvalidatingGetEnv' is introduced, and is set to a
more lax default value, which does not consider consecutive getenv calls
invalidating.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D154603

Files:
  clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
  clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp
  clang/test/Analysis/analyzer-config.c
  clang/test/Analysis/cert/env34-c-cert-examples.c
  clang/test/Analysis/cert/env34-c.c

Index: clang/test/Analysis/cert/env34-c.c
===
--- clang/test/Analysis/cert/env34-c.c
+++ clang/test/Analysis/cert/env34-c.c
@@ -1,6 +1,11 @@
 // RUN: %clang_analyze_cc1 \
 // RUN:  -analyzer-checker=alpha.security.cert.env.InvalidPtr\
+// RUN:  -analyzer-config alpha.security.cert.env.InvalidPtr:InvalidatingGetEnv=true \
 // RUN:  -analyzer-output=text -verify -Wno-unused %s
+//
+// TODO: write test cases that follow the pattern:
+//   "getenv -> store pointer -> setenv -> use stored pointer"
+//   and not rely solely on getenv as an invalidating function
 
 #include "../Inputs/system-header-simulator.h"
 char *getenv(const char *name);
Index: clang/test/Analysis/cert/env34-c-cert-examples.c
===
--- clang/test/Analysis/cert/env34-c-cert-examples.c
+++ clang/test/Analysis/cert/env34-c-cert-examples.c
@@ -1,15 +1,49 @@
+// Default options.
 // RUN: %clang_analyze_cc1 \
 // RUN:  -analyzer-checker=core,alpha.security.cert.env.InvalidPtr \
 // RUN:  -verify -Wno-unused %s
+//
+// Test the laxer handling of getenv function (this is the default).
+// RUN: %clang_analyze_cc1 \
+// RUN:  -analyzer-checker=core,alpha.security.cert.env.InvalidPtr \
+// RUN:  -analyzer-config alpha.security.cert.env.InvalidPtr:InvalidatingGetEnv=false \
+// RUN:  -verify -Wno-unused %s
+//
+// Test the stricter handling of getenv function.
+// RUN: %clang_analyze_cc1 \
+// RUN:  -analyzer-checker=core,alpha.security.cert.env.InvalidPtr \
+// RUN:  -analyzer-config alpha.security.cert.env.InvalidPtr:InvalidatingGetEnv=true \
+// RUN:  -verify=pedantic -Wno-unused %s
 
 #include "../Inputs/system-header-simulator.h"
 char *getenv(const char *name);
+int setenv(const char *name, const char *value, int overwrite);
 int strcmp(const char*, const char*);
 char *strdup(const char*);
 void free(void *memblock);
 void *malloc(size_t size);
 
-void incorrect_usage(void) {
+void incorrect_usage_setenv_getenv_invalidation(void) {
+  char *tmpvar;
+  char *tempvar;
+
+  tmpvar = getenv("TMP");
+
+  if (!tmpvar)
+return;
+
+  setenv("TEMP", "", 1); //setenv can invalidate env
+
+  if (!tmpvar)
+return;
+
+  if (strcmp(tmpvar, "") == 0) { // body of strcmp is unknown
+// expected-warning@-1{{use of invalidated pointer 'tmpvar' in a function call}}
+// pedantic-warning@-2{{use of invalidated pointer 'tmpvar' in a function call}}
+  }
+}
+
+void incorrect_usage_double_getenv_invalidation(void) {
   char *tmpvar;
   char *tempvar;
 
@@ -18,13 +52,13 @@
   if (!tmpvar)
 return;
 
-  tempvar = getenv("TEMP");
+  tempvar = getenv("TEMP"); //getenv should not invalidate env in non-pedantic mode
 
   if (!tempvar)
 return;
 
   if (strcmp(tmpvar, tempvar) == 0) { // body of strcmp is unknown
-// expected-warning@-1{{use of invalidated pointer 'tmpvar' in a function call}}
+// pedantic-warning@-1{{use of invalidated pointer 'tmpvar' in a function call}}
   }
 }
 
Index: clang/test/Analysis/analyzer-config.c
===
--- clang/test/Analysis/analyzer-config.c
+++ clang/test/Analysis/analyzer-config.c
@@ -11,6 +11,7 @@
 // CHECK-NEXT: alpha.osx.cocoa.DirectIvarAssignment:AnnotatedFunctions = false
 // CHECK-NEXT: alpha.security.MmapWriteExec:MmapProtExec = 0x04
 // CHECK-NEXT: alpha.security.MmapWriteExec:MmapProtRead = 0x01
+// CHECK-NEXT: alpha.security.cert.env.InvalidPtr:InvalidatingGetEnv = false
 // CHECK-NEXT: alpha.security.taint.TaintPropagation:Config = ""
 // CHECK-NEXT: alpha.unix.Errno:AllowErrnoReadOutsideConditionExpressions = true
 // CHECK-NEXT: alpha.unix.StdCLibraryFunctions:DisplayLoadedSummaries = false
Index: 

[PATCH] D153954: Relax alpha.cplusplusEnumCastOutOfRange This checker previously gave many false positives, because only the enum

2023-06-28 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 created this revision.
Herald added subscribers: steakhal, martong, Szelethus, dkrupp.
Herald added a reviewer: Szelethus.
Herald added a reviewer: NoQ.
Herald added a project: All.
gamesh411 requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Modify EnumCastOutOfRange implementation


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D153954

Files:
  clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp
  clang/test/Analysis/enum-cast-out-of-range.c
  clang/test/Analysis/enum-cast-out-of-range.cpp

Index: clang/test/Analysis/enum-cast-out-of-range.cpp
===
--- clang/test/Analysis/enum-cast-out-of-range.cpp
+++ clang/test/Analysis/enum-cast-out-of-range.cpp
@@ -2,199 +2,45 @@
 // RUN:   -analyzer-checker=core,alpha.cplusplus.EnumCastOutOfRange \
 // RUN:   -std=c++11 -verify %s
 
-enum unscoped_unspecified_t {
-  unscoped_unspecified_0 = -4,
-  unscoped_unspecified_1,
-  unscoped_unspecified_2 = 1,
-  unscoped_unspecified_3,
-  unscoped_unspecified_4 = 4
-};
+#define UINT_MAX (~0U)
+#define INT_MAX (int)(UINT_MAX & (UINT_MAX >> 1))
 
-enum unscoped_specified_t : int {
-  unscoped_specified_0 = -4,
-  unscoped_specified_1,
-  unscoped_specified_2 = 1,
-  unscoped_specified_3,
-  unscoped_specified_4 = 4
-};
+enum unscoped_specified_t : unsigned char;
 
-enum class scoped_unspecified_t {
-  scoped_unspecified_0 = -4,
-  scoped_unspecified_1,
-  scoped_unspecified_2 = 1,
-  scoped_unspecified_3,
-  scoped_unspecified_4 = 4
-};
-
-enum class scoped_specified_t : int {
-  scoped_specified_0 = -4,
-  scoped_specified_1,
-  scoped_specified_2 = 1,
-  scoped_specified_3,
-  scoped_specified_4 = 4
-};
-
-struct S {
-  unscoped_unspecified_t E : 5;
-};
-
-void unscopedUnspecified() {
-  unscoped_unspecified_t InvalidBeforeRangeBegin = static_cast(-5); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}}
-  unscoped_unspecified_t ValidNegativeValue1 = static_cast(-4); // OK.
-  unscoped_unspecified_t ValidNegativeValue2 = static_cast(-3); // OK.
-  unscoped_unspecified_t InvalidInsideRange1 = static_cast(-2); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}}
-  unscoped_unspecified_t InvalidInsideRange2 = static_cast(-1); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}}
-  unscoped_unspecified_t InvalidInsideRange3 = static_cast(0); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}}
-  unscoped_unspecified_t ValidPositiveValue1 = static_cast(1); // OK.
-  unscoped_unspecified_t ValidPositiveValue2 = static_cast(2); // OK.
-  unscoped_unspecified_t InvalidInsideRange4 = static_cast(3); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}}
-  unscoped_unspecified_t ValidPositiveValue3 = static_cast(4); // OK.
-  unscoped_unspecified_t InvalidAfterRangeEnd = static_cast(5); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}}
-}
+enum class scoped_specified_t : unsigned char;
 
 void unscopedSpecified() {
-  unscoped_specified_t InvalidBeforeRangeBegin = static_cast(-5); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}}
-  unscoped_specified_t ValidNegativeValue1 = static_cast(-4); // OK.
-  unscoped_specified_t ValidNegativeValue2 = static_cast(-3); // OK.
-  unscoped_specified_t InvalidInsideRange1 = static_cast(-2); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}}
-  unscoped_specified_t InvalidInsideRange2 = static_cast(-1); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}}
-  unscoped_specified_t InvalidInsideRange3 = static_cast(0); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}}
-  unscoped_specified_t ValidPositiveValue1 = static_cast(1); // OK.
-  unscoped_specified_t ValidPositiveValue2 = static_cast(2); // OK.
-  unscoped_specified_t InvalidInsideRange4 = static_cast(3); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}}
-  unscoped_specified_t ValidPositiveValue3 = static_cast(4); // OK.
-  unscoped_specified_t InvalidAfterRangeEnd = static_cast(5); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}}
-}
+  auto InvalidBeforeRangeBegin = static_cast(-1); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}}
+  auto Zero = static_cast(0); // 

[PATCH] D150647: [WIP][analyzer] Fix EnumCastOutOfRangeChecker C++17 handling

2023-05-16 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 added a comment.

In D150647#4345345 , @steakhal wrote:

>> In C++17 the initialization rules for enum classes are relaxed.
>
> In what way are they relaxed compared to regular enums?

The initialization rules are relaxed compared to their pre-C++17 state, so now 
there is a possibility of an initialization for enum classes without explicitly 
mentioning the underlying type.
I have updated the revision body.

That all being said, there is another fundamental issue with this checker, 
namely that the possible value range is I think restricted to the ones 
explicitly mentioned in the enumerators.
For example in the std::byte case even the old way of initializing gives a 
false positive.
I am investigating the issue, and have found so far, that fixed 
underlying-typed and non-fixed underlying-typed enums behave differently, which 
is not considered in the checker code.

Relevant info dump for future quoting:
https://eel.is/c++draft/dcl.enum#5
https://eel.is/c++draft/dcl.enum#7
https://eel.is/c++draft/dcl.enum#8
https://eel.is/c++draft/expr.static.cast#10
https://eel.is/c++draft/conv.fpint


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D150647/new/

https://reviews.llvm.org/D150647

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


[PATCH] D150647: [WIP][analyzer] Fix EnumCastOutOfRangeChecker C++17 handling

2023-05-16 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 added a comment.

Just the test cases are added so far.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D150647/new/

https://reviews.llvm.org/D150647

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


[PATCH] D150647: [WIP][analyzer] Fix EnumCastOutOfRangeChecker C++17 handling

2023-05-16 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 created this revision.
Herald added subscribers: steakhal, manas, ASDenysPetrov, martong, dkrupp, 
donat.nagy, Szelethus, mikhail.ramalho, a.sidorin, szepet, baloghadamsoftware, 
xazax.hun.
Herald added a reviewer: Szelethus.
Herald added a project: All.
gamesh411 requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

In C++17 the initialization rules for enum classes are relaxed.
See: https://en.cppreference.com/w/cpp/language/enum#enum_relaxed_init_cpp17
EnumCastOutOfRangeChecker now correctly recognizes this, and no longer gives 
false positive reports.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D150647

Files:
  clang/test/Analysis/Inputs/system-header-simulator-cxx.h
  clang/test/Analysis/enum-cast-out-of-range-c++17.cpp


Index: clang/test/Analysis/enum-cast-out-of-range-c++17.cpp
===
--- /dev/null
+++ clang/test/Analysis/enum-cast-out-of-range-c++17.cpp
@@ -0,0 +1,26 @@
+// RUN: %clang_analyze_cc1 \
+// RUN:   -analyzer-checker=core,alpha.cplusplus.EnumCastOutOfRange \
+// RUN:   -std=c++17 -verify %s
+//
+// Test relaxed enum class initialization.
+//
+
+// expected-no-diagnostics
+
+#include "Inputs/system-header-simulator-cxx.h"
+
+void test_direct_list_init() {
+  std::byte b{0};   // OK
+  (void)b;
+}
+
+void test_copy_init() {
+  std::byte b = std::byte{0}; // OK
+  (void)b;
+}
+
+struct A { std::byte b; };
+void test_aggregate_copy_init() {
+  A a = {std::byte{42}}; // OK
+  (void)a;
+}
Index: clang/test/Analysis/Inputs/system-header-simulator-cxx.h
===
--- clang/test/Analysis/Inputs/system-header-simulator-cxx.h
+++ clang/test/Analysis/Inputs/system-header-simulator-cxx.h
@@ -1253,3 +1253,11 @@
 };
 
 } // namespace std
+
+// C++17 std::byte
+#if __cplusplus >= 201703L
+namespace std {
+  enum class byte : unsigned char {};
+} // namespace std
+#endif
+


Index: clang/test/Analysis/enum-cast-out-of-range-c++17.cpp
===
--- /dev/null
+++ clang/test/Analysis/enum-cast-out-of-range-c++17.cpp
@@ -0,0 +1,26 @@
+// RUN: %clang_analyze_cc1 \
+// RUN:   -analyzer-checker=core,alpha.cplusplus.EnumCastOutOfRange \
+// RUN:   -std=c++17 -verify %s
+//
+// Test relaxed enum class initialization.
+//
+
+// expected-no-diagnostics
+
+#include "Inputs/system-header-simulator-cxx.h"
+
+void test_direct_list_init() {
+  std::byte b{0};   // OK
+  (void)b;
+}
+
+void test_copy_init() {
+  std::byte b = std::byte{0}; // OK
+  (void)b;
+}
+
+struct A { std::byte b; };
+void test_aggregate_copy_init() {
+  A a = {std::byte{42}}; // OK
+  (void)a;
+}
Index: clang/test/Analysis/Inputs/system-header-simulator-cxx.h
===
--- clang/test/Analysis/Inputs/system-header-simulator-cxx.h
+++ clang/test/Analysis/Inputs/system-header-simulator-cxx.h
@@ -1253,3 +1253,11 @@
 };
 
 } // namespace std
+
+// C++17 std::byte
+#if __cplusplus >= 201703L
+namespace std {
+  enum class byte : unsigned char {};
+} // namespace std
+#endif
+
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D136848: [clang][AST] Compare UnresolvedLookupExpr in structural equivalence.

2022-12-19 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 accepted this revision.
gamesh411 added a comment.
This revision is now accepted and ready to land.

I have verified this patch on open-source projects. Bitcoin had quite a few 
crashes without this; those are gone. LGTM


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D136848/new/

https://reviews.llvm.org/D136848

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


[PATCH] D126186: [clang-tidy] Extend cert-oop57-cpp to check non-zero memset values

2022-06-01 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 added a comment.

Thanks for the quick review!
Fixed the double backtick in the release notes as well.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D126186/new/

https://reviews.llvm.org/D126186

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


[PATCH] D126186: [clang-tidy] Extend cert-oop57-cpp to check non-zero memset values

2022-06-01 Thread Endre Fülöp via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rGd33f199910fa: [clang-tidy] Extend cert-oop57-cpp to check 
non-zero memset values (authored by gamesh411).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D126186/new/

https://reviews.llvm.org/D126186

Files:
  clang-tools-extra/clang-tidy/cert/NonTrivialTypesLibcMemoryCallsCheck.cpp
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/test/clang-tidy/checkers/cert-oop57-cpp.cpp


Index: clang-tools-extra/test/clang-tidy/checkers/cert-oop57-cpp.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/cert-oop57-cpp.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/cert-oop57-cpp.cpp
@@ -88,3 +88,17 @@
   mymemcmp(, , sizeof(Data));
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: consider using comparison 
operators instead of calling 'mymemcmp'
 }
+
+void nonNullSetValue() {
+  NonTrivial Data;
+  // Check non-null-valued second argument.
+  std::memset(, 1, sizeof(Data));
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: calling 'memset' on a 
non-trivially default constructible class is undefined
+}
+
+void nonLiteralSetValue(char C) {
+  NonTrivial Data;
+  // Check non-literal second argument.
+  std::memset(, C, sizeof(Data));
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: calling 'memset' on a 
non-trivially default constructible class is undefined
+}
Index: clang-tools-extra/docs/ReleaseNotes.rst
===
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -156,6 +156,9 @@
   ` when `sizeof(...)` is
   compared against a `__int128_t`.
 
+- Made :doc:`cert-oop57-cpp ` more sensitive
+  by checking for an arbitrary expression in the second argument of `memset`.
+
 - Improved :doc:`cppcoreguidelines-prefer-member-initializer
   ` check.
 
Index: clang-tools-extra/clang-tidy/cert/NonTrivialTypesLibcMemoryCallsCheck.cpp
===
--- clang-tools-extra/clang-tidy/cert/NonTrivialTypesLibcMemoryCallsCheck.cpp
+++ clang-tools-extra/clang-tidy/cert/NonTrivialTypesLibcMemoryCallsCheck.cpp
@@ -80,7 +80,7 @@
   auto IsRecordSizeOf =
   expr(sizeOfExpr(hasArgumentOfType(equalsBoundNode("Record";
   auto ArgChecker = [&](Matcher RecordConstraint,
-BindableMatcher SecondArg) {
+BindableMatcher SecondArg = expr()) {
 return allOf(argumentCountIs(3),
  hasArgument(0, IsStructPointer(RecordConstraint, true)),
  hasArgument(1, SecondArg), hasArgument(2, IsRecordSizeOf));
@@ -89,8 +89,7 @@
   Finder->addMatcher(
   callExpr(callee(namedDecl(hasAnyName(
utils::options::parseListPair(BuiltinMemSet, 
MemSetNames,
-   ArgChecker(unless(isTriviallyDefaultConstructible()),
-  expr(integerLiteral(equals(0)
+   ArgChecker(unless(isTriviallyDefaultConstructible(
   .bind("lazyConstruct"),
   this);
   Finder->addMatcher(


Index: clang-tools-extra/test/clang-tidy/checkers/cert-oop57-cpp.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/cert-oop57-cpp.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/cert-oop57-cpp.cpp
@@ -88,3 +88,17 @@
   mymemcmp(, , sizeof(Data));
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: consider using comparison operators instead of calling 'mymemcmp'
 }
+
+void nonNullSetValue() {
+  NonTrivial Data;
+  // Check non-null-valued second argument.
+  std::memset(, 1, sizeof(Data));
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: calling 'memset' on a non-trivially default constructible class is undefined
+}
+
+void nonLiteralSetValue(char C) {
+  NonTrivial Data;
+  // Check non-literal second argument.
+  std::memset(, C, sizeof(Data));
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: calling 'memset' on a non-trivially default constructible class is undefined
+}
Index: clang-tools-extra/docs/ReleaseNotes.rst
===
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -156,6 +156,9 @@
   ` when `sizeof(...)` is
   compared against a `__int128_t`.
 
+- Made :doc:`cert-oop57-cpp ` more sensitive
+  by checking for an arbitrary expression in the second argument of `memset`.
+
 - Improved :doc:`cppcoreguidelines-prefer-member-initializer
   ` check.
 
Index: clang-tools-extra/clang-tidy/cert/NonTrivialTypesLibcMemoryCallsCheck.cpp
===
--- clang-tools-extra/clang-tidy/cert/NonTrivialTypesLibcMemoryCallsCheck.cpp
+++ clang-tools-extra/clang-tidy/cert/NonTrivialTypesLibcMemoryCallsCheck.cpp
@@ -80,7 +80,7 @@
   auto IsRecordSizeOf =
   

[PATCH] D126186: [clang-tidy] Extend cert-oop57-cpp to check non-zero memset values

2022-05-30 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 updated this revision to Diff 432868.
gamesh411 added a comment.

Remove literal checking from the matcher for memset as well

There is no change in the result set on open source projects even without
restricting the matches to literals.

IMO this is more in line with the rule as it's written as @aaron.ballman 
mentioned.

Updated the ReleaseNotes to reflect this.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D126186/new/

https://reviews.llvm.org/D126186

Files:
  clang-tools-extra/clang-tidy/cert/NonTrivialTypesLibcMemoryCallsCheck.cpp
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/test/clang-tidy/checkers/cert-oop57-cpp.cpp


Index: clang-tools-extra/test/clang-tidy/checkers/cert-oop57-cpp.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/cert-oop57-cpp.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/cert-oop57-cpp.cpp
@@ -88,3 +88,17 @@
   mymemcmp(, , sizeof(Data));
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: consider using comparison 
operators instead of calling 'mymemcmp'
 }
+
+void nonNullSetValue() {
+  NonTrivial Data;
+  // Check non-null-valued second argument.
+  std::memset(, 1, sizeof(Data));
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: calling 'memset' on a 
non-trivially default constructible class is undefined
+}
+
+void nonLiteralSetValue(char C) {
+  NonTrivial Data;
+  // Check non-literal second argument.
+  std::memset(, C, sizeof(Data));
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: calling 'memset' on a 
non-trivially default constructible class is undefined
+}
Index: clang-tools-extra/docs/ReleaseNotes.rst
===
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -156,6 +156,9 @@
   ` when `sizeof(...)` is
   compared against a `__int128_t`.
 
+- Made :doc:`cert-oop57-cpp ` more sensitive
+  by checking for an arbitrary expression in the second argument of `memset`.
+
 - Improved :doc:`cppcoreguidelines-prefer-member-initializer
   ` check.
 
Index: clang-tools-extra/clang-tidy/cert/NonTrivialTypesLibcMemoryCallsCheck.cpp
===
--- clang-tools-extra/clang-tidy/cert/NonTrivialTypesLibcMemoryCallsCheck.cpp
+++ clang-tools-extra/clang-tidy/cert/NonTrivialTypesLibcMemoryCallsCheck.cpp
@@ -80,7 +80,7 @@
   auto IsRecordSizeOf =
   expr(sizeOfExpr(hasArgumentOfType(equalsBoundNode("Record";
   auto ArgChecker = [&](Matcher RecordConstraint,
-BindableMatcher SecondArg) {
+BindableMatcher SecondArg = expr()) {
 return allOf(argumentCountIs(3),
  hasArgument(0, IsStructPointer(RecordConstraint, true)),
  hasArgument(1, SecondArg), hasArgument(2, IsRecordSizeOf));
@@ -89,8 +89,7 @@
   Finder->addMatcher(
   callExpr(callee(namedDecl(hasAnyName(
utils::options::parseListPair(BuiltinMemSet, 
MemSetNames,
-   ArgChecker(unless(isTriviallyDefaultConstructible()),
-  expr(integerLiteral(equals(0)
+   ArgChecker(unless(isTriviallyDefaultConstructible(
   .bind("lazyConstruct"),
   this);
   Finder->addMatcher(


Index: clang-tools-extra/test/clang-tidy/checkers/cert-oop57-cpp.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/cert-oop57-cpp.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/cert-oop57-cpp.cpp
@@ -88,3 +88,17 @@
   mymemcmp(, , sizeof(Data));
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: consider using comparison operators instead of calling 'mymemcmp'
 }
+
+void nonNullSetValue() {
+  NonTrivial Data;
+  // Check non-null-valued second argument.
+  std::memset(, 1, sizeof(Data));
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: calling 'memset' on a non-trivially default constructible class is undefined
+}
+
+void nonLiteralSetValue(char C) {
+  NonTrivial Data;
+  // Check non-literal second argument.
+  std::memset(, C, sizeof(Data));
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: calling 'memset' on a non-trivially default constructible class is undefined
+}
Index: clang-tools-extra/docs/ReleaseNotes.rst
===
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -156,6 +156,9 @@
   ` when `sizeof(...)` is
   compared against a `__int128_t`.
 
+- Made :doc:`cert-oop57-cpp ` more sensitive
+  by checking for an arbitrary expression in the second argument of `memset`.
+
 - Improved :doc:`cppcoreguidelines-prefer-member-initializer
   ` check.
 
Index: clang-tools-extra/clang-tidy/cert/NonTrivialTypesLibcMemoryCallsCheck.cpp
===
--- 

[PATCH] D126186: [clang-tidy] Extend cert-oop57-cpp to check non-zero memset values

2022-05-30 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 updated this revision to Diff 432866.
gamesh411 added a comment.

fix Release Notes


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D126186/new/

https://reviews.llvm.org/D126186

Files:
  clang-tools-extra/clang-tidy/cert/NonTrivialTypesLibcMemoryCallsCheck.cpp
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/test/clang-tidy/checkers/cert-oop57-cpp.cpp


Index: clang-tools-extra/test/clang-tidy/checkers/cert-oop57-cpp.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/cert-oop57-cpp.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/cert-oop57-cpp.cpp
@@ -88,3 +88,10 @@
   mymemcmp(, , sizeof(Data));
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: consider using comparison 
operators instead of calling 'mymemcmp'
 }
+
+void nonNullSetValue() {
+  NonTrivial Data;
+  // Check non-null-valued second argument.
+  std::memset(, 1, sizeof(Data));
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: calling 'memset' on a 
non-trivially default constructible class is undefined
+}
Index: clang-tools-extra/docs/ReleaseNotes.rst
===
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -152,6 +152,9 @@
   ` when `sizeof(...)` is
   compared against a `__int128_t`.
 
+- Made :doc:`cert-oop57-cpp ` more sensitive
+  by checking for non-zero integer literal `memset` arguments as well.
+
 - Improved :doc:`cppcoreguidelines-prefer-member-initializer
   ` check.
 
Index: clang-tools-extra/clang-tidy/cert/NonTrivialTypesLibcMemoryCallsCheck.cpp
===
--- clang-tools-extra/clang-tidy/cert/NonTrivialTypesLibcMemoryCallsCheck.cpp
+++ clang-tools-extra/clang-tidy/cert/NonTrivialTypesLibcMemoryCallsCheck.cpp
@@ -90,7 +90,7 @@
   callExpr(callee(namedDecl(hasAnyName(
utils::options::parseListPair(BuiltinMemSet, 
MemSetNames,
ArgChecker(unless(isTriviallyDefaultConstructible()),
-  expr(integerLiteral(equals(0)
+  expr(integerLiteral(
   .bind("lazyConstruct"),
   this);
   Finder->addMatcher(


Index: clang-tools-extra/test/clang-tidy/checkers/cert-oop57-cpp.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/cert-oop57-cpp.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/cert-oop57-cpp.cpp
@@ -88,3 +88,10 @@
   mymemcmp(, , sizeof(Data));
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: consider using comparison operators instead of calling 'mymemcmp'
 }
+
+void nonNullSetValue() {
+  NonTrivial Data;
+  // Check non-null-valued second argument.
+  std::memset(, 1, sizeof(Data));
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: calling 'memset' on a non-trivially default constructible class is undefined
+}
Index: clang-tools-extra/docs/ReleaseNotes.rst
===
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -152,6 +152,9 @@
   ` when `sizeof(...)` is
   compared against a `__int128_t`.
 
+- Made :doc:`cert-oop57-cpp ` more sensitive
+  by checking for non-zero integer literal `memset` arguments as well.
+
 - Improved :doc:`cppcoreguidelines-prefer-member-initializer
   ` check.
 
Index: clang-tools-extra/clang-tidy/cert/NonTrivialTypesLibcMemoryCallsCheck.cpp
===
--- clang-tools-extra/clang-tidy/cert/NonTrivialTypesLibcMemoryCallsCheck.cpp
+++ clang-tools-extra/clang-tidy/cert/NonTrivialTypesLibcMemoryCallsCheck.cpp
@@ -90,7 +90,7 @@
   callExpr(callee(namedDecl(hasAnyName(
utils::options::parseListPair(BuiltinMemSet, MemSetNames,
ArgChecker(unless(isTriviallyDefaultConstructible()),
-  expr(integerLiteral(equals(0)
+  expr(integerLiteral(
   .bind("lazyConstruct"),
   this);
   Finder->addMatcher(
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D126186: [clang-tidy] Extend cert-oop57-cpp to check non-zero memset values

2022-05-23 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 updated this revision to Diff 431348.
gamesh411 added a comment.

Add full diff with arcanist


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D126186/new/

https://reviews.llvm.org/D126186

Files:
  clang-tools-extra/clang-tidy/cert/NonTrivialTypesLibcMemoryCallsCheck.cpp
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/test/clang-tidy/checkers/cert-oop57-cpp.cpp


Index: clang-tools-extra/test/clang-tidy/checkers/cert-oop57-cpp.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/cert-oop57-cpp.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/cert-oop57-cpp.cpp
@@ -88,3 +88,10 @@
   mymemcmp(, , sizeof(Data));
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: consider using comparison 
operators instead of calling 'mymemcmp'
 }
+
+void nonNullSetValue() {
+  NonTrivial Data;
+  // Check non-null-valued second argument.
+  std::memset(, 1, sizeof(Data));
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: calling 'memset' on a 
non-trivially default constructible class is undefined
+}
Index: clang-tools-extra/docs/ReleaseNotes.rst
===
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -198,6 +198,9 @@
   ` to simplify 
expressions
   using DeMorgan's Theorem.
 
+- Made :doc:`cert-oop57-cpp ` more sensitive
+  by checking for non-zero integer literal  memset arguments as well.
+
 Removed checks
 ^^
 
Index: clang-tools-extra/clang-tidy/cert/NonTrivialTypesLibcMemoryCallsCheck.cpp
===
--- clang-tools-extra/clang-tidy/cert/NonTrivialTypesLibcMemoryCallsCheck.cpp
+++ clang-tools-extra/clang-tidy/cert/NonTrivialTypesLibcMemoryCallsCheck.cpp
@@ -90,7 +90,7 @@
   callExpr(callee(namedDecl(hasAnyName(
utils::options::parseListPair(BuiltinMemSet, 
MemSetNames,
ArgChecker(unless(isTriviallyDefaultConstructible()),
-  expr(integerLiteral(equals(0)
+  expr(integerLiteral(
   .bind("lazyConstruct"),
   this);
   Finder->addMatcher(


Index: clang-tools-extra/test/clang-tidy/checkers/cert-oop57-cpp.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/cert-oop57-cpp.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/cert-oop57-cpp.cpp
@@ -88,3 +88,10 @@
   mymemcmp(, , sizeof(Data));
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: consider using comparison operators instead of calling 'mymemcmp'
 }
+
+void nonNullSetValue() {
+  NonTrivial Data;
+  // Check non-null-valued second argument.
+  std::memset(, 1, sizeof(Data));
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: calling 'memset' on a non-trivially default constructible class is undefined
+}
Index: clang-tools-extra/docs/ReleaseNotes.rst
===
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -198,6 +198,9 @@
   ` to simplify expressions
   using DeMorgan's Theorem.
 
+- Made :doc:`cert-oop57-cpp ` more sensitive
+  by checking for non-zero integer literal  memset arguments as well.
+
 Removed checks
 ^^
 
Index: clang-tools-extra/clang-tidy/cert/NonTrivialTypesLibcMemoryCallsCheck.cpp
===
--- clang-tools-extra/clang-tidy/cert/NonTrivialTypesLibcMemoryCallsCheck.cpp
+++ clang-tools-extra/clang-tidy/cert/NonTrivialTypesLibcMemoryCallsCheck.cpp
@@ -90,7 +90,7 @@
   callExpr(callee(namedDecl(hasAnyName(
utils::options::parseListPair(BuiltinMemSet, MemSetNames,
ArgChecker(unless(isTriviallyDefaultConstructible()),
-  expr(integerLiteral(equals(0)
+  expr(integerLiteral(
   .bind("lazyConstruct"),
   this);
   Finder->addMatcher(
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D126186: [clang-tidy] Extend cert-oop57-cpp to check non-zero memset values

2022-05-23 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 updated this revision to Diff 431319.
gamesh411 added a comment.

Added a release note
Also generated the full context (arcanist could validate the site certificate, 
that's why I had to resort to manual diff creation. Was there a certificate 
change on the reviews.llmv.org site maybe?)


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D126186/new/

https://reviews.llvm.org/D126186

Files:
  clang-tidy/cert/NonTrivialTypesLibcMemoryCallsCheck.cpp
  docs/ReleaseNotes.rst
  test/clang-tidy/checkers/cert-oop57-cpp.cpp


Index: test/clang-tidy/checkers/cert-oop57-cpp.cpp
===
--- test/clang-tidy/checkers/cert-oop57-cpp.cpp
+++ test/clang-tidy/checkers/cert-oop57-cpp.cpp
@@ -88,3 +88,10 @@
   mymemcmp(, , sizeof(Data));
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: consider using comparison 
operators instead of calling 'mymemcmp'
 }
+
+void nonNullSetValue() {
+  NonTrivial Data;
+  // Check non-null-valued second argument.
+  std::memset(, 1, sizeof(Data));
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: calling 'memset' on a 
non-trivially default constructible class is undefined
+}
Index: docs/ReleaseNotes.rst
===
--- docs/ReleaseNotes.rst
+++ docs/ReleaseNotes.rst
@@ -198,6 +198,9 @@
   ` to simplify 
expressions
   using DeMorgan's Theorem.
 
+- Made :doc:`cert-oop57-cpp ` more sensitive
+  by checking for non-zero integer literal  memset arguments as well.
+
 Removed checks
 ^^
 
Index: clang-tidy/cert/NonTrivialTypesLibcMemoryCallsCheck.cpp
===
--- clang-tidy/cert/NonTrivialTypesLibcMemoryCallsCheck.cpp
+++ clang-tidy/cert/NonTrivialTypesLibcMemoryCallsCheck.cpp
@@ -90,7 +90,7 @@
   callExpr(callee(namedDecl(hasAnyName(
utils::options::parseListPair(BuiltinMemSet, 
MemSetNames,
ArgChecker(unless(isTriviallyDefaultConstructible()),
-  expr(integerLiteral(equals(0)
+  expr(integerLiteral(
   .bind("lazyConstruct"),
   this);
   Finder->addMatcher(


Index: test/clang-tidy/checkers/cert-oop57-cpp.cpp
===
--- test/clang-tidy/checkers/cert-oop57-cpp.cpp
+++ test/clang-tidy/checkers/cert-oop57-cpp.cpp
@@ -88,3 +88,10 @@
   mymemcmp(, , sizeof(Data));
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: consider using comparison operators instead of calling 'mymemcmp'
 }
+
+void nonNullSetValue() {
+  NonTrivial Data;
+  // Check non-null-valued second argument.
+  std::memset(, 1, sizeof(Data));
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: calling 'memset' on a non-trivially default constructible class is undefined
+}
Index: docs/ReleaseNotes.rst
===
--- docs/ReleaseNotes.rst
+++ docs/ReleaseNotes.rst
@@ -198,6 +198,9 @@
   ` to simplify expressions
   using DeMorgan's Theorem.
 
+- Made :doc:`cert-oop57-cpp ` more sensitive
+  by checking for non-zero integer literal  memset arguments as well.
+
 Removed checks
 ^^
 
Index: clang-tidy/cert/NonTrivialTypesLibcMemoryCallsCheck.cpp
===
--- clang-tidy/cert/NonTrivialTypesLibcMemoryCallsCheck.cpp
+++ clang-tidy/cert/NonTrivialTypesLibcMemoryCallsCheck.cpp
@@ -90,7 +90,7 @@
   callExpr(callee(namedDecl(hasAnyName(
utils::options::parseListPair(BuiltinMemSet, MemSetNames,
ArgChecker(unless(isTriviallyDefaultConstructible()),
-  expr(integerLiteral(equals(0)
+  expr(integerLiteral(
   .bind("lazyConstruct"),
   this);
   Finder->addMatcher(
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D126186: [clang-tidy] Extend cert-oop57-cpp to check non-zero memset values

2022-05-23 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 added a comment.

F23163926: CSA_20testbench_20report.zip 
There is no change in the results as far as these OS are concerned.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D126186/new/

https://reviews.llvm.org/D126186

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


[PATCH] D126186: [clang-tidy] Extend cert-oop57-cpp to check non-zero memset values

2022-05-23 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 created this revision.
gamesh411 added reviewers: steakhal, martong, whisperity.
gamesh411 added a project: clang-tools-extra.
Herald added subscribers: carlosgalvezp, Szelethus, dkrupp, rnkovacs, xazax.hun.
Herald added a project: All.
gamesh411 requested review of this revision.
Herald added a subscriber: cfe-commits.

Clang Tidy check cert-oop57-cpp now checks for arbitrary-valued integer
literals in memset expressions containing non-trivially
default-constructible instances. Previously it only checked 0 values.

Note that the first non-compliant example of
https://wiki.sei.cmu.edu/confluence/display/cplusplus/OOP57-CPP.+Prefer+special+member+functions+and+overloaded+operators+to+C+Standard+Library+functions
 requires this.

A comparative analysis of OS projects is currently running to see the impact of 
this change.


https://reviews.llvm.org/D126186

Files:
  clang-tools-extra/clang-tidy/cert/NonTrivialTypesLibcMemoryCallsCheck.cpp
  clang-tools-extra/test/clang-tidy/checkers/cert-oop57-cpp.cpp


Index: clang-tools-extra/test/clang-tidy/checkers/cert-oop57-cpp.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/cert-oop57-cpp.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/cert-oop57-cpp.cpp
@@ -88,3 +88,10 @@
   mymemcmp(, , sizeof(Data));
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: consider using comparison 
operators instead of calling 'mymemcmp'
 }
+
+void nonNullSetValue() {
+  NonTrivial Data;
+  // Check non-null-valued second argument.
+  std::memset(, 1, sizeof(Data));
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: calling 'memset' on a 
non-trivially default constructible class is undefined
+}
Index: clang-tools-extra/clang-tidy/cert/NonTrivialTypesLibcMemoryCallsCheck.cpp
===
--- clang-tools-extra/clang-tidy/cert/NonTrivialTypesLibcMemoryCallsCheck.cpp
+++ clang-tools-extra/clang-tidy/cert/NonTrivialTypesLibcMemoryCallsCheck.cpp
@@ -90,7 +90,7 @@
   callExpr(callee(namedDecl(hasAnyName(
utils::options::parseListPair(BuiltinMemSet, 
MemSetNames,
ArgChecker(unless(isTriviallyDefaultConstructible()),
-  expr(integerLiteral(equals(0)
+  expr(integerLiteral(
   .bind("lazyConstruct"),
   this);
   Finder->addMatcher(


Index: clang-tools-extra/test/clang-tidy/checkers/cert-oop57-cpp.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/cert-oop57-cpp.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/cert-oop57-cpp.cpp
@@ -88,3 +88,10 @@
   mymemcmp(, , sizeof(Data));
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: consider using comparison operators instead of calling 'mymemcmp'
 }
+
+void nonNullSetValue() {
+  NonTrivial Data;
+  // Check non-null-valued second argument.
+  std::memset(, 1, sizeof(Data));
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: calling 'memset' on a non-trivially default constructible class is undefined
+}
Index: clang-tools-extra/clang-tidy/cert/NonTrivialTypesLibcMemoryCallsCheck.cpp
===
--- clang-tools-extra/clang-tidy/cert/NonTrivialTypesLibcMemoryCallsCheck.cpp
+++ clang-tools-extra/clang-tidy/cert/NonTrivialTypesLibcMemoryCallsCheck.cpp
@@ -90,7 +90,7 @@
   callExpr(callee(namedDecl(hasAnyName(
utils::options::parseListPair(BuiltinMemSet, MemSetNames,
ArgChecker(unless(isTriviallyDefaultConstructible()),
-  expr(integerLiteral(equals(0)
+  expr(integerLiteral(
   .bind("lazyConstruct"),
   this);
   Finder->addMatcher(
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D125524: [BoundV2] ArrayBoundV2 checks if the extent is tainted

2022-05-13 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 updated this revision to Diff 429159.
gamesh411 added a comment.

add analyzer tag


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D125524/new/

https://reviews.llvm.org/D125524

Files:
  clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
  clang/test/Analysis/taint-diagnostic-visitor.c


Index: clang/test/Analysis/taint-diagnostic-visitor.c
===
--- clang/test/Analysis/taint-diagnostic-visitor.c
+++ clang/test/Analysis/taint-diagnostic-visitor.c
@@ -1,9 +1,12 @@
-// RUN: %clang_cc1 -analyze 
-analyzer-checker=alpha.security.taint,core,alpha.security.ArrayBoundV2 
-analyzer-output=text -verify %s
+// RUN: %clang_cc1 -analyze 
-analyzer-checker=alpha.security.taint,core,unix.Malloc,alpha.security.ArrayBoundV2
 -analyzer-output=text -verify %s
 
 // This file is for testing enhanced diagnostics produced by the 
GenericTaintChecker
 
 int scanf(const char *restrict format, ...);
 int system(const char *command);
+typedef __typeof(sizeof(int)) size_t;
+void *malloc(size_t size);
+void free(void *ptr);
 
 void taintDiagnostic(void)
 {
@@ -34,3 +37,18 @@
   int vla[x]; // expected-warning {{Declared variable-length array (VLA) has 
tainted size}}
   // expected-note@-1 {{Declared variable-length array (VLA) has 
tainted size}}
 }
+
+void taintDiagnosticMalloc(int conj) {
+  int x;
+  scanf("%d", );
+  // expected-note@-1 2 {{Taint originated here}} Once for malloc(tainted), 
once for BoundsV2.
+
+  int *p = (int *)malloc(x + conj); // Generic taint checker forbids tainted 
allocation.
+  // expected-warning@-1 {{Untrusted data is used to specify the buffer size}}
+  // expected-note@-2{{Untrusted data is used to specify the buffer size}}
+
+  p[1] = 1; // BoundsV2 checker can not prove that the access is safe.
+  // expected-warning@-1 {{Out of bound memory access (index is tainted)}}
+  // expected-note@-2{{Out of bound memory access (index is tainted)}}
+  free(p);
+}
Index: clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
+++ clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
@@ -205,10 +205,9 @@
 
 // If we are under constrained and the index variables are tainted, report.
 if (state_exceedsUpperBound && state_withinUpperBound) {
-  SVal ByteOffset = rawOffset.getByteOffset();
-  if (isTainted(state, ByteOffset)) {
+  if (isTainted(state, *upperboundToCheck)) {
 reportOOB(checkerContext, state_exceedsUpperBound, OOB_Tainted,
-  std::make_unique(ByteOffset));
+  std::make_unique(*upperboundToCheck));
 return;
   }
 } else if (state_exceedsUpperBound) {


Index: clang/test/Analysis/taint-diagnostic-visitor.c
===
--- clang/test/Analysis/taint-diagnostic-visitor.c
+++ clang/test/Analysis/taint-diagnostic-visitor.c
@@ -1,9 +1,12 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.security.taint,core,alpha.security.ArrayBoundV2 -analyzer-output=text -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.security.taint,core,unix.Malloc,alpha.security.ArrayBoundV2 -analyzer-output=text -verify %s
 
 // This file is for testing enhanced diagnostics produced by the GenericTaintChecker
 
 int scanf(const char *restrict format, ...);
 int system(const char *command);
+typedef __typeof(sizeof(int)) size_t;
+void *malloc(size_t size);
+void free(void *ptr);
 
 void taintDiagnostic(void)
 {
@@ -34,3 +37,18 @@
   int vla[x]; // expected-warning {{Declared variable-length array (VLA) has tainted size}}
   // expected-note@-1 {{Declared variable-length array (VLA) has tainted size}}
 }
+
+void taintDiagnosticMalloc(int conj) {
+  int x;
+  scanf("%d", );
+  // expected-note@-1 2 {{Taint originated here}} Once for malloc(tainted), once for BoundsV2.
+
+  int *p = (int *)malloc(x + conj); // Generic taint checker forbids tainted allocation.
+  // expected-warning@-1 {{Untrusted data is used to specify the buffer size}}
+  // expected-note@-2{{Untrusted data is used to specify the buffer size}}
+
+  p[1] = 1; // BoundsV2 checker can not prove that the access is safe.
+  // expected-warning@-1 {{Out of bound memory access (index is tainted)}}
+  // expected-note@-2{{Out of bound memory access (index is tainted)}}
+  free(p);
+}
Index: clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
+++ clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
@@ -205,10 +205,9 @@
 
 // If we are under constrained and the index variables are tainted, report.
 if (state_exceedsUpperBound && state_withinUpperBound) {
-  SVal ByteOffset = 

[PATCH] D125524: [BoundV2] ArrayBoundV2 checks if the extent is tainted

2022-05-13 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 created this revision.
gamesh411 added a reviewer: steakhal.
Herald added subscribers: martong, Szelethus, dkrupp.
Herald added a reviewer: Szelethus.
Herald added a project: All.
gamesh411 requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Use upperbound instead of offset to check if the extent of memory region
being accessed is tainted or not.

Original author: steakhal


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D125524

Files:
  clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
  clang/test/Analysis/taint-diagnostic-visitor.c


Index: clang/test/Analysis/taint-diagnostic-visitor.c
===
--- clang/test/Analysis/taint-diagnostic-visitor.c
+++ clang/test/Analysis/taint-diagnostic-visitor.c
@@ -1,9 +1,12 @@
-// RUN: %clang_cc1 -analyze 
-analyzer-checker=alpha.security.taint,core,alpha.security.ArrayBoundV2 
-analyzer-output=text -verify %s
+// RUN: %clang_cc1 -analyze 
-analyzer-checker=alpha.security.taint,core,unix.Malloc,alpha.security.ArrayBoundV2
 -analyzer-output=text -verify %s
 
 // This file is for testing enhanced diagnostics produced by the 
GenericTaintChecker
 
 int scanf(const char *restrict format, ...);
 int system(const char *command);
+typedef __typeof(sizeof(int)) size_t;
+void *malloc(size_t size);
+void free(void *ptr);
 
 void taintDiagnostic(void)
 {
@@ -34,3 +37,18 @@
   int vla[x]; // expected-warning {{Declared variable-length array (VLA) has 
tainted size}}
   // expected-note@-1 {{Declared variable-length array (VLA) has 
tainted size}}
 }
+
+void taintDiagnosticMalloc(int conj) {
+  int x;
+  scanf("%d", );
+  // expected-note@-1 2 {{Taint originated here}} Once for malloc(tainted), 
once for BoundsV2.
+
+  int *p = (int *)malloc(x + conj); // Generic taint checker forbids tainted 
allocation.
+  // expected-warning@-1 {{Untrusted data is used to specify the buffer size}}
+  // expected-note@-2{{Untrusted data is used to specify the buffer size}}
+
+  p[1] = 1; // BoundsV2 checker can not prove that the access is safe.
+  // expected-warning@-1 {{Out of bound memory access (index is tainted)}}
+  // expected-note@-2{{Out of bound memory access (index is tainted)}}
+  free(p);
+}
Index: clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
+++ clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
@@ -205,10 +205,9 @@
 
 // If we are under constrained and the index variables are tainted, report.
 if (state_exceedsUpperBound && state_withinUpperBound) {
-  SVal ByteOffset = rawOffset.getByteOffset();
-  if (isTainted(state, ByteOffset)) {
+  if (isTainted(state, *upperboundToCheck)) {
 reportOOB(checkerContext, state_exceedsUpperBound, OOB_Tainted,
-  std::make_unique(ByteOffset));
+  std::make_unique(*upperboundToCheck));
 return;
   }
 } else if (state_exceedsUpperBound) {


Index: clang/test/Analysis/taint-diagnostic-visitor.c
===
--- clang/test/Analysis/taint-diagnostic-visitor.c
+++ clang/test/Analysis/taint-diagnostic-visitor.c
@@ -1,9 +1,12 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.security.taint,core,alpha.security.ArrayBoundV2 -analyzer-output=text -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.security.taint,core,unix.Malloc,alpha.security.ArrayBoundV2 -analyzer-output=text -verify %s
 
 // This file is for testing enhanced diagnostics produced by the GenericTaintChecker
 
 int scanf(const char *restrict format, ...);
 int system(const char *command);
+typedef __typeof(sizeof(int)) size_t;
+void *malloc(size_t size);
+void free(void *ptr);
 
 void taintDiagnostic(void)
 {
@@ -34,3 +37,18 @@
   int vla[x]; // expected-warning {{Declared variable-length array (VLA) has tainted size}}
   // expected-note@-1 {{Declared variable-length array (VLA) has tainted size}}
 }
+
+void taintDiagnosticMalloc(int conj) {
+  int x;
+  scanf("%d", );
+  // expected-note@-1 2 {{Taint originated here}} Once for malloc(tainted), once for BoundsV2.
+
+  int *p = (int *)malloc(x + conj); // Generic taint checker forbids tainted allocation.
+  // expected-warning@-1 {{Untrusted data is used to specify the buffer size}}
+  // expected-note@-2{{Untrusted data is used to specify the buffer size}}
+
+  p[1] = 1; // BoundsV2 checker can not prove that the access is safe.
+  // expected-warning@-1 {{Out of bound memory access (index is tainted)}}
+  // expected-note@-2{{Out of bound memory access (index is tainted)}}
+  free(p);
+}
Index: clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
===
--- 

[PATCH] D125360: [analyzer] Add taint to the BoolAssignmentChecker

2022-05-13 Thread Endre Fülöp via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rG094fb13b88b3: [analyzer] Add taint to the 
BoolAssignmentChecker (authored by gamesh411).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D125360/new/

https://reviews.llvm.org/D125360

Files:
  clang/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp
  clang/test/Analysis/bool-assignment.c


Index: clang/test/Analysis/bool-assignment.c
===
--- clang/test/Analysis/bool-assignment.c
+++ clang/test/Analysis/bool-assignment.c
@@ -1,5 +1,5 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core.BoolAssignment 
-analyzer-store=region -verify -std=c99 -Dbool=_Bool %s
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core.BoolAssignment 
-analyzer-store=region -verify -x c++ %s
+// RUN: %clang_analyze_cc1 
-analyzer-checker=core,alpha.core.BoolAssignment,alpha.security.taint 
-analyzer-store=region -verify -std=c99 -Dbool=_Bool %s
+// RUN: %clang_analyze_cc1 
-analyzer-checker=core,alpha.core.BoolAssignment,alpha.security.taint 
-analyzer-store=region -verify -x c++ %s
 
 // Test C++'s bool and C's _Bool.
 // FIXME: We stopped warning on these when SValBuilder got smarter about
@@ -104,3 +104,10 @@
   }
   x = y; // no-warning
 }
+
+int scanf(const char *format, ...);
+void test_tainted_Boolean() {
+  int n;
+  scanf("%d", );
+  Boolean copy = n; // expected-warning {{Might assign a tainted non-Boolean 
value}}
+}
Index: clang/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp
@@ -12,6 +12,7 @@
 
//===--===//
 
 #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
+#include "clang/StaticAnalyzer/Checkers/Taint.h"
 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
 #include "clang/StaticAnalyzer/Core/Checker.h"
 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
@@ -23,20 +24,23 @@
 namespace {
   class BoolAssignmentChecker : public Checker< check::Bind > {
 mutable std::unique_ptr BT;
-void emitReport(ProgramStateRef state, CheckerContext ) const;
+void emitReport(ProgramStateRef state, CheckerContext ,
+bool IsTainted = false) const;
+
   public:
 void checkBind(SVal loc, SVal val, const Stmt *S, CheckerContext ) const;
   };
 } // end anonymous namespace
 
-void BoolAssignmentChecker::emitReport(ProgramStateRef state,
-   CheckerContext ) const {
+void BoolAssignmentChecker::emitReport(ProgramStateRef state, CheckerContext 
,
+   bool IsTainted) const {
   if (ExplodedNode *N = C.generateNonFatalErrorNode(state)) {
 if (!BT)
   BT.reset(new BuiltinBug(this, "Assignment of a non-Boolean value"));
 
-C.emitReport(
-std::make_unique(*BT, BT->getDescription(), 
N));
+StringRef Msg = IsTainted ? "Might assign a tainted non-Boolean value"
+  : "Assignment of a non-Boolean value";
+C.emitReport(std::make_unique(*BT, Msg, N));
   }
 }
 
@@ -90,6 +94,8 @@
 
   if (!StIn)
 emitReport(StOut, C);
+  if (StIn && StOut && taint::isTainted(state, *NV))
+emitReport(StOut, C, /*IsTainted=*/true);
 }
 
 void ento::registerBoolAssignmentChecker(CheckerManager ) {


Index: clang/test/Analysis/bool-assignment.c
===
--- clang/test/Analysis/bool-assignment.c
+++ clang/test/Analysis/bool-assignment.c
@@ -1,5 +1,5 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core.BoolAssignment -analyzer-store=region -verify -std=c99 -Dbool=_Bool %s
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core.BoolAssignment -analyzer-store=region -verify -x c++ %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core.BoolAssignment,alpha.security.taint -analyzer-store=region -verify -std=c99 -Dbool=_Bool %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core.BoolAssignment,alpha.security.taint -analyzer-store=region -verify -x c++ %s
 
 // Test C++'s bool and C's _Bool.
 // FIXME: We stopped warning on these when SValBuilder got smarter about
@@ -104,3 +104,10 @@
   }
   x = y; // no-warning
 }
+
+int scanf(const char *format, ...);
+void test_tainted_Boolean() {
+  int n;
+  scanf("%d", );
+  Boolean copy = n; // expected-warning {{Might assign a tainted non-Boolean value}}
+}
Index: clang/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp
@@ -12,6 +12,7 @@
 

[PATCH] D125365: [NFC][analyzer] Pass down a State and a Pred ExplodedNode in the MallocChecker

2022-05-11 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 created this revision.
gamesh411 added a reviewer: steakhal.
Herald added subscribers: manas, ASDenysPetrov, martong, dkrupp, donat.nagy, 
Szelethus, mikhail.ramalho, a.sidorin, szepet, baloghadamsoftware, xazax.hun.
Herald added a reviewer: Szelethus.
Herald added a project: All.
gamesh411 requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Make the predecessor ExplodedNode available in the MallocChecker's state
modeling.

Original author: steakhal


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D125365

Files:
  clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp

Index: clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -214,16 +214,24 @@
 
 REGISTER_MAP_WITH_PROGRAMSTATE(RegionState, SymbolRef, RefState)
 
+namespace {
+struct StateAndPred {
+  ProgramStateRef State;
+  ExplodedNode *Pred;
+};
+} // namespace
+
 /// Check if the memory associated with this symbol was released.
 static bool isReleased(SymbolRef Sym, CheckerContext );
 
 /// Update the RefState to reflect the new memory allocation.
 /// The optional \p RetVal parameter specifies the newly allocated pointer
 /// value; if unspecified, the value of expression \p E is used.
-static ProgramStateRef MallocUpdateRefState(CheckerContext , const Expr *E,
-ProgramStateRef State,
-AllocationFamily Family,
-Optional RetVal = None);
+static StateAndPred MallocUpdateRefState(CheckerContext , const Expr *E,
+ ProgramStateRef State,
+ ExplodedNode *Pred,
+ AllocationFamily Family,
+ Optional RetVal = None);
 
 //===--===//
 // The modeling of memory reallocation.
@@ -455,9 +463,9 @@
   /// Process C++ operator new()'s allocation, which is the part of C++
   /// new-expression that goes before the constructor.
   LLVM_NODISCARD
-  ProgramStateRef processNewAllocation(const CXXAllocatorCall ,
-   CheckerContext ,
-   AllocationFamily Family) const;
+  StateAndPred processNewAllocation(const CXXAllocatorCall ,
+CheckerContext ,
+AllocationFamily Family) const;
 
   /// Perform a zero-allocation check.
   ///
@@ -490,9 +498,10 @@
   /// \param [in] State The \c ProgramState right before allocation.
   /// \returns The ProgramState right after allocation.
   LLVM_NODISCARD
-  ProgramStateRef MallocMemReturnsAttr(CheckerContext , const CallEvent ,
-   const OwnershipAttr *Att,
-   ProgramStateRef State) const;
+  StateAndPred MallocMemReturnsAttr(CheckerContext , const CallEvent ,
+const OwnershipAttr *Att,
+ProgramStateRef State,
+ExplodedNode *Pred) const;
 
   /// Models memory allocation.
   ///
@@ -504,10 +513,10 @@
   /// \param [in] State The \c ProgramState right before allocation.
   /// \returns The ProgramState right after allocation.
   LLVM_NODISCARD
-  static ProgramStateRef MallocMemAux(CheckerContext , const CallEvent ,
-  const Expr *SizeEx, SVal Init,
-  ProgramStateRef State,
-  AllocationFamily Family);
+  static StateAndPred MallocMemAux(CheckerContext , const CallEvent ,
+   const Expr *SizeEx, SVal Init,
+   ProgramStateRef State, ExplodedNode *Pred,
+   AllocationFamily Family);
 
   /// Models memory allocation.
   ///
@@ -519,17 +528,17 @@
   /// \param [in] State The \c ProgramState right before allocation.
   /// \returns The ProgramState right after allocation.
   LLVM_NODISCARD
-  static ProgramStateRef MallocMemAux(CheckerContext , const CallEvent ,
-  SVal Size, SVal Init,
-  ProgramStateRef State,
-  AllocationFamily Family);
+  static StateAndPred MallocMemAux(CheckerContext , const CallEvent ,
+   SVal Size, SVal Init, ProgramStateRef State,
+   ExplodedNode *Pred, AllocationFamily Family);
 
   // Check if this malloc() for special flags. At present that means M_ZERO or
   // __GFP_ZERO (in which case, treat it like 

[PATCH] D125362: [NFC][analyzer] Transitive interestingness in BugReporter

2022-05-11 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 created this revision.
gamesh411 added a reviewer: steakhal.
Herald added subscribers: manas, ASDenysPetrov, martong, dkrupp, donat.nagy, 
Szelethus, mikhail.ramalho, a.sidorin, szepet, baloghadamsoftware, xazax.hun.
Herald added a reviewer: Szelethus.
Herald added a project: All.
gamesh411 requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

When making a region interesting, also mark the subregions interesting.

Original author: steakhal


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D125362

Files:
  clang/lib/StaticAnalyzer/Core/BugReporter.cpp


Index: clang/lib/StaticAnalyzer/Core/BugReporter.cpp
===
--- clang/lib/StaticAnalyzer/Core/BugReporter.cpp
+++ clang/lib/StaticAnalyzer/Core/BugReporter.cpp
@@ -2261,6 +2261,12 @@
   // How to handle multiple metadata for the same region?
   if (const auto *meta = dyn_cast(sym))
 markInteresting(meta->getRegion(), TKind);
+
+  auto SubSyms = llvm::make_range(sym->symbol_begin(), sym->symbol_end());
+  for (SymbolRef SubSym : SubSyms) {
+if (SymbolData::classof(SubSym))
+  insertToInterestingnessMap(InterestingSymbols, SubSym, TKind);
+  }
 }
 
 void PathSensitiveBugReport::markNotInteresting(SymbolRef sym) {
@@ -2341,10 +2347,25 @@
 return None;
   // We don't currently consider metadata symbols to be interesting
   // even if we know their region is interesting. Is that correct behavior?
-  auto It = InterestingSymbols.find(sym);
-  if (It == InterestingSymbols.end())
-return None;
-  return It->getSecond();
+  auto TryToLookupTrackingKind =
+  [this](SymbolRef Sym) -> Optional {
+auto It = InterestingSymbols.find(Sym);
+if (It == InterestingSymbols.end())
+  return None;
+return It->getSecond();
+  };
+
+  if (auto MaybeTK = TryToLookupTrackingKind(sym))
+return MaybeTK;
+
+  auto SubSyms = llvm::make_range(sym->symbol_begin(), sym->symbol_end());
+  for (SymbolRef SubSym : SubSyms) {
+if (SymbolData::classof(SubSym)) {
+  if (auto MaybeTK = TryToLookupTrackingKind(SubSym))
+return MaybeTK;
+}
+  }
+  return None;
 }
 
 Optional


Index: clang/lib/StaticAnalyzer/Core/BugReporter.cpp
===
--- clang/lib/StaticAnalyzer/Core/BugReporter.cpp
+++ clang/lib/StaticAnalyzer/Core/BugReporter.cpp
@@ -2261,6 +2261,12 @@
   // How to handle multiple metadata for the same region?
   if (const auto *meta = dyn_cast(sym))
 markInteresting(meta->getRegion(), TKind);
+
+  auto SubSyms = llvm::make_range(sym->symbol_begin(), sym->symbol_end());
+  for (SymbolRef SubSym : SubSyms) {
+if (SymbolData::classof(SubSym))
+  insertToInterestingnessMap(InterestingSymbols, SubSym, TKind);
+  }
 }
 
 void PathSensitiveBugReport::markNotInteresting(SymbolRef sym) {
@@ -2341,10 +2347,25 @@
 return None;
   // We don't currently consider metadata symbols to be interesting
   // even if we know their region is interesting. Is that correct behavior?
-  auto It = InterestingSymbols.find(sym);
-  if (It == InterestingSymbols.end())
-return None;
-  return It->getSecond();
+  auto TryToLookupTrackingKind =
+  [this](SymbolRef Sym) -> Optional {
+auto It = InterestingSymbols.find(Sym);
+if (It == InterestingSymbols.end())
+  return None;
+return It->getSecond();
+  };
+
+  if (auto MaybeTK = TryToLookupTrackingKind(sym))
+return MaybeTK;
+
+  auto SubSyms = llvm::make_range(sym->symbol_begin(), sym->symbol_end());
+  for (SymbolRef SubSym : SubSyms) {
+if (SymbolData::classof(SubSym)) {
+  if (auto MaybeTK = TryToLookupTrackingKind(SubSym))
+return MaybeTK;
+}
+  }
+  return None;
 }
 
 Optional
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D125360: [analyzer] Add taint to the BoolAssignmentChecker

2022-05-11 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 created this revision.
gamesh411 added a reviewer: steakhal.
Herald added subscribers: manas, ASDenysPetrov, martong, dkrupp, donat.nagy, 
Szelethus, mikhail.ramalho, a.sidorin, szepet, baloghadamsoftware, xazax.hun.
Herald added a reviewer: Szelethus.
Herald added a project: All.
gamesh411 requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

BoolAssignment checker is now taint-aware and warns if a tainted value is
assigned.

Original author: steakhal


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D125360

Files:
  clang/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp
  clang/test/Analysis/bool-assignment.c


Index: clang/test/Analysis/bool-assignment.c
===
--- clang/test/Analysis/bool-assignment.c
+++ clang/test/Analysis/bool-assignment.c
@@ -1,5 +1,5 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core.BoolAssignment 
-analyzer-store=region -verify -std=c99 -Dbool=_Bool %s
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core.BoolAssignment 
-analyzer-store=region -verify -x c++ %s
+// RUN: %clang_analyze_cc1 
-analyzer-checker=core,alpha.core.BoolAssignment,alpha.security.taint 
-analyzer-store=region -verify -std=c99 -Dbool=_Bool %s
+// RUN: %clang_analyze_cc1 
-analyzer-checker=core,alpha.core.BoolAssignment,alpha.security.taint 
-analyzer-store=region -verify -x c++ %s
 
 // Test C++'s bool and C's _Bool.
 // FIXME: We stopped warning on these when SValBuilder got smarter about
@@ -104,3 +104,10 @@
   }
   x = y; // no-warning
 }
+
+int scanf(const char *format, ...);
+void test_tainted_Boolean() {
+  int n;
+  scanf("%d", );
+  Boolean copy = n; // expected-warning {{Might assign a tainted non-Boolean 
value}}
+}
Index: clang/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp
@@ -12,6 +12,7 @@
 
//===--===//
 
 #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
+#include "clang/StaticAnalyzer/Checkers/Taint.h"
 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
 #include "clang/StaticAnalyzer/Core/Checker.h"
 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
@@ -23,20 +24,23 @@
 namespace {
   class BoolAssignmentChecker : public Checker< check::Bind > {
 mutable std::unique_ptr BT;
-void emitReport(ProgramStateRef state, CheckerContext ) const;
+void emitReport(ProgramStateRef state, CheckerContext ,
+bool IsTainted = false) const;
+
   public:
 void checkBind(SVal loc, SVal val, const Stmt *S, CheckerContext ) const;
   };
 } // end anonymous namespace
 
-void BoolAssignmentChecker::emitReport(ProgramStateRef state,
-   CheckerContext ) const {
+void BoolAssignmentChecker::emitReport(ProgramStateRef state, CheckerContext 
,
+   bool IsTainted) const {
   if (ExplodedNode *N = C.generateNonFatalErrorNode(state)) {
 if (!BT)
   BT.reset(new BuiltinBug(this, "Assignment of a non-Boolean value"));
 
-C.emitReport(
-std::make_unique(*BT, BT->getDescription(), 
N));
+StringRef Msg = IsTainted ? "Might assign a tainted non-Boolean value"
+  : "Assignment of a non-Boolean value";
+C.emitReport(std::make_unique(*BT, Msg, N));
   }
 }
 
@@ -90,6 +94,8 @@
 
   if (!StIn)
 emitReport(StOut, C);
+  if (StIn && StOut && taint::isTainted(state, *NV))
+emitReport(StOut, C, /*IsTainted=*/true);
 }
 
 void ento::registerBoolAssignmentChecker(CheckerManager ) {


Index: clang/test/Analysis/bool-assignment.c
===
--- clang/test/Analysis/bool-assignment.c
+++ clang/test/Analysis/bool-assignment.c
@@ -1,5 +1,5 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core.BoolAssignment -analyzer-store=region -verify -std=c99 -Dbool=_Bool %s
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core.BoolAssignment -analyzer-store=region -verify -x c++ %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core.BoolAssignment,alpha.security.taint -analyzer-store=region -verify -std=c99 -Dbool=_Bool %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core.BoolAssignment,alpha.security.taint -analyzer-store=region -verify -x c++ %s
 
 // Test C++'s bool and C's _Bool.
 // FIXME: We stopped warning on these when SValBuilder got smarter about
@@ -104,3 +104,10 @@
   }
   x = y; // no-warning
 }
+
+int scanf(const char *format, ...);
+void test_tainted_Boolean() {
+  int n;
+  scanf("%d", );
+  Boolean copy = n; // expected-warning {{Might assign a tainted non-Boolean value}}
+}
Index: 

[PATCH] D125225: [WIP][analyzer] Taint Notes enhancements

2022-05-09 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 added a comment.

@steakhal
This is WIP as there is still a stdlib function, that does not pass the test, 
and I would like to add more complex taint propagation test cases as well.
Could you please glance over these commits:
[Malloc] Pass down a State and a Pred ExplodedNode in the MallocChecker
[BoundV2][Malloc] Place NoteTags when allocated an interesting tainted amount 
of memory
[Stdlib] Add taint to the StdLibraryFunctionsChecker


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D125225/new/

https://reviews.llvm.org/D125225

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


[PATCH] D125225: [WIP][analyzer] Taint Notes enhancements

2022-05-09 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 updated this revision to Diff 428070.
gamesh411 added a comment.

- [BoolAssign] Add taint to the BoolAssignmentChecker
- [BugReporter] Transitive interestingness
- [Malloc] Pass down a State and a Pred ExplodedNode in the MallocChecker
- [BoundV2] ArrayBoundV2 checks if the extent is tainted
- [BoundV2][Malloc] Place NoteTags when allocated an interesting tainted amount 
of memory
- [CString] Add ConsiderTaint checker option for CStringChecker
- [CString] Consider tainted out-of-bound accesses
- [Stdlib] Add taint to the StdLibraryFunctionsChecker
- [Malloc] Implement the rsize_t like heuristic


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D125225/new/

https://reviews.llvm.org/D125225

Files:
  clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
  clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
  clang/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp
  clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
  clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
  clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
  clang/lib/StaticAnalyzer/Core/BugReporter.cpp
  clang/test/Analysis/analyzer-config.c
  clang/test/Analysis/bool-assignment.c
  clang/test/Analysis/malloc.c
  clang/test/Analysis/std-c-library-functions-taint.c
  clang/test/Analysis/string.c
  clang/test/Analysis/taint-diagnostic-visitor.c

Index: clang/test/Analysis/taint-diagnostic-visitor.c
===
--- clang/test/Analysis/taint-diagnostic-visitor.c
+++ clang/test/Analysis/taint-diagnostic-visitor.c
@@ -1,9 +1,12 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.security.taint,core,alpha.security.ArrayBoundV2 -analyzer-output=text -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.security.taint,core,unix.Malloc,alpha.security.ArrayBoundV2 -analyzer-output=text -verify %s
 
 // This file is for testing enhanced diagnostics produced by the GenericTaintChecker
 
 int scanf(const char *restrict format, ...);
 int system(const char *command);
+typedef __typeof(sizeof(int)) size_t;
+void *malloc(size_t size);
+void free(void *ptr);
 
 void taintDiagnostic(void)
 {
@@ -34,3 +37,19 @@
   int vla[x]; // expected-warning {{Declared variable-length array (VLA) has tainted size}}
   // expected-note@-1 {{Declared variable-length array (VLA) has tainted size}}
 }
+
+void taintDiagnosticMalloc(int conj) {
+  int x;
+  scanf("%d", );
+  // expected-note@-1 2 {{Taint originated here}} Once for malloc(tainted), once for BoundsV2.
+
+  int *p = (int *)malloc(x + conj); // Generic taint checker forbids tainted allocation.
+  // expected-warning@-1 {{Untrusted data is used to specify the buffer size}}
+  // expected-note@-2{{Untrusted data is used to specify the buffer size}}
+  // expected-note@-3 {{Allocating tainted amount of memory}}
+
+  p[1] = 1; // BoundsV2 checker can not prove that the access is safe.
+  // expected-warning@-1 {{Out of bound memory access (index is tainted)}}
+  // expected-note@-2{{Out of bound memory access (index is tainted)}}
+  free(p);
+}
Index: clang/test/Analysis/string.c
===
--- clang/test/Analysis/string.c
+++ clang/test/Analysis/string.c
@@ -1,10 +1,13 @@
-// RUN: %clang_analyze_cc1 -verify %s -Wno-null-dereference \
+// RUN: %clang_analyze_cc1 %s -Wno-null-dereference \
 // RUN:   -analyzer-checker=core \
 // RUN:   -analyzer-checker=unix.cstring \
 // RUN:   -analyzer-checker=unix.Malloc \
+// RUN:   -analyzer-checker=alpha.security.taint \
 // RUN:   -analyzer-checker=alpha.unix.cstring \
 // RUN:   -analyzer-checker=debug.ExprInspection \
-// RUN:   -analyzer-config eagerly-assume=false
+// RUN:   -analyzer-config alpha.unix.cstring.OutOfBounds:ConsiderTaint=true \
+// RUN:   -analyzer-config eagerly-assume=false \
+// RUN:   -verify=expected,tainted,OOB-consider-tainted
 //
 // RUN: %clang_analyze_cc1 -verify %s -Wno-null-dereference -DUSE_BUILTINS \
 // RUN:   -analyzer-checker=core \
@@ -22,7 +25,7 @@
 // RUN:   -analyzer-checker=debug.ExprInspection \
 // RUN:   -analyzer-config eagerly-assume=false
 //
-// RUN: %clang_analyze_cc1 -verify %s -Wno-null-dereference \
+// RUN: %clang_analyze_cc1 %s -Wno-null-dereference \
 // RUN:   -DUSE_BUILTINS -DVARIANT \
 // RUN:   -analyzer-checker=core \
 // RUN:   -analyzer-checker=alpha.security.taint \
@@ -30,7 +33,8 @@
 // RUN:   -analyzer-checker=unix.Malloc \
 // RUN:   -analyzer-checker=alpha.unix.cstring \
 // RUN:   -analyzer-checker=debug.ExprInspection \
-// RUN:   -analyzer-config eagerly-assume=false
+// RUN:   -analyzer-config eagerly-assume=false \
+// RUN:   -verify=expected,tainted
 //
 // RUN: %clang_analyze_cc1 -verify %s -Wno-null-dereference \
 // RUN:   -DSUPPRESS_OUT_OF_BOUND \
@@ -481,6 +485,23 @@
 }
 #endif
 
+void strcat_overflow_tainted_dst_extent(char *y) {
+  int n;
+  scanf("%d", );
+  char *p = 

[PATCH] D125225: [WIP][analyzer] Taint Notes enhancements

2022-05-09 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 created this revision.
gamesh411 added a reviewer: steakhal.
Herald added subscribers: manas, ASDenysPetrov, martong, dkrupp, donat.nagy, 
Szelethus, mikhail.ramalho, a.sidorin, szepet, baloghadamsoftware, xazax.hun.
Herald added a reviewer: Szelethus.
Herald added a project: All.
gamesh411 requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

[BugReporter] Transitive interestingness

[Malloc] Pass down a State and a Pred ExplodedNode in the MallocChecker

[BoundV2] ArrayBoundV2 checks if the extent is tainted

[BoundV2][Malloc] Place NoteTags when allocated an interesting tainted amount 
of memory

[CString] Add ConsiderTaint checker option for CStringChecker

[CString] Consider tainted out-of-bound accesses

[TaintProp] Place NoteTags when propagating taint


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D125225

Files:
  clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
  clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
  clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
  clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
  clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
  clang/lib/StaticAnalyzer/Core/BugReporter.cpp
  clang/test/Analysis/analyzer-config.c
  clang/test/Analysis/string.c
  clang/test/Analysis/taint-diagnostic-visitor.c

Index: clang/test/Analysis/taint-diagnostic-visitor.c
===
--- clang/test/Analysis/taint-diagnostic-visitor.c
+++ clang/test/Analysis/taint-diagnostic-visitor.c
@@ -1,28 +1,31 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.security.taint,core,alpha.security.ArrayBoundV2 -analyzer-output=text -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.security.taint,core,unix.Malloc,alpha.security.ArrayBoundV2 -analyzer-output=text -verify %s
 
 // This file is for testing enhanced diagnostics produced by the GenericTaintChecker
 
 int scanf(const char *restrict format, ...);
 int system(const char *command);
+typedef __typeof(sizeof(int)) size_t;
+void *malloc(size_t size);
+void free(void *ptr);
 
 void taintDiagnostic(void)
 {
   char buf[128];
-  scanf("%s", buf); // expected-note {{Taint originated here}}
+  scanf("%s", buf); // expected-note {{Propagated taint to the 2nd parameter}}
   system(buf); // expected-warning {{Untrusted data is passed to a system call}} // expected-note {{Untrusted data is passed to a system call (CERT/STR02-C. Sanitize data passed to complex subsystems)}}
 }
 
 int taintDiagnosticOutOfBound(void) {
   int index;
   int Array[] = {1, 2, 3, 4, 5};
-  scanf("%d", ); // expected-note {{Taint originated here}}
+  scanf("%d", ); // expected-note {{Taint originated here}} expected-note {{Propagated taint to the 2nd parameter}}
   return Array[index]; // expected-warning {{Out of bound memory access (index is tainted)}}
// expected-note@-1 {{Out of bound memory access (index is tainted)}}
 }
 
 int taintDiagnosticDivZero(int operand) {
   scanf("%d", ); // expected-note {{Value assigned to 'operand'}}
- // expected-note@-1 {{Taint originated here}}
+ // expected-note@-1 {{Taint originated here}} expected-note@-1 {{Propagated taint to the 2nd parameter}}
   return 10 / operand; // expected-warning {{Division by a tainted value, possibly zero}}
// expected-note@-1 {{Division by a tainted value, possibly zero}}
 }
@@ -30,7 +33,23 @@
 void taintDiagnosticVLA(void) {
   int x;
   scanf("%d", ); // expected-note {{Value assigned to 'x'}}
-   // expected-note@-1 {{Taint originated here}}
+   // expected-note@-1 {{Taint originated here}} expected-note@-1 {{Propagated taint to the 2nd parameter}}
   int vla[x]; // expected-warning {{Declared variable-length array (VLA) has tainted size}}
   // expected-note@-1 {{Declared variable-length array (VLA) has tainted size}}
 }
+
+void taintDiagnosticMalloc(int conj) {
+  int x;
+  scanf("%d", ); // expected-note {{Taint originated here}}
+  // expected-note@-1 2 {{Propagated taint to the 2nd parameter}} Once for malloc(tainted), once for BoundsV2.
+
+  int *p = (int *)malloc(x + conj); // Generic taint checker forbids tainted allocation.
+  // expected-warning@-1 {{Untrusted data is used to specify the buffer size}}
+  // expected-note@-2{{Untrusted data is used to specify the buffer size}}
+  // expected-note@-3 {{Allocating tainted amount of memory}}
+
+  p[1] = 1; // BoundsV2 checker can not prove that the access is safe.
+  // expected-warning@-1 {{Out of bound memory access (index is tainted)}}
+  // expected-note@-2{{Out of bound memory access (index is tainted)}}
+  free(p);
+}
Index: clang/test/Analysis/string.c
===
--- clang/test/Analysis/string.c
+++ clang/test/Analysis/string.c
@@ -1,10 +1,13 @@
-// RUN: 

[PATCH] D120369: [analyzer] Add more propagations to Taint analysis

2022-03-07 Thread Endre Fülöp via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rG4fd6c6e65ab5: [analyzer] Add more propagations to Taint 
analysis (authored by gamesh411).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D120369/new/

https://reviews.llvm.org/D120369

Files:
  clang/docs/analyzer/checkers.rst
  clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
  clang/test/Analysis/taint-generic.c

Index: clang/test/Analysis/taint-generic.c
===
--- clang/test/Analysis/taint-generic.c
+++ clang/test/Analysis/taint-generic.c
@@ -1,20 +1,26 @@
-// RUN: %clang_analyze_cc1 -Wno-format-security -Wno-pointer-to-int-cast -verify %s \
+// RUN: %clang_analyze_cc1 -Wno-format-security -Wno-pointer-to-int-cast \
+// RUN:   -Wno-incompatible-library-redeclaration -verify %s \
 // RUN:   -analyzer-checker=alpha.security.taint \
 // RUN:   -analyzer-checker=core \
 // RUN:   -analyzer-checker=alpha.security.ArrayBoundV2 \
+// RUN:   -analyzer-checker=debug.ExprInspection \
 // RUN:   -analyzer-config \
 // RUN: alpha.security.taint.TaintPropagation:Config=%S/Inputs/taint-generic-config.yaml
 
-// RUN: %clang_analyze_cc1 -Wno-format-security -Wno-pointer-to-int-cast -verify %s \
+// RUN: %clang_analyze_cc1 -Wno-format-security -Wno-pointer-to-int-cast \
+// RUN:   -Wno-incompatible-library-redeclaration -verify %s \
 // RUN:   -DFILE_IS_STRUCT \
 // RUN:   -analyzer-checker=alpha.security.taint \
 // RUN:   -analyzer-checker=core \
 // RUN:   -analyzer-checker=alpha.security.ArrayBoundV2 \
+// RUN:   -analyzer-checker=debug.ExprInspection \
 // RUN:   -analyzer-config \
 // RUN: alpha.security.taint.TaintPropagation:Config=%S/Inputs/taint-generic-config.yaml
 
-// RUN: not %clang_analyze_cc1 -Wno-pointer-to-int-cast -verify %s \
+// RUN: not %clang_analyze_cc1 -Wno-pointer-to-int-cast \
+// RUN:   -Wno-incompatible-library-redeclaration -verify %s \
 // RUN:   -analyzer-checker=alpha.security.taint \
+// RUN:   -analyzer-checker=debug.ExprInspection \
 // RUN:   -analyzer-config \
 // RUN: alpha.security.taint.TaintPropagation:Config=justguessit \
 // RUN:   2>&1 | FileCheck %s -check-prefix=CHECK-INVALID-FILE
@@ -24,8 +30,10 @@
 // CHECK-INVALID-FILE-SAME:that expects a valid filename instead of
 // CHECK-INVALID-FILE-SAME:'justguessit'
 
-// RUN: not %clang_analyze_cc1 -verify %s \
+// RUN: not %clang_analyze_cc1 -Wno-incompatible-library-redeclaration \
+// RUN:   -verify %s \
 // RUN:   -analyzer-checker=alpha.security.taint \
+// RUN:   -analyzer-checker=debug.ExprInspection \
 // RUN:   -analyzer-config \
 // RUN: alpha.security.taint.TaintPropagation:Config=%S/Inputs/taint-generic-config-ill-formed.yaml \
 // RUN:   2>&1 | FileCheck -DMSG=%errc_EINVAL %s -check-prefix=CHECK-ILL-FORMED
@@ -34,8 +42,10 @@
 // CHECK-ILL-FORMED-SAME:'alpha.security.taint.TaintPropagation:Config',
 // CHECK-ILL-FORMED-SAME:that expects a valid yaml file: [[MSG]]
 
-// RUN: not %clang_analyze_cc1 -verify %s \
+// RUN: not %clang_analyze_cc1 -Wno-incompatible-library-redeclaration \
+// RUN:   -verify %s \
 // RUN:   -analyzer-checker=alpha.security.taint \
+// RUN:   -analyzer-checker=debug.ExprInspection \
 // RUN:   -analyzer-config \
 // RUN: alpha.security.taint.TaintPropagation:Config=%S/Inputs/taint-generic-config-invalid-arg.yaml \
 // RUN:   2>&1 | FileCheck %s -check-prefix=CHECK-INVALID-ARG
@@ -46,6 +56,9 @@
 // CHECK-INVALID-ARG-SAME:rules greater or equal to -1
 
 typedef long long rsize_t;
+void clang_analyzer_isTainted_char(char);
+void clang_analyzer_isTainted_charp(char*);
+void clang_analyzer_isTainted_int(int);
 
 int scanf(const char *restrict format, ...);
 char *gets(char *str);
@@ -60,13 +73,18 @@
 #endif
 
 #define bool _Bool
+#define NULL (void*)0
 
 char *getenv(const char *name);
+
+FILE *fopen(const char *name, const char *mode);
+
 int fscanf(FILE *restrict stream, const char *restrict format, ...);
 int sprintf(char *str, const char *format, ...);
 void setproctitle(const char *fmt, ...);
 void setproctitle_init(int argc, char *argv[], char *envp[]);
 typedef __typeof(sizeof(int)) size_t;
+typedef signed long long ssize_t;
 
 // Define string functions. Use builtin for some of them. They all default to
 // the processing in the taint checker.
@@ -388,7 +406,6 @@
   return system(c); // expected-warning {{Untrusted data is passed to a system call}}
 }
 
-typedef signed long long ssize_t;
 ssize_t readlink(const char *path, char *buf, size_t bufsiz);
 int testReadlink(char *path, char *buf, size_t bufsiz) {
   ssize_t s = readlink(path, buf, bufsiz);
@@ -463,6 +480,510 @@
   return system(buf); // expected-warning {{Untrusted data is passed to a system call}}
 }
 
+int fscanf_s(FILE *stream, const char *format, ...);
+void testFscanf_s(const char *fname, int *d) {
+  FILE *f = fopen(fname, "r");
+  fscanf_s(f, "%d", d);
+  

[PATCH] D120369: [analyzer] Add more propagations to Taint analysis

2022-03-07 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 updated this revision to Diff 413388.
gamesh411 added a comment.
Herald added a project: All.

rebase


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D120369/new/

https://reviews.llvm.org/D120369

Files:
  clang/docs/analyzer/checkers.rst
  clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
  clang/test/Analysis/taint-generic.c

Index: clang/test/Analysis/taint-generic.c
===
--- clang/test/Analysis/taint-generic.c
+++ clang/test/Analysis/taint-generic.c
@@ -1,20 +1,26 @@
-// RUN: %clang_analyze_cc1 -Wno-format-security -Wno-pointer-to-int-cast -verify %s \
+// RUN: %clang_analyze_cc1 -Wno-format-security -Wno-pointer-to-int-cast \
+// RUN:   -Wno-incompatible-library-redeclaration -verify %s \
 // RUN:   -analyzer-checker=alpha.security.taint \
 // RUN:   -analyzer-checker=core \
 // RUN:   -analyzer-checker=alpha.security.ArrayBoundV2 \
+// RUN:   -analyzer-checker=debug.ExprInspection \
 // RUN:   -analyzer-config \
 // RUN: alpha.security.taint.TaintPropagation:Config=%S/Inputs/taint-generic-config.yaml
 
-// RUN: %clang_analyze_cc1 -Wno-format-security -Wno-pointer-to-int-cast -verify %s \
+// RUN: %clang_analyze_cc1 -Wno-format-security -Wno-pointer-to-int-cast \
+// RUN:   -Wno-incompatible-library-redeclaration -verify %s \
 // RUN:   -DFILE_IS_STRUCT \
 // RUN:   -analyzer-checker=alpha.security.taint \
 // RUN:   -analyzer-checker=core \
 // RUN:   -analyzer-checker=alpha.security.ArrayBoundV2 \
+// RUN:   -analyzer-checker=debug.ExprInspection \
 // RUN:   -analyzer-config \
 // RUN: alpha.security.taint.TaintPropagation:Config=%S/Inputs/taint-generic-config.yaml
 
-// RUN: not %clang_analyze_cc1 -Wno-pointer-to-int-cast -verify %s \
+// RUN: not %clang_analyze_cc1 -Wno-pointer-to-int-cast \
+// RUN:   -Wno-incompatible-library-redeclaration -verify %s \
 // RUN:   -analyzer-checker=alpha.security.taint \
+// RUN:   -analyzer-checker=debug.ExprInspection \
 // RUN:   -analyzer-config \
 // RUN: alpha.security.taint.TaintPropagation:Config=justguessit \
 // RUN:   2>&1 | FileCheck %s -check-prefix=CHECK-INVALID-FILE
@@ -24,8 +30,10 @@
 // CHECK-INVALID-FILE-SAME:that expects a valid filename instead of
 // CHECK-INVALID-FILE-SAME:'justguessit'
 
-// RUN: not %clang_analyze_cc1 -verify %s \
+// RUN: not %clang_analyze_cc1 -Wno-incompatible-library-redeclaration \
+// RUN:   -verify %s \
 // RUN:   -analyzer-checker=alpha.security.taint \
+// RUN:   -analyzer-checker=debug.ExprInspection \
 // RUN:   -analyzer-config \
 // RUN: alpha.security.taint.TaintPropagation:Config=%S/Inputs/taint-generic-config-ill-formed.yaml \
 // RUN:   2>&1 | FileCheck -DMSG=%errc_EINVAL %s -check-prefix=CHECK-ILL-FORMED
@@ -34,8 +42,10 @@
 // CHECK-ILL-FORMED-SAME:'alpha.security.taint.TaintPropagation:Config',
 // CHECK-ILL-FORMED-SAME:that expects a valid yaml file: [[MSG]]
 
-// RUN: not %clang_analyze_cc1 -verify %s \
+// RUN: not %clang_analyze_cc1 -Wno-incompatible-library-redeclaration \
+// RUN:   -verify %s \
 // RUN:   -analyzer-checker=alpha.security.taint \
+// RUN:   -analyzer-checker=debug.ExprInspection \
 // RUN:   -analyzer-config \
 // RUN: alpha.security.taint.TaintPropagation:Config=%S/Inputs/taint-generic-config-invalid-arg.yaml \
 // RUN:   2>&1 | FileCheck %s -check-prefix=CHECK-INVALID-ARG
@@ -46,6 +56,9 @@
 // CHECK-INVALID-ARG-SAME:rules greater or equal to -1
 
 typedef long long rsize_t;
+void clang_analyzer_isTainted_char(char);
+void clang_analyzer_isTainted_charp(char*);
+void clang_analyzer_isTainted_int(int);
 
 int scanf(const char *restrict format, ...);
 char *gets(char *str);
@@ -60,13 +73,18 @@
 #endif
 
 #define bool _Bool
+#define NULL (void*)0
 
 char *getenv(const char *name);
+
+FILE *fopen(const char *name, const char *mode);
+
 int fscanf(FILE *restrict stream, const char *restrict format, ...);
 int sprintf(char *str, const char *format, ...);
 void setproctitle(const char *fmt, ...);
 void setproctitle_init(int argc, char *argv[], char *envp[]);
 typedef __typeof(sizeof(int)) size_t;
+typedef signed long long ssize_t;
 
 // Define string functions. Use builtin for some of them. They all default to
 // the processing in the taint checker.
@@ -388,7 +406,6 @@
   return system(c); // expected-warning {{Untrusted data is passed to a system call}}
 }
 
-typedef signed long long ssize_t;
 ssize_t readlink(const char *path, char *buf, size_t bufsiz);
 int testReadlink(char *path, char *buf, size_t bufsiz) {
   ssize_t s = readlink(path, buf, bufsiz);
@@ -463,6 +480,510 @@
   return system(buf); // expected-warning {{Untrusted data is passed to a system call}}
 }
 
+int fscanf_s(FILE *stream, const char *format, ...);
+void testFscanf_s(const char *fname, int *d) {
+  FILE *f = fopen(fname, "r");
+  fscanf_s(f, "%d", d);
+  clang_analyzer_isTainted_int(*d); // expected-warning {{YES}}
+}
+
+int 

[PATCH] D120369: [analyzer] Add more propagations to Taint analysis

2022-03-01 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 added inline comments.



Comment at: clang/docs/analyzer/checkers.rst:2361
 Default propagations defined by ``GenericTaintChecker``:
-``atoi``, ``atol``, ``atoll``, ``fgetc``, ``fgetln``, ``fgets``, ``fscanf``, 
``sscanf``, ``getc``, ``getc_unlocked``, ``getdelim``, ``getline``, ``getw``, 
``pread``, ``read``, ``strchr``, ``strrchr``, ``tolower``, ``toupper``
+``atoi``, ``atol``, ``atoll``, ``basename``, ``dirname``, ``fgetc``, 
``fgetln``, ``fgets``, ``fnmatch``, ``fread``, ``fscanf``, ``fscanf_s``, 
``index``, ``inflate``, ``isalnum``, ``isalpha``, ``isascii``, ``isblank``, 
``iscntrl``, ``isdigit``, ``isgraph``, ``islower``, ``isprint``, ``ispunct``, 
``isspace``, ``isupper``, ``isxdigit``, ``memchr``, ``memrchr``, ``sscanf``, 
``getc``, ``getc_unlocked``, ``getdelim``, ``getline``, ``getw``, ``memcmp``, 
``memcpy``, ``memmem``, ``memmove``, ``mbtowc``, ``pread``, ``qsort``, 
``qsort_r``, ``rawmemchr``, ``read``, ``readv``, ``recv``, ``recvfrom``, 
``rindex``, ``strcasestr``, ``strchr``, ``strchrnul``,  ``strcasecmp``, 
``strcmp``, ``strcspn``, ``strlen``, ``strncasecmp``, ``strncmp``, ``strndup``, 
``strndupa``, ``strpbrk``, ``strrchr``, ``strsep``, ``strspn``, ``strstr``, 
``strtol``, ``strtoll``, ``strtoul``, ``strtoull``, ``tolower``, ``toupper``, 
``ttyname``, ``ttyname_r``, ``vfscanf``, ``vfscanf``, ``wctomb``, ``wcwidth``
 

steakhal wrote:
> I cannot see the corresponding propagation rule.
> That being said, it would be handy to mention that this is for `zlib` 
> decompression and this should be probably a taint source anyway.
> 
> `vfscanf` occurs two times.
> 
> `vscanf` is not mentioned here; and there are probably a couple others like 
> this.
Removed `vscanf` and `vfscanf` as modeling their taint is not straightforward 
and should be done in another checker.
The problem with those is that they do not use variadic arguments, but an 
abstraction of those implemented by the type `va_list`, which is used to 
support invocations, where the number of arguments is determined at runtime.
In addition to modeling individual v-variants we will also have to handle the 
creation of `va_list` objects, and `va_start` function calls and try to reason 
about which parameters will be tainted.



Comment at: clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp:561
+  {{"vscanf"}, TR::Prop({{0}}, {{}, 1})},
+  {{"vfscanf"}, TR::Prop({{0}}, {{}, 2})},
+

steakhal wrote:
> This function has exactly 3 arguments.
> I'm also puzzled how tainting `va_list` will work out. That should be modeled 
> separately IMO.
> This comment applies to all of the similar `va_list` accepting functions, 
> such as `vscanf`, `vfscanf`, and possibly others.
> 
> That being said, I think `vscanf` is more like `scanf`, so it should be 
> modeled as a taint source instead of a propagator.
removed



Comment at: clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp:575
+  {{"fread"}, TR::Prop({{3}}, {{0, ReturnValueIndex}})},
+  {{"readv"}, TR::Prop({{0}}, {{1, ReturnValueIndex}})},
+  {{"recv"}, TR::Prop({{0}}, {{1, ReturnValueIndex}})},

steakhal wrote:
> I'm on board with marking read operations as props/sources.
> Let's look at the declaration: `ssize_t readv(int fd, const struct iovec 
> *iov, int iovcnt);`
> I'm not sure how could the pointee of `iov` be modified by this call, as its 
> `const`.
> Additionally, I doubt the effectiveness of the rule, since I don't think it 
> would be too likely to have a path leading to a taint sink with an `iov` 
> pointer. That being said, let it be, but don't expect much from this rule :D
On second thought, this seems pointless indeed, removed.



Comment at: clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp:582-583
+
+  {{"dirname"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+  {{"basename"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+  {{"fnmatch"}, TR::Prop({{0}}, {{ReturnValueIndex}})},

steakhal wrote:
> These should be sorted, isn't it?
swapped, thx



Comment at: clang/test/Analysis/taint-generic.c:399-400
+struct iovec {
+  void *iov_base; /* Starting address */
+  size_t iov_len; /* Number of bytes to transfer */
+};

steakhal wrote:
> Please use single-line comments.
> It makes debugging test files easier in some cases.
removed



Comment at: clang/test/Analysis/taint-generic.c:408
+  size_t read = readv(fd, iov, iovcnt);
+  // FIXME: should be able to assert that iov is also tainted
+  return 1 / read; // expected-warning {{Division by a tainted value, possibly 
zero}}

steakhal wrote:
> `clang_analyzer_isTainted(*iov)`
test case removed


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D120369/new/

https://reviews.llvm.org/D120369

___
cfe-commits 

[PATCH] D120369: [analyzer] Add more propagations to Taint analysis

2022-03-01 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 updated this revision to Diff 412057.
gamesh411 marked 17 inline comments as done.
gamesh411 added a comment.
Herald added a subscriber: manas.

- remove vscanf and co.
- use debug.ExprInspection for test cases
- fix semantic issues for modeled functions


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D120369/new/

https://reviews.llvm.org/D120369

Files:
  clang/docs/analyzer/checkers.rst
  clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
  clang/test/Analysis/taint-generic.c

Index: clang/test/Analysis/taint-generic.c
===
--- clang/test/Analysis/taint-generic.c
+++ clang/test/Analysis/taint-generic.c
@@ -1,20 +1,26 @@
-// RUN: %clang_analyze_cc1 -Wno-format-security -Wno-pointer-to-int-cast -verify %s \
+// RUN: %clang_analyze_cc1 -Wno-format-security -Wno-pointer-to-int-cast \
+// RUN:   -Wno-incompatible-library-redeclaration -verify %s \
 // RUN:   -analyzer-checker=alpha.security.taint \
 // RUN:   -analyzer-checker=core \
 // RUN:   -analyzer-checker=alpha.security.ArrayBoundV2 \
+// RUN:   -analyzer-checker=debug.ExprInspection \
 // RUN:   -analyzer-config \
 // RUN: alpha.security.taint.TaintPropagation:Config=%S/Inputs/taint-generic-config.yaml
 
-// RUN: %clang_analyze_cc1 -Wno-format-security -Wno-pointer-to-int-cast -verify %s \
+// RUN: %clang_analyze_cc1 -Wno-format-security -Wno-pointer-to-int-cast \
+// RUN:   -Wno-incompatible-library-redeclaration -verify %s \
 // RUN:   -DFILE_IS_STRUCT \
 // RUN:   -analyzer-checker=alpha.security.taint \
 // RUN:   -analyzer-checker=core \
 // RUN:   -analyzer-checker=alpha.security.ArrayBoundV2 \
+// RUN:   -analyzer-checker=debug.ExprInspection \
 // RUN:   -analyzer-config \
 // RUN: alpha.security.taint.TaintPropagation:Config=%S/Inputs/taint-generic-config.yaml
 
-// RUN: not %clang_analyze_cc1 -Wno-pointer-to-int-cast -verify %s \
+// RUN: not %clang_analyze_cc1 -Wno-pointer-to-int-cast \
+// RUN:   -Wno-incompatible-library-redeclaration -verify %s \
 // RUN:   -analyzer-checker=alpha.security.taint \
+// RUN:   -analyzer-checker=debug.ExprInspection \
 // RUN:   -analyzer-config \
 // RUN: alpha.security.taint.TaintPropagation:Config=justguessit \
 // RUN:   2>&1 | FileCheck %s -check-prefix=CHECK-INVALID-FILE
@@ -24,8 +30,10 @@
 // CHECK-INVALID-FILE-SAME:that expects a valid filename instead of
 // CHECK-INVALID-FILE-SAME:'justguessit'
 
-// RUN: not %clang_analyze_cc1 -verify %s \
+// RUN: not %clang_analyze_cc1 -Wno-incompatible-library-redeclaration \
+// RUN:   -verify %s \
 // RUN:   -analyzer-checker=alpha.security.taint \
+// RUN:   -analyzer-checker=debug.ExprInspection \
 // RUN:   -analyzer-config \
 // RUN: alpha.security.taint.TaintPropagation:Config=%S/Inputs/taint-generic-config-ill-formed.yaml \
 // RUN:   2>&1 | FileCheck -DMSG=%errc_EINVAL %s -check-prefix=CHECK-ILL-FORMED
@@ -34,8 +42,10 @@
 // CHECK-ILL-FORMED-SAME:'alpha.security.taint.TaintPropagation:Config',
 // CHECK-ILL-FORMED-SAME:that expects a valid yaml file: [[MSG]]
 
-// RUN: not %clang_analyze_cc1 -verify %s \
+// RUN: not %clang_analyze_cc1 -Wno-incompatible-library-redeclaration \
+// RUN:   -verify %s \
 // RUN:   -analyzer-checker=alpha.security.taint \
+// RUN:   -analyzer-checker=debug.ExprInspection \
 // RUN:   -analyzer-config \
 // RUN: alpha.security.taint.TaintPropagation:Config=%S/Inputs/taint-generic-config-invalid-arg.yaml \
 // RUN:   2>&1 | FileCheck %s -check-prefix=CHECK-INVALID-ARG
@@ -45,6 +55,10 @@
 // CHECK-INVALID-ARG-SAME:that expects an argument number for propagation
 // CHECK-INVALID-ARG-SAME:rules greater or equal to -1
 
+void clang_analyzer_isTainted_char(char);
+void clang_analyzer_isTainted_charp(char*);
+void clang_analyzer_isTainted_int(int);
+
 int scanf(const char *restrict format, ...);
 char *gets(char *str);
 int getchar(void);
@@ -58,10 +72,15 @@
 
 #define bool _Bool
 
+#define NULL (void*)0
+
+FILE *fopen(const char *name, const char *mode);
+
 int fscanf(FILE *restrict stream, const char *restrict format, ...);
 int sprintf(char *str, const char *format, ...);
 void setproctitle(const char *fmt, ...);
 typedef __typeof(sizeof(int)) size_t;
+typedef int ssize_t;
 
 // Define string functions. Use builtin for some of them. They all default to
 // the processing in the taint checker.
@@ -352,6 +371,510 @@
   return 1 / x; // expected-warning {{Division by a tainted value, possibly zero}}
 }
 
+int fscanf_s(FILE *stream, const char *format, ...);
+void testFscanf_s(const char *fname, int *d) {
+  FILE *f = fopen(fname, "r");
+  fscanf_s(f, "%d", d);
+  clang_analyzer_isTainted_int(*d); // expected-warning {{YES}}
+}
+
+int fread(void *buffer, size_t size, size_t count, FILE *stream);
+void testFread(const char *fname, int *buffer, size_t size, size_t count) {
+  FILE *f = fopen(fname, "r");
+  size_t read = fread(buffer, 

[PATCH] D120236: [analyzer] Add more sources to Taint analysis

2022-02-28 Thread Endre Fülöp via Phabricator via cfe-commits
This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rG34a7387986a6: [analyzer] Add more sources to Taint analysis 
(authored by gamesh411).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D120236/new/

https://reviews.llvm.org/D120236

Files:
  clang/docs/analyzer/checkers.rst
  clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
  clang/test/Analysis/taint-generic.c

Index: clang/test/Analysis/taint-generic.c
===
--- clang/test/Analysis/taint-generic.c
+++ clang/test/Analysis/taint-generic.c
@@ -45,8 +45,11 @@
 // CHECK-INVALID-ARG-SAME:that expects an argument number for propagation
 // CHECK-INVALID-ARG-SAME:rules greater or equal to -1
 
+typedef long long rsize_t;
+
 int scanf(const char *restrict format, ...);
 char *gets(char *str);
+char *gets_s(char *str, rsize_t n);
 int getchar(void);
 
 typedef struct _FILE FILE;
@@ -197,6 +200,12 @@
   system(str); // expected-warning {{Untrusted data is passed to a system call}}
 }
 
+void testGets_s(void) {
+  char str[50];
+  gets_s(str, 49);
+  system(str); // expected-warning {{Untrusted data is passed to a system call}}
+}
+
 void testTaintedBufferSize(void) {
   size_t ts;
   scanf("%zd", );
@@ -343,15 +352,115 @@
 *(volatile int *) 0; // no-warning
 }
 
-int sprintf_is_not_a_source(char *buf, char *msg) {
+int testSprintf_is_not_a_source(char *buf, char *msg) {
   int x = sprintf(buf, "%s", msg); // no-warning
-  return 1 / x; // no-warning: 'sprintf' is not a taint source
+  return 1 / x;// no-warning: 'sprintf' is not a taint source
 }
 
-int sprintf_propagates_taint(char *buf, char *msg) {
+int testSprintf_propagates_taint(char *buf, char *msg) {
   scanf("%s", msg);
   int x = sprintf(buf, "%s", msg); // propagate taint!
-  return 1 / x; // expected-warning {{Division by a tainted value, possibly zero}}
+  return 1 / x;// expected-warning {{Division by a tainted value, possibly zero}}
+}
+
+int scanf_s(const char *format, ...);
+int testScanf_s_(int *out) {
+  scanf_s("%d", out);
+  return 1 / *out; // expected-warning {{Division by a tainted value, possibly zero}}
+}
+
+#define _IO_FILE FILE
+int _IO_getc(_IO_FILE *__fp);
+int testUnderscoreIO_getc(_IO_FILE *fp) {
+  char c = _IO_getc(fp);
+  return 1 / c; // expected-warning {{Division by a tainted value, possibly zero}}
+}
+
+char *getcwd(char *buf, size_t size);
+int testGetcwd(char *buf, size_t size) {
+  char *c = getcwd(buf, size);
+  return system(c); // expected-warning {{Untrusted data is passed to a system call}}
+}
+
+char *getwd(char *buf);
+int testGetwd(char *buf) {
+  char *c = getwd(buf);
+  return system(c); // expected-warning {{Untrusted data is passed to a system call}}
+}
+
+typedef signed long long ssize_t;
+ssize_t readlink(const char *path, char *buf, size_t bufsiz);
+int testReadlink(char *path, char *buf, size_t bufsiz) {
+  ssize_t s = readlink(path, buf, bufsiz);
+  system(buf); // expected-warning {{Untrusted data is passed to a system call}}
+  // readlink never returns 0
+  return 1 / (s + 1); // expected-warning {{Division by a tainted value, possibly zero}}
+}
+
+ssize_t readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz);
+int testReadlinkat(int dirfd, char *path, char *buf, size_t bufsiz) {
+  ssize_t s = readlinkat(dirfd, path, buf, bufsiz);
+  system(buf);// expected-warning {{Untrusted data is passed to a system call}}
+  (void)(1 / dirfd);  // arg 0 is not tainted
+  system(path);   // arg 1 is not tainted
+  (void)(1 / bufsiz); // arg 3 is not tainted
+  // readlinkat never returns 0
+  return 1 / (s + 1); // expected-warning {{Division by a tainted value, possibly zero}}
+}
+
+char *get_current_dir_name(void);
+int testGet_current_dir_name() {
+  char *d = get_current_dir_name();
+  return system(d); // expected-warning {{Untrusted data is passed to a system call}}
+}
+
+int gethostname(char *name, size_t len);
+int testGethostname(char *name, size_t len) {
+  gethostname(name, len);
+  return system(name); // expected-warning {{Untrusted data is passed to a system call}}
+}
+
+struct sockaddr;
+typedef size_t socklen_t;
+int getnameinfo(const struct sockaddr *restrict addr, socklen_t addrlen,
+char *restrict host, socklen_t hostlen,
+char *restrict serv, socklen_t servlen, int flags);
+int testGetnameinfo(const struct sockaddr *restrict addr, socklen_t addrlen,
+char *restrict host, socklen_t hostlen,
+char *restrict serv, socklen_t servlen, int flags) {
+  getnameinfo(addr, addrlen, host, hostlen, serv, servlen, flags);
+
+  system(host);// expected-warning {{Untrusted data is passed to a system call}}
+  return system(serv); // expected-warning {{Untrusted data is passed to a 

[PATCH] D120236: [analyzer] Add more sources to Taint analysis

2022-02-28 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 updated this revision to Diff 411765.
gamesh411 added a comment.

fix readlinkat arg index
extend testcase for readlinkat


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D120236/new/

https://reviews.llvm.org/D120236

Files:
  clang/docs/analyzer/checkers.rst
  clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
  clang/test/Analysis/taint-generic.c

Index: clang/test/Analysis/taint-generic.c
===
--- clang/test/Analysis/taint-generic.c
+++ clang/test/Analysis/taint-generic.c
@@ -45,8 +45,11 @@
 // CHECK-INVALID-ARG-SAME:that expects an argument number for propagation
 // CHECK-INVALID-ARG-SAME:rules greater or equal to -1
 
+typedef long long rsize_t;
+
 int scanf(const char *restrict format, ...);
 char *gets(char *str);
+char *gets_s(char *str, rsize_t n);
 int getchar(void);
 
 typedef struct _FILE FILE;
@@ -195,6 +198,12 @@
   system(str); // expected-warning {{Untrusted data is passed to a system call}}
 }
 
+void testGets_s(void) {
+  char str[50];
+  gets_s(str, 49);
+  system(str); // expected-warning {{Untrusted data is passed to a system call}}
+}
+
 void testTaintedBufferSize(void) {
   size_t ts;
   scanf("%zd", );
@@ -341,15 +350,115 @@
 *(volatile int *) 0; // no-warning
 }
 
-int sprintf_is_not_a_source(char *buf, char *msg) {
+int testSprintf_is_not_a_source(char *buf, char *msg) {
   int x = sprintf(buf, "%s", msg); // no-warning
-  return 1 / x; // no-warning: 'sprintf' is not a taint source
+  return 1 / x;// no-warning: 'sprintf' is not a taint source
 }
 
-int sprintf_propagates_taint(char *buf, char *msg) {
+int testSprintf_propagates_taint(char *buf, char *msg) {
   scanf("%s", msg);
   int x = sprintf(buf, "%s", msg); // propagate taint!
-  return 1 / x; // expected-warning {{Division by a tainted value, possibly zero}}
+  return 1 / x;// expected-warning {{Division by a tainted value, possibly zero}}
+}
+
+int scanf_s(const char *format, ...);
+int testScanf_s_(int *out) {
+  scanf_s("%d", out);
+  return 1 / *out; // expected-warning {{Division by a tainted value, possibly zero}}
+}
+
+#define _IO_FILE FILE
+int _IO_getc(_IO_FILE *__fp);
+int testUnderscoreIO_getc(_IO_FILE *fp) {
+  char c = _IO_getc(fp);
+  return 1 / c; // expected-warning {{Division by a tainted value, possibly zero}}
+}
+
+char *getcwd(char *buf, size_t size);
+int testGetcwd(char *buf, size_t size) {
+  char *c = getcwd(buf, size);
+  return system(c); // expected-warning {{Untrusted data is passed to a system call}}
+}
+
+char *getwd(char *buf);
+int testGetwd(char *buf) {
+  char *c = getwd(buf);
+  return system(c); // expected-warning {{Untrusted data is passed to a system call}}
+}
+
+typedef signed long long ssize_t;
+ssize_t readlink(const char *path, char *buf, size_t bufsiz);
+int testReadlink(char *path, char *buf, size_t bufsiz) {
+  ssize_t s = readlink(path, buf, bufsiz);
+  system(buf); // expected-warning {{Untrusted data is passed to a system call}}
+  // readlink never returns 0
+  return 1 / (s + 1); // expected-warning {{Division by a tainted value, possibly zero}}
+}
+
+ssize_t readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz);
+int testReadlinkat(int dirfd, char *path, char *buf, size_t bufsiz) {
+  ssize_t s = readlinkat(dirfd, path, buf, bufsiz);
+  system(buf);// expected-warning {{Untrusted data is passed to a system call}}
+  (void)(1 / dirfd);  // arg 0 is not tainted
+  system(path);   // arg 1 is not tainted
+  (void)(1 / bufsiz); // arg 3 is not tainted
+  // readlinkat never returns 0
+  return 1 / (s + 1); // expected-warning {{Division by a tainted value, possibly zero}}
+}
+
+char *get_current_dir_name(void);
+int testGet_current_dir_name() {
+  char *d = get_current_dir_name();
+  return system(d); // expected-warning {{Untrusted data is passed to a system call}}
+}
+
+int gethostname(char *name, size_t len);
+int testGethostname(char *name, size_t len) {
+  gethostname(name, len);
+  return system(name); // expected-warning {{Untrusted data is passed to a system call}}
+}
+
+struct sockaddr;
+typedef size_t socklen_t;
+int getnameinfo(const struct sockaddr *restrict addr, socklen_t addrlen,
+char *restrict host, socklen_t hostlen,
+char *restrict serv, socklen_t servlen, int flags);
+int testGetnameinfo(const struct sockaddr *restrict addr, socklen_t addrlen,
+char *restrict host, socklen_t hostlen,
+char *restrict serv, socklen_t servlen, int flags) {
+  getnameinfo(addr, addrlen, host, hostlen, serv, servlen, flags);
+
+  system(host);// expected-warning {{Untrusted data is passed to a system call}}
+  return system(serv); // expected-warning {{Untrusted data is passed to a system call}}
+}
+
+int getseuserbyname(const char *linuxuser, char **selinuxuser, char **level);
+int 

[PATCH] D120236: [analyzer] Add more sources to Taint analysis

2022-02-28 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 marked 3 inline comments as done.
gamesh411 added a comment.

readlinkat fix incoming


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D120236/new/

https://reviews.llvm.org/D120236

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


[PATCH] D120236: [analyzer] Add more sources to Taint analysis

2022-02-28 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 updated this revision to Diff 411763.
gamesh411 added a comment.
Herald added a subscriber: manas.

add readlinkat
rename _IO_getc testcase


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D120236/new/

https://reviews.llvm.org/D120236

Files:
  clang/docs/analyzer/checkers.rst
  clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
  clang/test/Analysis/taint-generic.c

Index: clang/test/Analysis/taint-generic.c
===
--- clang/test/Analysis/taint-generic.c
+++ clang/test/Analysis/taint-generic.c
@@ -45,8 +45,11 @@
 // CHECK-INVALID-ARG-SAME:that expects an argument number for propagation
 // CHECK-INVALID-ARG-SAME:rules greater or equal to -1
 
+typedef long long rsize_t;
+
 int scanf(const char *restrict format, ...);
 char *gets(char *str);
+char *gets_s(char *str, rsize_t n);
 int getchar(void);
 
 typedef struct _FILE FILE;
@@ -195,6 +198,12 @@
   system(str); // expected-warning {{Untrusted data is passed to a system call}}
 }
 
+void testGets_s(void) {
+  char str[50];
+  gets_s(str, 49);
+  system(str); // expected-warning {{Untrusted data is passed to a system call}}
+}
+
 void testTaintedBufferSize(void) {
   size_t ts;
   scanf("%zd", );
@@ -341,15 +350,112 @@
 *(volatile int *) 0; // no-warning
 }
 
-int sprintf_is_not_a_source(char *buf, char *msg) {
+int testSprintf_is_not_a_source(char *buf, char *msg) {
   int x = sprintf(buf, "%s", msg); // no-warning
-  return 1 / x; // no-warning: 'sprintf' is not a taint source
+  return 1 / x;// no-warning: 'sprintf' is not a taint source
 }
 
-int sprintf_propagates_taint(char *buf, char *msg) {
+int testSprintf_propagates_taint(char *buf, char *msg) {
   scanf("%s", msg);
   int x = sprintf(buf, "%s", msg); // propagate taint!
-  return 1 / x; // expected-warning {{Division by a tainted value, possibly zero}}
+  return 1 / x;// expected-warning {{Division by a tainted value, possibly zero}}
+}
+
+int scanf_s(const char *format, ...);
+int testScanf_s_(int *out) {
+  scanf_s("%d", out);
+  return 1 / *out; // expected-warning {{Division by a tainted value, possibly zero}}
+}
+
+#define _IO_FILE FILE
+int _IO_getc(_IO_FILE *__fp);
+int testUnderscoreIO_getc(_IO_FILE *fp) {
+  char c = _IO_getc(fp);
+  return 1 / c; // expected-warning {{Division by a tainted value, possibly zero}}
+}
+
+char *getcwd(char *buf, size_t size);
+int testGetcwd(char *buf, size_t size) {
+  char *c = getcwd(buf, size);
+  return system(c); // expected-warning {{Untrusted data is passed to a system call}}
+}
+
+char *getwd(char *buf);
+int testGetwd(char *buf) {
+  char *c = getwd(buf);
+  return system(c); // expected-warning {{Untrusted data is passed to a system call}}
+}
+
+typedef signed long long ssize_t;
+ssize_t readlink(const char *path, char *buf, size_t bufsiz);
+int testReadlink(char *path, char *buf, size_t bufsiz) {
+  ssize_t s = readlink(path, buf, bufsiz);
+  system(buf); // expected-warning {{Untrusted data is passed to a system call}}
+  // readlink never returns 0
+  return 1 / (s + 1); // expected-warning {{Division by a tainted value, possibly zero}}
+}
+
+ssize_t readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz);
+int testReadlinkat(int dirfd, char *path, char *buf, size_t bufsiz) {
+  ssize_t s = readlinkat(dirfd, path, buf, bufsiz);
+  system(buf); // expected-warning {{Untrusted data is passed to a system call}}
+  // readlinkat never returns 0
+  return 1 / (s + 1); // expected-warning {{Division by a tainted value, possibly zero}}
+}
+
+char *get_current_dir_name(void);
+int testGet_current_dir_name() {
+  char *d = get_current_dir_name();
+  return system(d); // expected-warning {{Untrusted data is passed to a system call}}
+}
+
+int gethostname(char *name, size_t len);
+int testGethostname(char *name, size_t len) {
+  gethostname(name, len);
+  return system(name); // expected-warning {{Untrusted data is passed to a system call}}
+}
+
+struct sockaddr;
+typedef size_t socklen_t;
+int getnameinfo(const struct sockaddr *restrict addr, socklen_t addrlen,
+char *restrict host, socklen_t hostlen,
+char *restrict serv, socklen_t servlen, int flags);
+int testGetnameinfo(const struct sockaddr *restrict addr, socklen_t addrlen,
+char *restrict host, socklen_t hostlen,
+char *restrict serv, socklen_t servlen, int flags) {
+  getnameinfo(addr, addrlen, host, hostlen, serv, servlen, flags);
+
+  system(host);// expected-warning {{Untrusted data is passed to a system call}}
+  return system(serv); // expected-warning {{Untrusted data is passed to a system call}}
+}
+
+int getseuserbyname(const char *linuxuser, char **selinuxuser, char **level);
+int testGetseuserbyname(const char *linuxuser, char **selinuxuser, char **level) {
+  getseuserbyname(linuxuser, selinuxuser, level);
+  

[PATCH] D120236: [analyzer] Add more sources to Taint analysis

2022-02-23 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 added inline comments.



Comment at: clang/docs/analyzer/checkers.rst:2358
 Default sources defined by ``GenericTaintChecker``:
-``fdopen``, ``fopen``, ``freopen``, ``getch``, ``getchar``, 
``getchar_unlocked``, ``gets``, ``scanf``, ``socket``, ``wgetch``
+ ``_IO_getc``, ``fdopen``, ``fopen``, ``freopen``, ``get_current_dir_name``, 
``getch``, ``getchar``, ``getchar_unlocked``, ``getcw``, ``getcwd``, 
``getgroups``, ``gethostname``, ``getlogin``, ``getlogin_r``, ``getnameinfo``, 
``getopt``, ``getopt_long``, ``getopt_only``, ``gets``, ``getseuserbyname``, 
``readlink``, ``scanf``, ``scanf_s``, ``socket``, ``wgetch``
 

steakhal wrote:
> typo/dup?
> I cannot recognize the `getcw()` call. Could you please refer to the 
> specification or an instance where it was defined?
`getwd` is the right one instead of `getcw`



Comment at: clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp:546-548
   {{"gets"}, TR::Source({{0}, ReturnValueIndex})},
   {{"scanf"}, TR::Source({{}, 1})},
+  {{"scanf_s"}, TR::Source({{}, {1}})},

steakhal wrote:
> If we handle `gets`, `scanf`, we should also model the `*_s` versions as well.
> ```lang=C
> char *gets_s(char *s, rsize_t n);
> int scanf_s(const char *restrict format, ...);
> int fscanf_s(FILE *restrict stream, const char *restrict format, ...);
> int sscanf_s(const char *restrict s, const char *restrict format, ...);
> int vscanf_s(const char *restrict format, va_list arg);
> int vfscanf_s(FILE *restrict stream, const char *restrict format, va_list 
> arg);
> int vsscanf_s(const char *restrict s, const char *restrict format, va_list 
> arg);
> ```
I have added gets_s, and will add the _s variants for the others in the other 
patch that deals with the propagatorsj.



Comment at: clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp:550-552
+  {{"getopt"}, TR::Source({{ReturnValueIndex}})},
+  {{"getopt_long"}, TR::Source({{ReturnValueIndex}})},
+  {{"getopt_long_only"}, TR::Source({{ReturnValueIndex}})},

steakhal wrote:
> IMO these functions are highly domain-specific.
> On errors, they return specific/well-defined values e.g. `-1`, `'?'` or `':'`.
> That being said, the analyzer does not have this knowledge, thus it will 
> model these as `conjured` symbols.
> If these values were modeled as tainted, we would likely introduce the number 
> of false-positives regarding our limited capabilities of modeling the 
> function accurately.
> 
> tldr; I'm against these three rules; or alternatively prove that my concerns 
> are not issues on real code bases.
I  agree that the handling of these should be in another checker, I remember 
some false positives ( mainly uninteresting, typical "just won't fix" errors ) 
relating to `getopt`, and a domain-specific checker could be more appropriate 
here.
Removed them.



Comment at: clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp:556
+  {{"getwd"}, TR::Source({{0, ReturnValueIndex}})},
+  {{"readlink"}, TR::Source({{1, ReturnValueIndex}})},
+  {{"get_current_dir_name"}, TR::Source({{ReturnValueIndex}})},

steakhal wrote:
> We should check `readlinkat` as well.
Added



Comment at: clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp:559
+  {{"gethostname"}, TR::Source({{0}})},
+  {{"getnameinfo"}, TR::Source({{2, 4}})},
+  {{"getseuserbyname"}, TR::Source({{1, 2}})},

steakhal wrote:
> In what cases can this function introduce taint?
The getnameinfo converts from
```
struct sockaddr_in {
sa_family_tsin_family; /* address family: AF_INET */
in_port_t  sin_port;   /* port in network byte order */
struct in_addr sin_addr;   /* internet address */
};

/* Internet address */
struct in_addr {
uint32_t   s_addr; /* address in network byte order */
};
```
to hostname and servername strings.
One could argue that by crafting a specific IP address, that  is known to 
resolve to a specific hostname in the running environment could lead an 
attacker injecting a chosen (in some circumstances arbitrary) string into the 
code at the point of this function.

I know this is a bit contrived, and more on the cybersecurity side of things, 
so I am not sure whether to add this here, or add this in a specific checker, 
or just leave altogether. Please share your opinion about this.



Comment at: clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp:561
+  {{"getseuserbyname"}, TR::Source({{1, 2}})},
+  {{"getgroups"}, TR::Source({{1}})},
+  {{"getlogin"}, TR::Source({{ReturnValueIndex}})},

steakhal wrote:
> >On success, `getgroups()` returns the number of supplementary group IDs. On 
> >error, -1 is returned, and `errno` is set appropriately.
> 
> According to this, the return value index should be also tainted.
Added





[PATCH] D120236: [analyzer] Add more sources to Taint analysis

2022-02-23 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 updated this revision to Diff 410747.
gamesh411 marked 9 inline comments as done.
gamesh411 added a comment.

- s/getcw/getwd
- add gets_s
- remove getopt variants
- add realinkat
- discuss getnameinfo?
- rename tests
- update getnameinfo
- comment on source/propagator discrepancy
- update tests where 1 / tainted, and tainted cannot be 0
- renamed tests


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D120236/new/

https://reviews.llvm.org/D120236

Files:
  clang/docs/analyzer/checkers.rst
  clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
  clang/test/Analysis/taint-generic.c

Index: clang/test/Analysis/taint-generic.c
===
--- clang/test/Analysis/taint-generic.c
+++ clang/test/Analysis/taint-generic.c
@@ -45,8 +45,11 @@
 // CHECK-INVALID-ARG-SAME:that expects an argument number for propagation
 // CHECK-INVALID-ARG-SAME:rules greater or equal to -1
 
+typedef long long rsize_t;
+
 int scanf(const char *restrict format, ...);
 char *gets(char *str);
+char *gets_s(char *str, rsize_t n);
 int getchar(void);
 
 typedef struct _FILE FILE;
@@ -195,6 +198,12 @@
   system(str); // expected-warning {{Untrusted data is passed to a system call}}
 }
 
+void testGets_s(void) {
+  char str[50];
+  gets_s(str, 49);
+  system(str); // expected-warning {{Untrusted data is passed to a system call}}
+}
+
 void testTaintedBufferSize(void) {
   size_t ts;
   scanf("%zd", );
@@ -341,15 +350,112 @@
 *(volatile int *) 0; // no-warning
 }
 
-int sprintf_is_not_a_source(char *buf, char *msg) {
+int testSprintf_is_not_a_source(char *buf, char *msg) {
   int x = sprintf(buf, "%s", msg); // no-warning
-  return 1 / x; // no-warning: 'sprintf' is not a taint source
+  return 1 / x;// no-warning: 'sprintf' is not a taint source
 }
 
-int sprintf_propagates_taint(char *buf, char *msg) {
+int testSprintf_propagates_taint(char *buf, char *msg) {
   scanf("%s", msg);
   int x = sprintf(buf, "%s", msg); // propagate taint!
-  return 1 / x; // expected-warning {{Division by a tainted value, possibly zero}}
+  return 1 / x;// expected-warning {{Division by a tainted value, possibly zero}}
+}
+
+int scanf_s(const char *format, ...);
+int testScanf_s_(int *out) {
+  scanf_s("%d", out);
+  return 1 / *out; // expected-warning {{Division by a tainted value, possibly zero}}
+}
+
+#define _IO_FILE FILE
+int _IO_getc(_IO_FILE *__fp);
+int test_IO_getc(_IO_FILE *fp) {
+  char c = _IO_getc(fp);
+  return 1 / c; // expected-warning {{Division by a tainted value, possibly zero}}
+}
+
+char *getcwd(char *buf, size_t size);
+int testGetcwd(char *buf, size_t size) {
+  char *c = getcwd(buf, size);
+  return system(c); // expected-warning {{Untrusted data is passed to a system call}}
+}
+
+char *getwd(char *buf);
+int testGetwd(char *buf) {
+  char *c = getwd(buf);
+  return system(c); // expected-warning {{Untrusted data is passed to a system call}}
+}
+
+typedef signed long long ssize_t;
+ssize_t readlink(const char *path, char *buf, size_t bufsiz);
+int testReadlink(char *path, char *buf, size_t bufsiz) {
+  ssize_t s = readlink(path, buf, bufsiz);
+  system(buf); // expected-warning {{Untrusted data is passed to a system call}}
+  // readlink never returns 0
+  return 1 / (s + 1); // expected-warning {{Division by a tainted value, possibly zero}}
+}
+
+ssize_t readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz);
+int testReadlinkat(int dirfd, char *path, char *buf, size_t bufsiz) {
+  ssize_t s = readlinkat(dirfd, path, buf, bufsiz);
+  system(buf); // expected-warning {{Untrusted data is passed to a system call}}
+  // readlinkat never returns 0
+  return 1 / (s + 1); // expected-warning {{Division by a tainted value, possibly zero}}
+}
+
+char *get_current_dir_name(void);
+int testGet_current_dir_name() {
+  char *d = get_current_dir_name();
+  return system(d); // expected-warning {{Untrusted data is passed to a system call}}
+}
+
+int gethostname(char *name, size_t len);
+int testGethostname(char *name, size_t len) {
+  gethostname(name, len);
+  return system(name); // expected-warning {{Untrusted data is passed to a system call}}
+}
+
+struct sockaddr;
+typedef size_t socklen_t;
+int getnameinfo(const struct sockaddr *restrict addr, socklen_t addrlen,
+char *restrict host, socklen_t hostlen,
+char *restrict serv, socklen_t servlen, int flags);
+int testGetnameinfo(const struct sockaddr *restrict addr, socklen_t addrlen,
+char *restrict host, socklen_t hostlen,
+char *restrict serv, socklen_t servlen, int flags) {
+  getnameinfo(addr, addrlen, host, hostlen, serv, servlen, flags);
+
+  system(host);// expected-warning {{Untrusted data is passed to a system call}}
+  return system(serv); // expected-warning {{Untrusted data is passed to a system call}}
+}
+
+int 

[PATCH] D120369: [analyzer] Add more propagations to Taint analysis

2022-02-22 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 created this revision.
gamesh411 added a reviewer: steakhal.
Herald added subscribers: ASDenysPetrov, martong, dkrupp, donat.nagy, 
Szelethus, mikhail.ramalho, a.sidorin, szepet, baloghadamsoftware, xazax.hun.
Herald added a reviewer: Szelethus.
gamesh411 requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Add more functions as taint propators to GenericTaintChecker.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D120369

Files:
  clang/docs/analyzer/checkers.rst
  clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
  clang/test/Analysis/taint-generic.c

Index: clang/test/Analysis/taint-generic.c
===
--- clang/test/Analysis/taint-generic.c
+++ clang/test/Analysis/taint-generic.c
@@ -1,11 +1,13 @@
-// RUN: %clang_analyze_cc1 -Wno-format-security -Wno-pointer-to-int-cast -verify %s \
+// RUN: %clang_analyze_cc1 -Wno-format-security -Wno-pointer-to-int-cast \
+// RUN:   -Wno-incompatible-library-redeclaration -verify %s \
 // RUN:   -analyzer-checker=alpha.security.taint \
 // RUN:   -analyzer-checker=core \
 // RUN:   -analyzer-checker=alpha.security.ArrayBoundV2 \
 // RUN:   -analyzer-config \
 // RUN: alpha.security.taint.TaintPropagation:Config=%S/Inputs/taint-generic-config.yaml
 
-// RUN: %clang_analyze_cc1 -Wno-format-security -Wno-pointer-to-int-cast -verify %s \
+// RUN: %clang_analyze_cc1 -Wno-format-security -Wno-pointer-to-int-cast \
+// RUN:   -Wno-incompatible-library-redeclaration -verify %s \
 // RUN:   -DFILE_IS_STRUCT \
 // RUN:   -analyzer-checker=alpha.security.taint \
 // RUN:   -analyzer-checker=core \
@@ -13,7 +15,8 @@
 // RUN:   -analyzer-config \
 // RUN: alpha.security.taint.TaintPropagation:Config=%S/Inputs/taint-generic-config.yaml
 
-// RUN: not %clang_analyze_cc1 -Wno-pointer-to-int-cast -verify %s \
+// RUN: not %clang_analyze_cc1 -Wno-pointer-to-int-cast \
+// RUN:   -Wno-incompatible-library-redeclaration -verify %s \
 // RUN:   -analyzer-checker=alpha.security.taint \
 // RUN:   -analyzer-config \
 // RUN: alpha.security.taint.TaintPropagation:Config=justguessit \
@@ -24,7 +27,8 @@
 // CHECK-INVALID-FILE-SAME:that expects a valid filename instead of
 // CHECK-INVALID-FILE-SAME:'justguessit'
 
-// RUN: not %clang_analyze_cc1 -verify %s \
+// RUN: not %clang_analyze_cc1 -Wno-incompatible-library-redeclaration \
+// RUN:   -verify %s \
 // RUN:   -analyzer-checker=alpha.security.taint \
 // RUN:   -analyzer-config \
 // RUN: alpha.security.taint.TaintPropagation:Config=%S/Inputs/taint-generic-config-ill-formed.yaml \
@@ -34,7 +38,8 @@
 // CHECK-ILL-FORMED-SAME:'alpha.security.taint.TaintPropagation:Config',
 // CHECK-ILL-FORMED-SAME:that expects a valid yaml file: [[MSG]]
 
-// RUN: not %clang_analyze_cc1 -verify %s \
+// RUN: not %clang_analyze_cc1 -Wno-incompatible-library-redeclaration \
+// RUN:   -verify %s \
 // RUN:   -analyzer-checker=alpha.security.taint \
 // RUN:   -analyzer-config \
 // RUN: alpha.security.taint.TaintPropagation:Config=%S/Inputs/taint-generic-config-invalid-arg.yaml \
@@ -45,6 +50,8 @@
 // CHECK-INVALID-ARG-SAME:that expects an argument number for propagation
 // CHECK-INVALID-ARG-SAME:rules greater or equal to -1
 
+extern int some_global_flag_to_branch_on;
+
 int scanf(const char *restrict format, ...);
 char *gets(char *str);
 int getchar(void);
@@ -58,6 +65,8 @@
 
 #define bool _Bool
 
+FILE *fopen(const char *name, const char *mode);
+
 int fscanf(FILE *restrict stream, const char *restrict format, ...);
 int sprintf(char *str, const char *format, ...);
 void setproctitle(const char *fmt, ...);
@@ -352,6 +361,596 @@
   return 1 / x; // expected-warning {{Division by a tainted value, possibly zero}}
 }
 
+int fscanf_s(FILE *stream, const char *format, ...);
+int testFscanf_s(const char *fname, int *d) {
+  FILE *f = fopen(fname, "r");
+  fscanf_s(f, "%d", d);
+  return 1 / *d; // expected-warning {{Division by a tainted value, possibly zero}}
+}
+
+int vscanf(const char *format, ...);
+int testVscanf(int *d) {
+  char format[10];
+  scanf("%9s", format); // fake a tainted a file descriptor
+
+  vscanf(format, );
+  return 1 / *d; // expected-warning {{Division by a tainted value, possibly zero}}
+}
+
+int vfscanf(FILE *stream, const char *format, ...);
+int testVfscanf(const char *fname, int *d) {
+  FILE *f = fopen(fname, "r");
+  vfscanf(f, "%d", d);
+  return 1 / *d; // expected-warning {{Division by a tainted value, possibly zero}}
+}
+
+int fread(void *buffer, size_t size, size_t count, FILE *stream);
+int testFread(const char *fname, int *buffer, size_t size, size_t count) {
+  FILE *f = fopen(fname, "r");
+  size_t read = fread(buffer, size, count, f);
+
+  if (some_global_flag_to_branch_on) // just to have 2 branches, and assert 2 division by zero messages
+return 1 / *buffer;  // expected-warning 

[PATCH] D120236: Add more sources to Taint analysis

2022-02-21 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 created this revision.
gamesh411 added a reviewer: steakhal.
Herald added subscribers: martong, Szelethus, dkrupp.
Herald added a reviewer: Szelethus.
gamesh411 requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Add more functions as taint sources to GenericTaintChecker.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D120236

Files:
  clang/docs/analyzer/checkers.rst
  clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
  clang/test/Analysis/taint-generic.c

Index: clang/test/Analysis/taint-generic.c
===
--- clang/test/Analysis/taint-generic.c
+++ clang/test/Analysis/taint-generic.c
@@ -352,6 +352,119 @@
   return 1 / x; // expected-warning {{Division by a tainted value, possibly zero}}
 }
 
+int scanf_s(const char *format, ...);
+int scanf_s_is_source(int *out) {
+  scanf_s("%d", out);
+  return 1 / *out; // expected-warning {{Division by a tainted value, possibly zero}}
+}
+
+int getopt(int argc, char *const argv[], const char *optstring);
+int getopt_is_source(int argc, char **argv) {
+  int opt = getopt(argc, argv, "nt:");
+  return 1 / opt; // expected-warning {{Division by a tainted value, possibly zero}}
+}
+
+struct option {
+  const char *name;
+  int has_arg;
+  int *flag;
+  int val;
+};
+int getopt_long(int argc, char *const argv[], const char *optstring, const struct option *longopts, int *longindex);
+int getopt_long_is_source(int argc, char **argv) {
+  int option_index = 0;
+  struct option long_opts[] = {{0, 0, 0, 0}};
+  int opt = getopt_long(argc, argv, "a:b:02", long_opts, _index);
+  return 1 / opt; // expected-warning {{Division by a tainted value, possibly zero}}
+}
+
+int getopt_long_only(int argc, char *const argv[], const char *optstring, const struct option *longopts, int *longindex);
+int getopt_long_only_is_source(int argc, char **argv) {
+  int option_index = 0;
+  struct option long_opts[] = {{0, 0, 0, 0}};
+  int opt = getopt_long_only(argc, argv, "a:b:02", long_opts, _index);
+  return 1 / opt; // expected-warning {{Division by a tainted value, possibly zero}}
+}
+
+#define _IO_FILE FILE
+int _IO_getc(_IO_FILE *__fp);
+int underscore_IO_getc_is_source(_IO_FILE *fp) {
+  char c = _IO_getc(fp);
+  return 1 / c; // expected-warning {{Division by a tainted value, possibly zero}}
+}
+
+char *getcwd(char *buf, size_t size);
+int getcwd_is_source(char *buf, size_t size) {
+  char *c = getcwd(buf, size);
+  return system(c); // expected-warning {{Untrusted data is passed to a system call}}
+}
+
+char *getwd(char *buf);
+int getwd_is_source(char *buf) {
+  char *c = getwd(buf);
+  return system(c); // expected-warning {{Untrusted data is passed to a system call}}
+}
+
+typedef signed long long ssize_t;
+ssize_t readlink(const char *path, char *buf, size_t bufsiz);
+int readlink_is_source(char *path, char *buf, size_t bufsiz) {
+  ssize_t s = readlink(path, buf, bufsiz);
+  system(buf);  // expected-warning {{Untrusted data is passed to a system call}}
+  return 1 / s; // expected-warning {{Division by a tainted value, possibly zero}}
+}
+
+char *get_current_dir_name(void);
+int get_current_dir_name_is_source() {
+  char *d = get_current_dir_name();
+  return system(d); // expected-warning {{Untrusted data is passed to a system call}}
+}
+
+int gethostname(char *name, size_t len);
+int gethostname_is_source(char *name, size_t len) {
+  gethostname(name, len);
+  return system(name); // expected-warning {{Untrusted data is passed to a system call}}
+}
+
+struct sockaddr;
+typedef size_t socklen_t;
+int getnameinfo(const struct sockaddr *restrict addr, socklen_t addrlen,
+   char *restrict host, socklen_t hostlen,
+   char *restrict serv, socklen_t servlen, int flags);
+int getnameinfo_is_source(const struct sockaddr *restrict addr, socklen_t addrlen,
+   char *restrict host, socklen_t hostlen,
+   char *restrict serv, socklen_t servlen, int flags) {
+  getnameinfo(addr, addrlen, host, hostlen, serv, servlen, flags);
+
+  system(host); // expected-warning {{Untrusted data is passed to a system call}}
+  return system(serv); // expected-warning {{Untrusted data is passed to a system call}}
+}
+
+int getseuserbyname(const char *linuxuser, char **selinuxuser, char **level);
+int getseuserbyname_is_source(const char* linuxuser, char **selinuxuser, char**level) {
+  getseuserbyname(linuxuser, selinuxuser, level);
+  system(selinuxuser[0]); // expected-warning {{Untrusted data is passed to a system call}}
+  return system(level[0]);// expected-warning {{Untrusted data is passed to a system call}}
+}
+
+typedef int gid_t;
+int getgroups(int size, gid_t list[]);
+int getgroups_is_source(int size, gid_t list[]) {
+  getgroups(size, list);
+  return 1 / list[0]; // expected-warning {{Division by a tainted value, possibly zero}}
+}
+
+char *getlogin(void);
+int 

[PATCH] D116025: [analyzer][NFC] Refactor GenericTaintChecker to use CallDescriptionMap

2022-01-18 Thread Endre Fülöp via Phabricator via cfe-commits
This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rG17f74240e6c3: [analyzer][NFC] Refactor GenericTaintChecker 
to use CallDescriptionMap (authored by gamesh411).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D116025/new/

https://reviews.llvm.org/D116025

Files:
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
  clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp

Index: clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
@@ -22,15 +22,14 @@
 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
 #include "clang/StaticAnalyzer/Core/Checker.h"
 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
 #include "llvm/Support/YAMLTraits.h"
 
-#include 
 #include 
 #include 
-#include 
 #include 
 
 using namespace clang;
@@ -38,577 +37,651 @@
 using namespace taint;
 
 namespace {
-class GenericTaintChecker : public Checker {
-public:
-  static void *getTag() {
-static int Tag;
-return 
+
+class GenericTaintChecker;
+
+/// Check for CWE-134: Uncontrolled Format String.
+constexpr llvm::StringLiteral MsgUncontrolledFormatString =
+"Untrusted data is used as a format string "
+"(CWE-134: Uncontrolled Format String)";
+
+/// Check for:
+/// CERT/STR02-C. "Sanitize data passed to complex subsystems"
+/// CWE-78, "Failure to Sanitize Data into an OS Command"
+constexpr llvm::StringLiteral MsgSanitizeSystemArgs =
+"Untrusted data is passed to a system call "
+"(CERT/STR02-C. Sanitize data passed to complex subsystems)";
+
+/// Check if tainted data is used as a buffer size in strn.. functions,
+/// and allocators.
+constexpr llvm::StringLiteral MsgTaintedBufferSize =
+"Untrusted data is used to specify the buffer size "
+"(CERT/STR31-C. Guarantee that storage for strings has sufficient space "
+"for character data and the null terminator)";
+
+/// Check if tainted data is used as a custom sink's parameter.
+constexpr llvm::StringLiteral MsgCustomSink =
+"Untrusted data is passed to a user-defined sink";
+
+using ArgIdxTy = int;
+using ArgVecTy = llvm::SmallVector;
+
+/// Denotes the return value.
+constexpr ArgIdxTy ReturnValueIndex{-1};
+
+static ArgIdxTy fromArgumentCount(unsigned Count) {
+  assert(Count <=
+ static_cast(std::numeric_limits::max()) &&
+ "ArgIdxTy is not large enough to represent the number of arguments.");
+  return Count;
+}
+
+/// Check if the region the expression evaluates to is the standard input,
+/// and thus, is tainted.
+/// FIXME: Move this to Taint.cpp.
+bool isStdin(SVal Val, const ASTContext ) {
+  // FIXME: What if Val is NonParamVarRegion?
+
+  // The region should be symbolic, we do not know it's value.
+  const auto *SymReg = dyn_cast_or_null(Val.getAsRegion());
+  if (!SymReg)
+return false;
+
+  // Get it's symbol and find the declaration region it's pointing to.
+  const auto *Sm = dyn_cast(SymReg->getSymbol());
+  if (!Sm)
+return false;
+  const auto *DeclReg = dyn_cast(Sm->getRegion());
+  if (!DeclReg)
+return false;
+
+  // This region corresponds to a declaration, find out if it's a global/extern
+  // variable named stdin with the proper type.
+  if (const auto *D = dyn_cast_or_null(DeclReg->getDecl())) {
+D = D->getCanonicalDecl();
+// FIXME: This should look for an exact match.
+if (D->getName().contains("stdin") && D->isExternC()) {
+  const QualType FILETy = ACtx.getFILEType().getCanonicalType();
+  const QualType Ty = D->getType().getCanonicalType();
+
+  if (Ty->isPointerType())
+return Ty->getPointeeType() == FILETy;
+}
   }
+  return false;
+}
 
-  void checkPreCall(const CallEvent , CheckerContext ) const;
-  void checkPostCall(const CallEvent , CheckerContext ) const;
+SVal getPointeeOf(const CheckerContext , Loc LValue) {
+  const QualType ArgTy = LValue.getType(C.getASTContext());
+  if (!ArgTy->isPointerType() || !ArgTy->getPointeeType()->isVoidType())
+return C.getState()->getSVal(LValue);
 
-  void printState(raw_ostream , ProgramStateRef State, const char *NL,
-  const char *Sep) const override;
+  // Do not dereference void pointers. Treat them as byte pointers instead.
+  // FIXME: we might want to consider more than just the first byte.
+  return C.getState()->getSVal(LValue, C.getASTContext().CharTy);
+}
+
+/// Given a pointer/reference argument, return the value it refers to.

[PATCH] D116025: [analyzer][NFC] Refactor GenericTaintChecker to use CallDescriptionMap

2022-01-18 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 updated this revision to Diff 400790.
gamesh411 added a comment.

Remove explicit template keyword for MSVC compatibility


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D116025/new/

https://reviews.llvm.org/D116025

Files:
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
  clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp

Index: clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
@@ -22,15 +22,14 @@
 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
 #include "clang/StaticAnalyzer/Core/Checker.h"
 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
 #include "llvm/Support/YAMLTraits.h"
 
-#include 
 #include 
 #include 
-#include 
 #include 
 
 using namespace clang;
@@ -38,577 +37,651 @@
 using namespace taint;
 
 namespace {
-class GenericTaintChecker : public Checker {
-public:
-  static void *getTag() {
-static int Tag;
-return 
+
+class GenericTaintChecker;
+
+/// Check for CWE-134: Uncontrolled Format String.
+constexpr llvm::StringLiteral MsgUncontrolledFormatString =
+"Untrusted data is used as a format string "
+"(CWE-134: Uncontrolled Format String)";
+
+/// Check for:
+/// CERT/STR02-C. "Sanitize data passed to complex subsystems"
+/// CWE-78, "Failure to Sanitize Data into an OS Command"
+constexpr llvm::StringLiteral MsgSanitizeSystemArgs =
+"Untrusted data is passed to a system call "
+"(CERT/STR02-C. Sanitize data passed to complex subsystems)";
+
+/// Check if tainted data is used as a buffer size in strn.. functions,
+/// and allocators.
+constexpr llvm::StringLiteral MsgTaintedBufferSize =
+"Untrusted data is used to specify the buffer size "
+"(CERT/STR31-C. Guarantee that storage for strings has sufficient space "
+"for character data and the null terminator)";
+
+/// Check if tainted data is used as a custom sink's parameter.
+constexpr llvm::StringLiteral MsgCustomSink =
+"Untrusted data is passed to a user-defined sink";
+
+using ArgIdxTy = int;
+using ArgVecTy = llvm::SmallVector;
+
+/// Denotes the return value.
+constexpr ArgIdxTy ReturnValueIndex{-1};
+
+static ArgIdxTy fromArgumentCount(unsigned Count) {
+  assert(Count <=
+ static_cast(std::numeric_limits::max()) &&
+ "ArgIdxTy is not large enough to represent the number of arguments.");
+  return Count;
+}
+
+/// Check if the region the expression evaluates to is the standard input,
+/// and thus, is tainted.
+/// FIXME: Move this to Taint.cpp.
+bool isStdin(SVal Val, const ASTContext ) {
+  // FIXME: What if Val is NonParamVarRegion?
+
+  // The region should be symbolic, we do not know it's value.
+  const auto *SymReg = dyn_cast_or_null(Val.getAsRegion());
+  if (!SymReg)
+return false;
+
+  // Get it's symbol and find the declaration region it's pointing to.
+  const auto *Sm = dyn_cast(SymReg->getSymbol());
+  if (!Sm)
+return false;
+  const auto *DeclReg = dyn_cast(Sm->getRegion());
+  if (!DeclReg)
+return false;
+
+  // This region corresponds to a declaration, find out if it's a global/extern
+  // variable named stdin with the proper type.
+  if (const auto *D = dyn_cast_or_null(DeclReg->getDecl())) {
+D = D->getCanonicalDecl();
+// FIXME: This should look for an exact match.
+if (D->getName().contains("stdin") && D->isExternC()) {
+  const QualType FILETy = ACtx.getFILEType().getCanonicalType();
+  const QualType Ty = D->getType().getCanonicalType();
+
+  if (Ty->isPointerType())
+return Ty->getPointeeType() == FILETy;
+}
   }
+  return false;
+}
 
-  void checkPreCall(const CallEvent , CheckerContext ) const;
-  void checkPostCall(const CallEvent , CheckerContext ) const;
+SVal getPointeeOf(const CheckerContext , Loc LValue) {
+  const QualType ArgTy = LValue.getType(C.getASTContext());
+  if (!ArgTy->isPointerType() || !ArgTy->getPointeeType()->isVoidType())
+return C.getState()->getSVal(LValue);
 
-  void printState(raw_ostream , ProgramStateRef State, const char *NL,
-  const char *Sep) const override;
+  // Do not dereference void pointers. Treat them as byte pointers instead.
+  // FIXME: we might want to consider more than just the first byte.
+  return C.getState()->getSVal(LValue, C.getASTContext().CharTy);
+}
+
+/// Given a pointer/reference argument, return the value it refers to.
+Optional getPointeeOf(const CheckerContext , SVal Arg) {
+  if (auto LValue = Arg.getAs())
+return getPointeeOf(C, *LValue);
+  

[PATCH] D116025: [analyzer][NFC] Refactor GenericTaintChecker to use CallDescriptionMap

2022-01-17 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 updated this revision to Diff 400498.
gamesh411 added a comment.

All commits were exluded in the previous patch upload


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D116025/new/

https://reviews.llvm.org/D116025

Files:
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
  clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp

Index: clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
@@ -22,15 +22,14 @@
 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
 #include "clang/StaticAnalyzer/Core/Checker.h"
 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
 #include "llvm/Support/YAMLTraits.h"
 
-#include 
 #include 
 #include 
-#include 
 #include 
 
 using namespace clang;
@@ -38,577 +37,651 @@
 using namespace taint;
 
 namespace {
-class GenericTaintChecker : public Checker {
-public:
-  static void *getTag() {
-static int Tag;
-return 
+
+class GenericTaintChecker;
+
+/// Check for CWE-134: Uncontrolled Format String.
+constexpr llvm::StringLiteral MsgUncontrolledFormatString =
+"Untrusted data is used as a format string "
+"(CWE-134: Uncontrolled Format String)";
+
+/// Check for:
+/// CERT/STR02-C. "Sanitize data passed to complex subsystems"
+/// CWE-78, "Failure to Sanitize Data into an OS Command"
+constexpr llvm::StringLiteral MsgSanitizeSystemArgs =
+"Untrusted data is passed to a system call "
+"(CERT/STR02-C. Sanitize data passed to complex subsystems)";
+
+/// Check if tainted data is used as a buffer size in strn.. functions,
+/// and allocators.
+constexpr llvm::StringLiteral MsgTaintedBufferSize =
+"Untrusted data is used to specify the buffer size "
+"(CERT/STR31-C. Guarantee that storage for strings has sufficient space "
+"for character data and the null terminator)";
+
+/// Check if tainted data is used as a custom sink's parameter.
+constexpr llvm::StringLiteral MsgCustomSink =
+"Untrusted data is passed to a user-defined sink";
+
+using ArgIdxTy = int;
+using ArgVecTy = llvm::SmallVector;
+
+/// Denotes the return value.
+constexpr ArgIdxTy ReturnValueIndex{-1};
+
+static ArgIdxTy fromArgumentCount(unsigned Count) {
+  assert(Count <=
+ static_cast(std::numeric_limits::max()) &&
+ "ArgIdxTy is not large enough to represent the number of arguments.");
+  return Count;
+}
+
+/// Check if the region the expression evaluates to is the standard input,
+/// and thus, is tainted.
+/// FIXME: Move this to Taint.cpp.
+bool isStdin(SVal Val, const ASTContext ) {
+  // FIXME: What if Val is NonParamVarRegion?
+
+  // The region should be symbolic, we do not know it's value.
+  const auto *SymReg = dyn_cast_or_null(Val.getAsRegion());
+  if (!SymReg)
+return false;
+
+  // Get it's symbol and find the declaration region it's pointing to.
+  const auto *Sm = dyn_cast(SymReg->getSymbol());
+  if (!Sm)
+return false;
+  const auto *DeclReg = dyn_cast(Sm->getRegion());
+  if (!DeclReg)
+return false;
+
+  // This region corresponds to a declaration, find out if it's a global/extern
+  // variable named stdin with the proper type.
+  if (const auto *D = dyn_cast_or_null(DeclReg->getDecl())) {
+D = D->getCanonicalDecl();
+// FIXME: This should look for an exact match.
+if (D->getName().contains("stdin") && D->isExternC()) {
+  const QualType FILETy = ACtx.getFILEType().getCanonicalType();
+  const QualType Ty = D->getType().getCanonicalType();
+
+  if (Ty->isPointerType())
+return Ty->getPointeeType() == FILETy;
+}
   }
+  return false;
+}
 
-  void checkPreCall(const CallEvent , CheckerContext ) const;
-  void checkPostCall(const CallEvent , CheckerContext ) const;
+SVal getPointeeOf(const CheckerContext , Loc LValue) {
+  const QualType ArgTy = LValue.getType(C.getASTContext());
+  if (!ArgTy->isPointerType() || !ArgTy->getPointeeType()->isVoidType())
+return C.getState()->getSVal(LValue);
 
-  void printState(raw_ostream , ProgramStateRef State, const char *NL,
-  const char *Sep) const override;
+  // Do not dereference void pointers. Treat them as byte pointers instead.
+  // FIXME: we might want to consider more than just the first byte.
+  return C.getState()->getSVal(LValue, C.getASTContext().CharTy);
+}
+
+/// Given a pointer/reference argument, return the value it refers to.
+Optional getPointeeOf(const CheckerContext , SVal Arg) {
+  if (auto LValue = Arg.getAs())
+return getPointeeOf(C, *LValue);
+  

[PATCH] D114706: [analyzer] Fix sensitive argument logic in GenericTaintChecker

2022-01-17 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 abandoned this revision.
gamesh411 added a comment.

This is superseded by D116025 .


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D114706/new/

https://reviews.llvm.org/D114706

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


[PATCH] D116025: [analyzer][NFC] Refactor GenericTaintChecker to use CallDescriptionMap

2022-01-17 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 added a comment.

Applied typo and naming fixes, introduced 2 move operations, and re-introduced 
short circuiting.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D116025/new/

https://reviews.llvm.org/D116025

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


[PATCH] D116025: [analyzer][NFC] Refactor GenericTaintChecker to use CallDescriptionMap

2022-01-17 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 updated this revision to Diff 400464.
gamesh411 marked 7 inline comments as done.
gamesh411 added a comment.

Fixes round two


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D116025/new/

https://reviews.llvm.org/D116025

Files:
  clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp


Index: clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
@@ -52,7 +52,7 @@
 "Untrusted data is passed to a system call "
 "(CERT/STR02-C. Sanitize data passed to complex subsystems)";
 
-/// Check if tainted data is used as a buffer size ins strn.. functions,
+/// Check if tainted data is used as a buffer size in strn.. functions,
 /// and allocators.
 constexpr llvm::StringLiteral MsgTaintedBufferSize =
 "Untrusted data is used to specify the buffer size "
@@ -160,7 +160,8 @@
 public:
   ArgSet() = default;
   ArgSet(ArgVecTy &, Optional VariadicIndex = None)
-  : DiscreteArgs(DiscreteArgs), VariadicIndex(VariadicIndex) {}
+  : DiscreteArgs(std::move(DiscreteArgs)),
+VariadicIndex(std::move(VariadicIndex)) {}
 
   bool contains(ArgIdxTy ArgIdx) const {
 if (llvm::is_contained(DiscreteArgs, ArgIdx))
@@ -308,13 +309,13 @@
  TaintConfiguration &) const;
 
 private:
-  using NamePartTy = llvm::SmallVector, 2>;
+  using NamePartsTy = llvm::SmallVector, 2>;
 
   /// Validate part of the configuration, which contains a list of argument
   /// indexes.
   void validateArgVector(const std::string , const ArgVecTy ) 
const;
 
-  template  static NamePartTy parseNameParts(const Config );
+  template  static NamePartsTy parseNameParts(const Config 
);
 
   // Takes the config and creates a CallDescription for it and associates a 
Rule
   // with that.
@@ -445,9 +446,9 @@
 }
 
 template 
-GenericTaintRuleParser::NamePartTy
+GenericTaintRuleParser::NamePartsTy
 GenericTaintRuleParser::parseNameParts(const Config ) {
-  NamePartTy NameParts;
+  NamePartsTy NameParts;
   if (!C.Scope.empty()) {
 // If the Scope argument contains multiple "::" parts, those are considered
 // namespace identifiers.
@@ -464,7 +465,7 @@
 void GenericTaintRuleParser::consumeRulesFromConfig(const Config ,
 GenericTaintRule &,
 RulesContTy ) {
-  NamePartTy NameParts = parseNameParts(C);
+  NamePartsTy NameParts = parseNameParts(C);
   llvm::SmallVector CallDescParts{NameParts.size()};
   llvm::transform(NameParts, CallDescParts.begin(),
   [](SmallString<32> ) { return S.c_str(); });
@@ -642,6 +643,7 @@
   llvm::Optional Config =
   getConfiguration(*Mgr, this, Option, ConfigFile);
   if (!Config) {
+// We don't have external taint config, no parsing required.
 DynamicTaintRules = RuleLookupTy{};
 return;
   }
@@ -746,8 +748,8 @@
   bool IsMatching = PropSrcArgs.isEmpty();
   ForEachCallArg(
   [this, , , ](ArgIdxTy I, const Expr *E, SVal) {
-IsMatching |=
-PropSrcArgs.contains(I) && isTaintedOrPointsToTainted(E, State, C);
+IsMatching = IsMatching || (PropSrcArgs.contains(I) &&
+isTaintedOrPointsToTainted(E, State, C));
   });
 
   if (!IsMatching)
@@ -860,7 +862,7 @@
 
   SourceLocation DomLoc = Call.getArgExpr(0)->getExprLoc();
   StringRef DomName = C.getMacroNameOrSpelling(DomLoc);
-  // White list the internal communication protocols.
+  // Allow internal communication protocols.
   bool SafeProtocol = DomName.equals("AF_SYSTEM") ||
   DomName.equals("AF_LOCAL") || DomName.equals("AF_UNIX") 
||
   DomName.equals("AF_RESERVED_36");


Index: clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
@@ -52,7 +52,7 @@
 "Untrusted data is passed to a system call "
 "(CERT/STR02-C. Sanitize data passed to complex subsystems)";
 
-/// Check if tainted data is used as a buffer size ins strn.. functions,
+/// Check if tainted data is used as a buffer size in strn.. functions,
 /// and allocators.
 constexpr llvm::StringLiteral MsgTaintedBufferSize =
 "Untrusted data is used to specify the buffer size "
@@ -160,7 +160,8 @@
 public:
   ArgSet() = default;
   ArgSet(ArgVecTy &, Optional VariadicIndex = None)
-  : DiscreteArgs(DiscreteArgs), VariadicIndex(VariadicIndex) {}
+  : DiscreteArgs(std::move(DiscreteArgs)),
+VariadicIndex(std::move(VariadicIndex)) {}
 
   bool contains(ArgIdxTy ArgIdx) const {
 if (llvm::is_contained(DiscreteArgs, ArgIdx))
@@ -308,13 +309,13 @@
  

[PATCH] D116025: [analyzer][NFC] Refactor GenericTaintChecker to use CallDescriptionMap

2022-01-12 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 updated this revision to Diff 399246.
gamesh411 added a comment.

Tidy things up thanks to the recommendations of @steakhal


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D116025/new/

https://reviews.llvm.org/D116025

Files:
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
  clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp

Index: clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
@@ -38,6 +38,8 @@
 
 namespace {
 
+class GenericTaintChecker;
+
 /// Check for CWE-134: Uncontrolled Format String.
 constexpr llvm::StringLiteral MsgUncontrolledFormatString =
 "Untrusted data is used as a format string "
@@ -62,23 +64,26 @@
 "Untrusted data is passed to a user-defined sink";
 
 using ArgIdxTy = int;
-using ArgVecTy = llvm::SmallVector;
+using ArgVecTy = llvm::SmallVector;
 
-constexpr int InvalidArgIndex{-2};
 /// Denotes the return value.
-constexpr int ReturnValueIndex{-1};
+constexpr ArgIdxTy ReturnValueIndex{-1};
+
+static ArgIdxTy fromArgumentCount(unsigned Count) {
+  assert(Count <=
+ static_cast(std::numeric_limits::max()) &&
+ "ArgIdxTy is not large enough to represent the number of arguments.");
+  return Count;
+}
 
 /// Check if the region the expression evaluates to is the standard input,
 /// and thus, is tainted.
-bool isStdin(const Expr *E, CheckerContext ) {
-  ProgramStateRef State = C.getState();
-  SVal Val = C.getSVal(E);
-
-  // stdin is a pointer, so it would be a region.
-  const MemRegion *MemReg = Val.getAsRegion();
+/// FIXME: Move this to Taint.cpp.
+bool isStdin(SVal Val, const ASTContext ) {
+  // FIXME: What if Val is NonParamVarRegion?
 
   // The region should be symbolic, we do not know it's value.
-  const auto *SymReg = dyn_cast_or_null(MemReg);
+  const auto *SymReg = dyn_cast_or_null(Val.getAsRegion());
   if (!SymReg)
 return false;
 
@@ -86,7 +91,7 @@
   const auto *Sm = dyn_cast(SymReg->getSymbol());
   if (!Sm)
 return false;
-  const auto *DeclReg = dyn_cast_or_null(Sm->getRegion());
+  const auto *DeclReg = dyn_cast(Sm->getRegion());
   if (!DeclReg)
 return false;
 
@@ -94,68 +99,58 @@
   // variable named stdin with the proper type.
   if (const auto *D = dyn_cast_or_null(DeclReg->getDecl())) {
 D = D->getCanonicalDecl();
+// FIXME: This should look for an exact match.
 if (D->getName().contains("stdin") && D->isExternC()) {
-  const auto *PtrTy = dyn_cast(D->getType().getTypePtr());
-  if (PtrTy && PtrTy->getPointeeType().getCanonicalType() ==
-   C.getASTContext().getFILEType().getCanonicalType())
-return true;
+  const QualType FILETy = ACtx.getFILEType().getCanonicalType();
+  const QualType Ty = D->getType().getCanonicalType();
+
+  if (Ty->isPointerType())
+return Ty->getPointeeType() == FILETy;
 }
   }
   return false;
 }
 
-/// Given a pointer argument, return the value it points to.
-Optional getPointeeOf(CheckerContext , const Expr *Arg) {
-  ProgramStateRef State = C.getState();
-  SVal AddrVal = C.getSVal(Arg->IgnoreParens());
-  if (AddrVal.isUnknownOrUndef())
-return None;
-
-  Optional AddrLoc = AddrVal.getAs();
-  if (!AddrLoc)
-return None;
-
-  QualType ArgTy = Arg->getType().getCanonicalType();
-  if (!ArgTy->isPointerType())
-return State->getSVal(*AddrLoc);
-
-  QualType ValTy = ArgTy->getPointeeType();
+SVal getPointeeOf(const CheckerContext , Loc LValue) {
+  const QualType ArgTy = LValue.getType(C.getASTContext());
+  if (!ArgTy->isPointerType() || !ArgTy->getPointeeType()->isVoidType())
+return C.getState()->getSVal(LValue);
 
   // Do not dereference void pointers. Treat them as byte pointers instead.
   // FIXME: we might want to consider more than just the first byte.
-  if (ValTy->isVoidType())
-ValTy = C.getASTContext().CharTy;
+  return C.getState()->getSVal(LValue, C.getASTContext().CharTy);
+}
 
-  return State->getSVal(*AddrLoc, ValTy);
+/// Given a pointer/reference argument, return the value it refers to.
+Optional getPointeeOf(const CheckerContext , SVal Arg) {
+  if (auto LValue = Arg.getAs())
+return getPointeeOf(C, *LValue);
+  return None;
 }
 
 /// Given a pointer, return the SVal of its pointee or if it is tainted,
 /// otherwise return the pointer's SVal if tainted.
-Optional getTaintedPointeeOrPointer(CheckerContext , const Expr *Arg) {
-  assert(Arg);
-  // Check for taint.
-  ProgramStateRef State = C.getState();
-  Optional PointedToSVal = getPointeeOf(C, Arg);
+/// Also considers stdin as a taint source.
+Optional getTaintedPointeeOrPointer(const CheckerContext , SVal Arg) {
+  const ProgramStateRef State = C.getState();
 
-  if (PointedToSVal && isTainted(State, *PointedToSVal))
-return 

[PATCH] D115934: [analyzer] Add range constructor to CallDescriptionMap

2021-12-20 Thread Endre Fülöp via Phabricator via cfe-commits
This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rGc6a861e644a9: [analyzer] Add range constructor to 
CallDescriptionMap (authored by gamesh411).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D115934/new/

https://reviews.llvm.org/D115934

Files:
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h


Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h
===
--- clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h
+++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h
@@ -134,6 +134,9 @@
   std::initializer_list> &)
   : LinearMap(List) {}
 
+  template 
+  CallDescriptionMap(InputIt First, InputIt Last) : LinearMap(First, Last) {}
+
   ~CallDescriptionMap() = default;
 
   // These maps are usually stored once per checker, so let's make sure


Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h
===
--- clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h
+++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h
@@ -134,6 +134,9 @@
   std::initializer_list> &)
   : LinearMap(List) {}
 
+  template 
+  CallDescriptionMap(InputIt First, InputIt Last) : LinearMap(First, Last) {}
+
   ~CallDescriptionMap() = default;
 
   // These maps are usually stored once per checker, so let's make sure
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D115931: [analyzer] Enable move semantics for CallDescriptionMap

2021-12-20 Thread Endre Fülöp via Phabricator via cfe-commits
This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rGe0321eb86158: [analyzer] Enable move semantics for 
CallDescriptionMap (authored by gamesh411).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D115931/new/

https://reviews.llvm.org/D115931

Files:
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h


Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h
===
--- clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h
+++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h
@@ -141,6 +141,9 @@
   CallDescriptionMap(const CallDescriptionMap &) = delete;
   CallDescriptionMap =(const CallDescription &) = delete;
 
+  CallDescriptionMap(CallDescriptionMap &&) = default;
+  CallDescriptionMap =(CallDescriptionMap &&) = default;
+
   LLVM_NODISCARD const T *lookup(const CallEvent ) const {
 // Slow path: linear lookup.
 // TODO: Implement some sort of fast path.


Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h
===
--- clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h
+++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h
@@ -141,6 +141,9 @@
   CallDescriptionMap(const CallDescriptionMap &) = delete;
   CallDescriptionMap =(const CallDescription &) = delete;
 
+  CallDescriptionMap(CallDescriptionMap &&) = default;
+  CallDescriptionMap =(CallDescriptionMap &&) = default;
+
   LLVM_NODISCARD const T *lookup(const CallEvent ) const {
 // Slow path: linear lookup.
 // TODO: Implement some sort of fast path.
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D116025: [analyzer][NFC] Refactor GenericTaintChecker to use CallDescriptionMap

2021-12-20 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 created this revision.
gamesh411 added reviewers: steakhal, martong, NoQ.
Herald added subscribers: manas, ASDenysPetrov, dkrupp, donat.nagy, Szelethus, 
mikhail.ramalho, a.sidorin, rnkovacs, szepet, baloghadamsoftware, xazax.hun.
Herald added a reviewer: Szelethus.
gamesh411 requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

GenericTaintChecker now uses CallDescriptionMap to describe the possible
operation in code which trigger the introduction (sources), the removal
(filters), the passing along (propagations) and detection (sinks) of
tainted values.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D116025

Files:
  clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp

Index: clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
@@ -22,15 +22,14 @@
 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
 #include "clang/StaticAnalyzer/Core/Checker.h"
 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
 #include "llvm/Support/YAMLTraits.h"
 
-#include 
 #include 
 #include 
-#include 
 #include 
 
 using namespace clang;
@@ -38,577 +37,685 @@
 using namespace taint;
 
 namespace {
-class GenericTaintChecker : public Checker {
-public:
-  static void *getTag() {
-static int Tag;
-return 
+
+/// Check for CWE-134: Uncontrolled Format String.
+constexpr llvm::StringLiteral MsgUncontrolledFormatString =
+"Untrusted data is used as a format string "
+"(CWE-134: Uncontrolled Format String)";
+
+/// Check for:
+/// CERT/STR02-C. "Sanitize data passed to complex subsystems"
+/// CWE-78, "Failure to Sanitize Data into an OS Command"
+constexpr llvm::StringLiteral MsgSanitizeSystemArgs =
+"Untrusted data is passed to a system call "
+"(CERT/STR02-C. Sanitize data passed to complex subsystems)";
+
+/// Check if tainted data is used as a buffer size ins strn.. functions,
+/// and allocators.
+constexpr llvm::StringLiteral MsgTaintedBufferSize =
+"Untrusted data is used to specify the buffer size "
+"(CERT/STR31-C. Guarantee that storage for strings has sufficient space "
+"for character data and the null terminator)";
+
+/// Check if tainted data is used as a custom sink's parameter.
+constexpr llvm::StringLiteral MsgCustomSink =
+"Untrusted data is passed to a user-defined sink";
+
+using ArgIdxTy = int;
+using ArgVecTy = llvm::SmallVector;
+
+constexpr int InvalidArgIndex{-2};
+/// Denotes the return value.
+constexpr int ReturnValueIndex{-1};
+
+/// Check if the region the expression evaluates to is the standard input,
+/// and thus, is tainted.
+bool isStdin(const Expr *E, CheckerContext ) {
+  ProgramStateRef State = C.getState();
+  SVal Val = C.getSVal(E);
+
+  // stdin is a pointer, so it would be a region.
+  const MemRegion *MemReg = Val.getAsRegion();
+
+  // The region should be symbolic, we do not know it's value.
+  const auto *SymReg = dyn_cast_or_null(MemReg);
+  if (!SymReg)
+return false;
+
+  // Get it's symbol and find the declaration region it's pointing to.
+  const auto *Sm = dyn_cast(SymReg->getSymbol());
+  if (!Sm)
+return false;
+  const auto *DeclReg = dyn_cast_or_null(Sm->getRegion());
+  if (!DeclReg)
+return false;
+
+  // This region corresponds to a declaration, find out if it's a global/extern
+  // variable named stdin with the proper type.
+  if (const auto *D = dyn_cast_or_null(DeclReg->getDecl())) {
+D = D->getCanonicalDecl();
+if (D->getName().contains("stdin") && D->isExternC()) {
+  const auto *PtrTy = dyn_cast(D->getType().getTypePtr());
+  if (PtrTy && PtrTy->getPointeeType().getCanonicalType() ==
+   C.getASTContext().getFILEType().getCanonicalType())
+return true;
+}
   }
+  return false;
+}
 
-  void checkPreCall(const CallEvent , CheckerContext ) const;
-  void checkPostCall(const CallEvent , CheckerContext ) const;
+/// Given a pointer argument, return the value it points to.
+Optional getPointeeOf(CheckerContext , const Expr *Arg) {
+  ProgramStateRef State = C.getState();
+  SVal AddrVal = C.getSVal(Arg->IgnoreParens());
+  if (AddrVal.isUnknownOrUndef())
+return None;
 
-  void printState(raw_ostream , ProgramStateRef State, const char *NL,
-  const char *Sep) const override;
+  Optional AddrLoc = AddrVal.getAs();
+  if (!AddrLoc)
+return None;
 
-  using ArgVector = SmallVector;
-  using SignedArgVector = SmallVector;
+  QualType ArgTy = Arg->getType().getCanonicalType();
+  if 

[PATCH] D115931: [analyzer] Enable move semantics for CallDescriptionMap

2021-12-20 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 updated this revision to Diff 395395.
gamesh411 added a comment.

Remove static asserts as it adds little to no value in this case


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D115931/new/

https://reviews.llvm.org/D115931

Files:
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h


Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h
===
--- clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h
+++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h
@@ -141,6 +141,9 @@
   CallDescriptionMap(const CallDescriptionMap &) = delete;
   CallDescriptionMap =(const CallDescription &) = delete;
 
+  CallDescriptionMap(CallDescriptionMap &&) = default;
+  CallDescriptionMap =(CallDescriptionMap &&) = default;
+
   LLVM_NODISCARD const T *lookup(const CallEvent ) const {
 // Slow path: linear lookup.
 // TODO: Implement some sort of fast path.


Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h
===
--- clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h
+++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h
@@ -141,6 +141,9 @@
   CallDescriptionMap(const CallDescriptionMap &) = delete;
   CallDescriptionMap =(const CallDescription &) = delete;
 
+  CallDescriptionMap(CallDescriptionMap &&) = default;
+  CallDescriptionMap =(CallDescriptionMap &&) = default;
+
   LLVM_NODISCARD const T *lookup(const CallEvent ) const {
 // Slow path: linear lookup.
 // TODO: Implement some sort of fast path.
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D115934: [analyzer] Add range constructor to CallDescriptionMap

2021-12-20 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 updated this revision to Diff 395394.
gamesh411 added a comment.

Remove static asserts as it only makes the tests more brittle


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D115934/new/

https://reviews.llvm.org/D115934

Files:
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h


Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h
===
--- clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h
+++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h
@@ -134,6 +134,9 @@
   std::initializer_list> &)
   : LinearMap(List) {}
 
+  template 
+  CallDescriptionMap(InputIt First, InputIt Last) : LinearMap(First, Last) {}
+
   ~CallDescriptionMap() = default;
 
   // These maps are usually stored once per checker, so let's make sure


Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h
===
--- clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h
+++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h
@@ -134,6 +134,9 @@
   std::initializer_list> &)
   : LinearMap(List) {}
 
+  template 
+  CallDescriptionMap(InputIt First, InputIt Last) : LinearMap(First, Last) {}
+
   ~CallDescriptionMap() = default;
 
   // These maps are usually stored once per checker, so let's make sure
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D115934: [analyzer] Add range constructor to CallDescriptionMap

2021-12-17 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 created this revision.
gamesh411 added reviewers: steakhal, martong.
Herald added subscribers: manas, ASDenysPetrov, dkrupp, donat.nagy, Szelethus, 
mikhail.ramalho, a.sidorin, rnkovacs, szepet, baloghadamsoftware, xazax.hun.
Herald added a reviewer: Szelethus.
gamesh411 requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

CallDescriptionMap benefits from a range constructor when the
CallDescription and mapped type pairs cannot be constructed at once, but
are built incrementally.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D115934

Files:
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h
  clang/unittests/StaticAnalyzer/CallDescriptionTest.cpp


Index: clang/unittests/StaticAnalyzer/CallDescriptionTest.cpp
===
--- clang/unittests/StaticAnalyzer/CallDescriptionTest.cpp
+++ clang/unittests/StaticAnalyzer/CallDescriptionTest.cpp
@@ -19,6 +19,14 @@
 namespace ento {
 namespace {
 
+using ArgsContainer = std::vector>;
+
+static_assert(
+std::is_constructible,
+  decltype(std::declval().begin()),
+  decltype(std::declval().end())>(),
+"should be range constructible");
+
 // A wrapper around CallDescriptionMap that allows verifying that
 // all functions have been found. This is needed because CallDescriptionMap
 // isn't supposed to support iteration.
Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h
===
--- clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h
+++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h
@@ -134,6 +134,9 @@
   std::initializer_list> &)
   : LinearMap(List) {}
 
+  template 
+  CallDescriptionMap(InputIt First, InputIt Last) : LinearMap(First, Last) {}
+
   ~CallDescriptionMap() = default;
 
   // These maps are usually stored once per checker, so let's make sure


Index: clang/unittests/StaticAnalyzer/CallDescriptionTest.cpp
===
--- clang/unittests/StaticAnalyzer/CallDescriptionTest.cpp
+++ clang/unittests/StaticAnalyzer/CallDescriptionTest.cpp
@@ -19,6 +19,14 @@
 namespace ento {
 namespace {
 
+using ArgsContainer = std::vector>;
+
+static_assert(
+std::is_constructible,
+  decltype(std::declval().begin()),
+  decltype(std::declval().end())>(),
+"should be range constructible");
+
 // A wrapper around CallDescriptionMap that allows verifying that
 // all functions have been found. This is needed because CallDescriptionMap
 // isn't supposed to support iteration.
Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h
===
--- clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h
+++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h
@@ -134,6 +134,9 @@
   std::initializer_list> &)
   : LinearMap(List) {}
 
+  template 
+  CallDescriptionMap(InputIt First, InputIt Last) : LinearMap(First, Last) {}
+
   ~CallDescriptionMap() = default;
 
   // These maps are usually stored once per checker, so let's make sure
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D115931: [analyzer] Enable move semantics for CallDescriptionMap

2021-12-17 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 created this revision.
gamesh411 added reviewers: steakhal, martong.
Herald added subscribers: manas, ASDenysPetrov, dkrupp, donat.nagy, Szelethus, 
mikhail.ramalho, a.sidorin, rnkovacs, szepet, baloghadamsoftware, xazax.hun.
Herald added a reviewer: Szelethus.
gamesh411 requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

CallDescriptionMap is supposed to be immutable and opaque about the
stored CallDescriptions, but moving a CallDescriptionMap does not
violate these principles.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D115931

Files:
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h
  clang/unittests/StaticAnalyzer/CallDescriptionTest.cpp


Index: clang/unittests/StaticAnalyzer/CallDescriptionTest.cpp
===
--- clang/unittests/StaticAnalyzer/CallDescriptionTest.cpp
+++ clang/unittests/StaticAnalyzer/CallDescriptionTest.cpp
@@ -19,6 +19,10 @@
 namespace ento {
 namespace {
 
+static_assert(std::is_move_constructible>() &&
+  std::is_move_assignable>(),
+  "CallDescriptionMap should support move semantics");
+
 // A wrapper around CallDescriptionMap that allows verifying that
 // all functions have been found. This is needed because CallDescriptionMap
 // isn't supposed to support iteration.
Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h
===
--- clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h
+++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h
@@ -141,6 +141,9 @@
   CallDescriptionMap(const CallDescriptionMap &) = delete;
   CallDescriptionMap =(const CallDescription &) = delete;
 
+  CallDescriptionMap(CallDescriptionMap &&) = default;
+  CallDescriptionMap =(CallDescriptionMap &&) = default;
+
   LLVM_NODISCARD const T *lookup(const CallEvent ) const {
 // Slow path: linear lookup.
 // TODO: Implement some sort of fast path.


Index: clang/unittests/StaticAnalyzer/CallDescriptionTest.cpp
===
--- clang/unittests/StaticAnalyzer/CallDescriptionTest.cpp
+++ clang/unittests/StaticAnalyzer/CallDescriptionTest.cpp
@@ -19,6 +19,10 @@
 namespace ento {
 namespace {
 
+static_assert(std::is_move_constructible>() &&
+  std::is_move_assignable>(),
+  "CallDescriptionMap should support move semantics");
+
 // A wrapper around CallDescriptionMap that allows verifying that
 // all functions have been found. This is needed because CallDescriptionMap
 // isn't supposed to support iteration.
Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h
===
--- clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h
+++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h
@@ -141,6 +141,9 @@
   CallDescriptionMap(const CallDescriptionMap &) = delete;
   CallDescriptionMap =(const CallDescription &) = delete;
 
+  CallDescriptionMap(CallDescriptionMap &&) = default;
+  CallDescriptionMap =(CallDescriptionMap &&) = default;
+
   LLVM_NODISCARD const T *lookup(const CallEvent ) const {
 // Slow path: linear lookup.
 // TODO: Implement some sort of fast path.
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D114706: [analyzer] Fix sensitive argument logic in GenericTaintChecker

2021-11-29 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 created this revision.
gamesh411 added reviewers: steakhal, Szelethus, NoQ.
Herald added subscribers: manas, ASDenysPetrov, martong, dkrupp, donat.nagy, 
mikhail.ramalho, a.sidorin, szepet, baloghadamsoftware, xazax.hun.
gamesh411 requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

The semantics of taint sinks is that if ANY of the arguments is tainted, a
warning should be emmitted. Before this change, if there were multiple
arguments that are sensitive, and if the first arg is not tainted, but any of
the noninitial are tainted, a warning is not emitted. After this change the
correct semantics is reflected in code.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D114706

Files:
  clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
  clang/test/Analysis/taint-generic.c

Index: clang/test/Analysis/taint-generic.c
===
--- clang/test/Analysis/taint-generic.c
+++ clang/test/Analysis/taint-generic.c
@@ -209,6 +209,15 @@
   strncat(dst2, dst, ts); // no-warning
 }
 
+void testTaintedBufferSizeNoninitialTaintedArg() {
+  size_t ts;
+  scanf("%zd", );
+
+  const int nontainted_num = 1;
+
+  (void)calloc(nontainted_num, ts); //expected-warning {{Untrusted data is used to specify the buffer size}}
+}
+
 #define AF_UNIX   1   /* local to host (pipes) */
 #define AF_INET   2   /* internetwork: UDP, TCP, etc. */
 #define AF_LOCAL  AF_UNIX   /* backward compatibility */
Index: clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
@@ -869,24 +869,26 @@
   // TODO: It might make sense to run this check on demand. In some cases,
   // we should check if the environment has been cleansed here. We also might
   // need to know if the user was reset before these calls(seteuid).
-  unsigned ArgNum = llvm::StringSwitch(Name)
-.Case("system", 0)
-.Case("popen", 0)
-.Case("execl", 0)
-.Case("execle", 0)
-.Case("execlp", 0)
-.Case("execv", 0)
-.Case("execvp", 0)
-.Case("execvP", 0)
-.Case("execve", 0)
-.Case("dlopen", 0)
-.Default(InvalidArgIndex);
-
-  if (ArgNum == InvalidArgIndex || Call.getNumArgs() < (ArgNum + 1))
-return false;
-
-  return generateReportIfTainted(Call.getArgExpr(ArgNum), MsgSanitizeSystemArgs,
- C);
+  const ArgVector SensitiveArgs = llvm::StringSwitch(Name)
+  .Case("system", {0})
+  .Case("popen", {0})
+  .Case("execl", {0, 1})
+  .Case("execle", {0, 1})
+  .Case("execlp", {0, 1})
+  .Case("execv", {0, 1})
+  .Case("execvp", {0, 1})
+  .Case("execvP", {0})
+  .Case("execve", {0, 1, 2})
+  .Case("dlopen", {0})
+  .Default({});
+
+  // Find the first argument that receives a tainted value.
+  // The report is emitted as a side-effect.
+  return llvm::find_if(SensitiveArgs, [this, , ](unsigned Idx) {
+   return Idx < Call.getNumArgs() &&
+  generateReportIfTainted(Call.getArgExpr(Idx),
+  MsgSanitizeSystemArgs, C);
+ }) != SensitiveArgs.end();
 }
 
 // TODO: Should this check be a part of the CString checker?
@@ -895,40 +897,45 @@
  CheckerContext ) const {
   const auto *FDecl = Call.getDecl()->getAsFunction();
   // If the function has a buffer size argument, set ArgNum.
-  unsigned ArgNum = InvalidArgIndex;
+  ArgVector SensitiveArgs = {};
   unsigned BId = 0;
   if ((BId = FDecl->getMemoryFunctionKind())) {
 switch (BId) {
 case Builtin::BImemcpy:
 case Builtin::BImemmove:
 case Builtin::BIstrncpy:
-  ArgNum = 2;
+  SensitiveArgs = {2};
   break;
 case Builtin::BIstrndup:
-  ArgNum = 1;
+  SensitiveArgs = {1};
   break;
 default:
   break;
 }
   }
 
-  if (ArgNum == InvalidArgIndex) {
+  if (SensitiveArgs.empty()) {
 using CCtx = CheckerContext;
 if (CCtx::isCLibraryFunction(FDecl, "malloc") ||
-CCtx::isCLibraryFunction(FDecl, "calloc") ||
 CCtx::isCLibraryFunction(FDecl, "alloca"))
-  ArgNum = 0;
+  SensitiveArgs = {0};
+else if (CCtx::isCLibraryFunction(FDecl, "calloc"))

[PATCH] D113251: [analyzer][doc] Add user documenation for taint analysis

2021-11-28 Thread Endre Fülöp via Phabricator via cfe-commits
This revision was not accepted when it landed; it landed in state "Needs 
Review".
This revision was automatically updated to reflect the committed changes.
Closed by commit rG4aac00a71db3: [analyzer][doc] Add user documenation for 
taint analysis (authored by gamesh411).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D113251/new/

https://reviews.llvm.org/D113251

Files:
  clang/docs/analyzer/checkers.rst
  clang/docs/analyzer/user-docs.rst
  clang/docs/analyzer/user-docs/TaintAnalysisConfiguration.rst

Index: clang/docs/analyzer/user-docs/TaintAnalysisConfiguration.rst
===
--- /dev/null
+++ clang/docs/analyzer/user-docs/TaintAnalysisConfiguration.rst
@@ -0,0 +1,170 @@
+
+Taint Analysis Configuration
+
+
+The Clang Static Analyzer uses taint analysis to detect security-related issues in code.
+The backbone of taint analysis in the Clang SA is the `GenericTaintChecker`, which the user can access via the :ref:`alpha-security-taint-TaintPropagation` checker alias and this checker has a default taint-related configuration.
+The built-in default settings are defined in code, and they are always in effect once the checker is enabled, either directly or via the alias.
+The checker also provides a configuration interface for extending the default settings by providing a configuration file in `YAML `_ format.
+This documentation describes the syntax of the configuration file and gives the informal semantics of the configuration options.
+
+.. contents::
+   :local:
+
+.. _clangsa-taint-configuration-overview:
+
+Overview
+
+
+Taint analysis works by checking for the occurrence of special operations during the symbolic execution of the program.
+Taint analysis defines sources, sinks, and propagation rules. It identifies errors by detecting a flow of information that originates from a taint source, reaches a taint sink, and propagates through the program paths via propagation rules.
+A source, sink, or an operation that propagates taint is mainly domain-specific knowledge, but there are some built-in defaults provided by :ref:`alpha-security-taint-TaintPropagation`.
+It is possible to express that a statement sanitizes tainted values by providing a ``Filters`` section in the external configuration (see :ref:`clangsa-taint-configuration-example` and :ref:`clangsa-taint-filter-details`).
+There are no default filters defined in the built-in settings.
+The checker's documentation also specifies how to provide a custom taint configuration with command-line options.
+
+.. _clangsa-taint-configuration-example:
+
+Example configuration file
+__
+
+.. code-block:: yaml
+
+  # The entries that specify arguments use 0-based indexing when specifying
+  # input arguments, and -1 is used to denote the return value.
+
+  Filters:
+# Filter functions
+# Taint is sanitized when tainted variables are pass arguments to filters.
+
+# Filter function
+#   void cleanse_first_arg(int* arg)
+#
+# Result example:
+#   int x; // x is tainted
+#   cleanse_first_arg(); // x is not tainted after the call
+- Name: cleanse_first_arg
+  Args: [0]
+
+  Propagations:
+# Source functions
+# The omission of SrcArgs key indicates unconditional taint propagation,
+# which is conceptually what a source does.
+
+# Source function
+#   size_t fread(void *ptr, size_t size, size_t nmemb, FILE * stream)
+#
+# Result example:
+#   FILE* f = fopen("file.txt");
+#   char buf[1024];
+#   size_t read = fread(buf, sizeof(buf[0]), sizeof(buf)/sizeof(buf[0]), f);
+#   // both read and buf are tainted
+- Name: fread
+  DstArgs: [0, -1]
+
+# Propagation functions
+# The presence of SrcArgs key indicates conditional taint propagation,
+# which is conceptually what a propagator does.
+
+# Propagation function
+#   char *dirname(char *path)
+#
+# Result example:
+#   char* path = read_path();
+#   char* dir = dirname(path);
+#   // dir is tainted if path was tainted
+- Name: dirname
+  SrcArgs: [0]
+  DstArgs: [-1]
+
+  Sinks:
+# Sink functions
+# If taint reaches any of the arguments specified, a warning is emitted.
+
+# Sink function
+#   int system(const char* command)
+#
+# Result example:
+#   const char* command = read_command();
+#   system(command); // emit diagnostic if command is tainted
+- Name: system
+  Args: [0]
+
+In the example file above, the entries under the `Propagation` key implement the conceptual sources and propagations, and sinks have their dedicated `Sinks` key.
+The user can define operations (function calls) where the tainted values should be cleansed by listing entries under the `Filters` key.
+Filters model the 

[PATCH] D113251: [analyzer][doc] Add user documenation for taint analysis

2021-11-25 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 updated this revision to Diff 389684.
gamesh411 added a comment.

update with `arc diff $(git merge-base HEAD upstream) --update D113251`
in order to satisfy workflow `pre-merge checks`


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D113251/new/

https://reviews.llvm.org/D113251

Files:
  clang/docs/analyzer/checkers.rst
  clang/docs/analyzer/user-docs.rst
  clang/docs/analyzer/user-docs/TaintAnalysisConfiguration.rst

Index: clang/docs/analyzer/user-docs/TaintAnalysisConfiguration.rst
===
--- /dev/null
+++ clang/docs/analyzer/user-docs/TaintAnalysisConfiguration.rst
@@ -0,0 +1,170 @@
+
+Taint Analysis Configuration
+
+
+The Clang Static Analyzer uses taint analysis to detect security-related issues in code.
+The backbone of taint analysis in the Clang SA is the `GenericTaintChecker`, which the user can access via the :ref:`alpha-security-taint-TaintPropagation` checker alias and this checker has a default taint-related configuration.
+The built-in default settings are defined in code, and they are always in effect once the checker is enabled, either directly or via the alias.
+The checker also provides a configuration interface for extending the default settings by providing a configuration file in `YAML `_ format.
+This documentation describes the syntax of the configuration file and gives the informal semantics of the configuration options.
+
+.. contents::
+   :local:
+
+.. _clangsa-taint-configuration-overview:
+
+Overview
+
+
+Taint analysis works by checking for the occurrence of special operations during the symbolic execution of the program.
+Taint analysis defines sources, sinks, and propagation rules. It identifies errors by detecting a flow of information that originates from a taint source, reaches a taint sink, and propagates through the program paths via propagation rules.
+A source, sink, or an operation that propagates taint is mainly domain-specific knowledge, but there are some built-in defaults provided by :ref:`alpha-security-taint-TaintPropagation`.
+It is possible to express that a statement sanitizes tainted values by providing a ``Filters`` section in the external configuration (see :ref:`clangsa-taint-configuration-example` and :ref:`clangsa-taint-filter-details`).
+There are no default filters defined in the built-in settings.
+The checker's documentation also specifies how to provide a custom taint configuration with command-line options.
+
+.. _clangsa-taint-configuration-example:
+
+Example configuration file
+__
+
+.. code-block:: yaml
+
+  # The entries that specify arguments use 0-based indexing when specifying
+  # input arguments, and -1 is used to denote the return value.
+
+  Filters:
+# Filter functions
+# Taint is sanitized when tainted variables are pass arguments to filters.
+
+# Filter function
+#   void cleanse_first_arg(int* arg)
+#
+# Result example:
+#   int x; // x is tainted
+#   cleanse_first_arg(); // x is not tainted after the call
+- Name: cleanse_first_arg
+  Args: [0]
+
+  Propagations:
+# Source functions
+# The omission of SrcArgs key indicates unconditional taint propagation,
+# which is conceptually what a source does.
+
+# Source function
+#   size_t fread(void *ptr, size_t size, size_t nmemb, FILE * stream)
+#
+# Result example:
+#   FILE* f = fopen("file.txt");
+#   char buf[1024];
+#   size_t read = fread(buf, sizeof(buf[0]), sizeof(buf)/sizeof(buf[0]), f);
+#   // both read and buf are tainted
+- Name: fread
+  DstArgs: [0, -1]
+
+# Propagation functions
+# The presence of SrcArgs key indicates conditional taint propagation,
+# which is conceptually what a propagator does.
+
+# Propagation function
+#   char *dirname(char *path)
+#
+# Result example:
+#   char* path = read_path();
+#   char* dir = dirname(path);
+#   // dir is tainted if path was tainted
+- Name: dirname
+  SrcArgs: [0]
+  DstArgs: [-1]
+
+  Sinks:
+# Sink functions
+# If taint reaches any of the arguments specified, a warning is emitted.
+
+# Sink function
+#   int system(const char* command)
+#
+# Result example:
+#   const char* command = read_command();
+#   system(command); // emit diagnostic if command is tainted
+- Name: system
+  Args: [0]
+
+In the example file above, the entries under the `Propagation` key implement the conceptual sources and propagations, and sinks have their dedicated `Sinks` key.
+The user can define operations (function calls) where the tainted values should be cleansed by listing entries under the `Filters` key.
+Filters model the sanitization of values done by the programmer, and providing these is key to 

[PATCH] D113251: [analyzer][doc] Add user documenation for taint analysis

2021-11-23 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 updated this revision to Diff 389134.
gamesh411 added a comment.

fix indentation warning
make inline code formatting look better


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D113251/new/

https://reviews.llvm.org/D113251

Files:
  clang/docs/analyzer/checkers.rst
  clang/docs/analyzer/user-docs/TaintAnalysisConfiguration.rst

Index: clang/docs/analyzer/user-docs/TaintAnalysisConfiguration.rst
===
--- clang/docs/analyzer/user-docs/TaintAnalysisConfiguration.rst
+++ clang/docs/analyzer/user-docs/TaintAnalysisConfiguration.rst
@@ -2,15 +2,16 @@
 Taint Analysis Configuration
 
 
-Clang Static Analyzer uses taint analysis to detect security-related issues in code.
-The backbone of taint analysis in Clang is the `GenericTaintChecker`, which the user can access via the :ref:`alpha-security-taint-TaintPropagation` checker alias and this checker has a default taint-related configuration.
-The checker also provides a configuration interface for extending the default settings by providing a configuration file in `YAML `_ format.
+The Clang Static Analyzer uses taint analysis to detect security-related issues in code.
+The backbone of taint analysis in the Clang SA is the `GenericTaintChecker`, which the user can access via the :ref:`alpha-security-taint-TaintPropagation` checker alias and this checker has a default taint-related configuration.
+The built-in default settings are defined in code, and they are always in effect once the checker is enabled, either directly or via the alias.
+The checker also provides a configuration interface for extending the default settings by providing a configuration file in `YAML `_ format.
 This documentation describes the syntax of the configuration file and gives the informal semantics of the configuration options.
 
 .. contents::
:local:
 
-.. _taint-configuration-overview
+.. _clangsa-taint-configuration-overview:
 
 Overview
 
@@ -18,61 +19,74 @@
 Taint analysis works by checking for the occurrence of special operations during the symbolic execution of the program.
 Taint analysis defines sources, sinks, and propagation rules. It identifies errors by detecting a flow of information that originates from a taint source, reaches a taint sink, and propagates through the program paths via propagation rules.
 A source, sink, or an operation that propagates taint is mainly domain-specific knowledge, but there are some built-in defaults provided by :ref:`alpha-security-taint-TaintPropagation`.
+It is possible to express that a statement sanitizes tainted values by providing a ``Filters`` section in the external configuration (see :ref:`clangsa-taint-configuration-example` and :ref:`clangsa-taint-filter-details`).
+There are no default filters defined in the built-in settings.
 The checker's documentation also specifies how to provide a custom taint configuration with command-line options.
 
-.. _taint-configuration-example:
+.. _clangsa-taint-configuration-example:
 
 Example configuration file
 __
 
 .. code-block:: yaml
 
+  # The entries that specify arguments use 0-based indexing when specifying
+  # input arguments, and -1 is used to denote the return value.
+
   Filters:
-# signature:
-# void cleanse_first_arg(int* arg)
+# Filter functions
+# Taint is sanitized when tainted variables are pass arguments to filters.
+
+# Filter function
+#   void cleanse_first_arg(int* arg)
 #
-# example:
-# int x; // x is tainted
-# cleanse_first_arg(); // x is not tainted anymore
+# Result example:
+#   int x; // x is tainted
+#   cleanse_first_arg(); // x is not tainted after the call
 - Name: cleanse_first_arg
   Args: [0]
 
   Propagations:
-  # sources:
-  # The omission of SrcArgs key indicates unconditional taint propagation,
-  # which is conceptually what a source does.
-# signature:
-# size_t fread(void *ptr, size_t size, size_t nmemb, FILE * stream)
+# Source functions
+# The omission of SrcArgs key indicates unconditional taint propagation,
+# which is conceptually what a source does.
+
+# Source function
+#   size_t fread(void *ptr, size_t size, size_t nmemb, FILE * stream)
 #
-# example:
-# FILE* f = fopen("file.txt");
-# char buf[1024];
-# size_t read = fread(buf, sizeof(buf[0]), sizeof(buf)/sizeof(buf[0]), f);
-# // both read and buf are tainted
+# Result example:
+#   FILE* f = fopen("file.txt");
+#   char buf[1024];
+#   size_t read = fread(buf, sizeof(buf[0]), sizeof(buf)/sizeof(buf[0]), f);
+#   // both read and buf are tainted
 - Name: fread
   DstArgs: [0, -1]
 
-  # propagations:
-  # The presence of SrcArgs key indicates conditional taint propagation,
-  # which is 

[PATCH] D113251: [analyzer][doc] Add user documenation for taint analysis

2021-11-23 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 added inline comments.



Comment at: clang/docs/analyzer/checkers.rst:2341-2342
+
+Default propagations defined by `GenericTaintChecker`:
+``atoi``, ``atol``, ``atoll``, ``fgetc``, ``fgetln``, ``fgets``, ``fscanf``, 
``sscanf``, ``getc``, ``getc_unlocked``, ``getdelim``, ``getline``, ``getw``, 
``pread``, ``read``, ``strchr``, ``strrchr``, ``tolower``, ``toupper``
+

whisperity wrote:
> What does it mean that these are "default propagations"? That taint passes 
> through calls to them trivially?
Added just 2 sentences about what default means.
Please see them a bit further up in the new version of the patch. 



Comment at: clang/docs/analyzer/checkers.rst:2345
+Default sinks defined in `GenericTaintChecker`:
+``printf``, ``setproctitle``, ``system``, ``popen``, ``execl``, ``execle``, 
``execlp``, ``execv``, ``execvp``, ``execvP``, ``execve``, ``dlopen``, 
``memcpy``, ``memmove``, ``strncpy``, ``strndup``, ``malloc``, ``calloc``, 
``alloca``, ``memccpy``, ``realloc``, ``bcopy``
+

whisperity wrote:
> `execvp` and `execvP`? What is the capital `P` for? I can't find this 
> overload in the POSIX docs.
I have found a refence to this function inside `TargetLibraryInfoTest.cpp`.
```
 926   │   case LibFunc_execv:
 927   │   case LibFunc_execvp:
 928   │ return (NumParams == 2 && FTy.getParamType(0)->isPointerTy() &&
 929   │ FTy.getParamType(1)->isPointerTy() &&
 930   │ FTy.getReturnType()->isIntegerTy(32));
 931   │   case LibFunc_execvP:
 932   │   case LibFunc_execvpe:
 933   │   case LibFunc_execve:
 934   │ return (NumParams == 3 && FTy.getParamType(0)->isPointerTy() &&
 935   │ FTy.getParamType(1)->isPointerTy() &&
 936   │ FTy.getParamType(2)->isPointerTy() &&
 937   │ FTy.getReturnType()->isIntegerTy(32));
```
It seems like an OSX-specific spelling and seems like it has the semantics of 
`execve`.
During the implementation of this patch, I just collected the references to 
functions inside  `GenericTaintChecker.cpp`.



Comment at: clang/docs/analyzer/user-docs/TaintAnalysisConfiguration.rst:5
+
+Clang Static Analyzer uses taint analysis to detect security-related issues in 
code.
+The backbone of taint analysis in Clang is the `GenericTaintChecker`, which 
the user can access via the :ref:`alpha-security-taint-TaintPropagation` 
checker alias and this checker has a default taint-related configuration.

whisperity wrote:
> whisperity wrote:
> > //The// Clang Static [...]?
> uses, or can use?
For brevity and clarity, I will leave it at `uses`, it is just a generic 
statement about the availability of taint analysis as a method, and I think it 
would not improve the understanding to change it to `can use`. IMHO it is 
implicit, and `can use` would make people wonder as to what does Clang need to 
use it etc.



Comment at: clang/docs/analyzer/user-docs/TaintAnalysisConfiguration.rst:6
+Clang Static Analyzer uses taint analysis to detect security-related issues in 
code.
+The backbone of taint analysis in Clang is the `GenericTaintChecker`, which 
the user can access via the :ref:`alpha-security-taint-TaintPropagation` 
checker alias and this checker has a default taint-related configuration.
+The checker also provides a configuration interface for extending the default 
settings by providing a configuration file in `YAML `_ 
format.

whisperity wrote:
> whisperity wrote:
> > Clang -> Clang SA / CSA?
> So the checker has the defaults all the time, or only by enabling the alias 
> can I get the defaults?
Good point, added a line to clarify this.



Comment at: clang/docs/analyzer/user-docs/TaintAnalysisConfiguration.rst:23
+
+.. _taint-configuration-example:
+

whisperity wrote:
> AFAIK, RST anchors are global identifiers for the project, so maybe we should 
> take care in adding "clang-sa" or some other sort of namespaceing...
> 
> (Although this might depend on how exactly the docs are built!)
added `clangsa-` prefix



Comment at: clang/docs/analyzer/user-docs/TaintAnalysisConfiguration.rst:30
+
+  Filters:
+# signature:

whisperity wrote:
> //Filters// are not mentioned earlier.
Added a mention with references in the Overview section.



Comment at: clang/docs/analyzer/user-docs/TaintAnalysisConfiguration.rst:31-36
+# signature:
+# void cleanse_first_arg(int* arg)
+#
+# example:
+# int x; // x is tainted
+# cleanse_first_arg(); // x is not tainted anymore

whisperity wrote:
> If none of the comments themselves are just commented out ("optional") keys 
> in the YAML, it would be better readable with a bit of formatting.
Reformatted the examples section according to your suggestions.



Comment at: 

[PATCH] D113251: [analyzer][doc] Add user documenation for taint analysis

2021-11-23 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 updated this revision to Diff 389117.
gamesh411 marked 15 inline comments as done.
gamesh411 added a comment.

tidy up based on comments from whispy


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D113251/new/

https://reviews.llvm.org/D113251

Files:
  clang/docs/analyzer/checkers.rst
  clang/docs/analyzer/user-docs/TaintAnalysisConfiguration.rst

Index: clang/docs/analyzer/user-docs/TaintAnalysisConfiguration.rst
===
--- clang/docs/analyzer/user-docs/TaintAnalysisConfiguration.rst
+++ clang/docs/analyzer/user-docs/TaintAnalysisConfiguration.rst
@@ -2,15 +2,16 @@
 Taint Analysis Configuration
 
 
-Clang Static Analyzer uses taint analysis to detect security-related issues in code.
-The backbone of taint analysis in Clang is the `GenericTaintChecker`, which the user can access via the :ref:`alpha-security-taint-TaintPropagation` checker alias and this checker has a default taint-related configuration.
-The checker also provides a configuration interface for extending the default settings by providing a configuration file in `YAML `_ format.
+The Clang Static Analyzer uses taint analysis to detect security-related issues in code.
+The backbone of taint analysis in the Clang SA is the `GenericTaintChecker`, which the user can access via the :ref:`alpha-security-taint-TaintPropagation` checker alias and this checker has a default taint-related configuration.
+The built-in default settings are defined in code, and they are always in effect once the checker is enabled, either directly or via the alias.
+The checker also provides a configuration interface for extending the default settings by providing a configuration file in `YAML `_ format.
 This documentation describes the syntax of the configuration file and gives the informal semantics of the configuration options.
 
 .. contents::
:local:
 
-.. _taint-configuration-overview
+.. _clangsa-taint-configuration-overview:
 
 Overview
 
@@ -18,61 +19,74 @@
 Taint analysis works by checking for the occurrence of special operations during the symbolic execution of the program.
 Taint analysis defines sources, sinks, and propagation rules. It identifies errors by detecting a flow of information that originates from a taint source, reaches a taint sink, and propagates through the program paths via propagation rules.
 A source, sink, or an operation that propagates taint is mainly domain-specific knowledge, but there are some built-in defaults provided by :ref:`alpha-security-taint-TaintPropagation`.
+It is possible to express that a statement sanitizes tainted values by providing a ``Filters`` section in the external configuration (see :ref:`clangsa-taint-configuration-example` and :ref:`clangsa-taint-filter-details`).
+There are no default filters defined in the built-in settings.
 The checker's documentation also specifies how to provide a custom taint configuration with command-line options.
 
-.. _taint-configuration-example:
+.. _clangsa-taint-configuration-example:
 
 Example configuration file
 __
 
 .. code-block:: yaml
 
+  # The entries that specify arguments use 0 based indexing when specifying
+  # input arguments, and -1 is used to denote the return value.
+
   Filters:
-# signature:
-# void cleanse_first_arg(int* arg)
+# Filter functions
+# Taint is sanitized when tainted variables are pass arguments to filters.
+
+# Filter function
+#   void cleanse_first_arg(int* arg)
 #
-# example:
-# int x; // x is tainted
-# cleanse_first_arg(); // x is not tainted anymore
+# Result example:
+#   int x; // x is tainted
+#   cleanse_first_arg(); // x is not tainted after the call
 - Name: cleanse_first_arg
   Args: [0]
 
   Propagations:
-  # sources:
-  # The omission of SrcArgs key indicates unconditional taint propagation,
-  # which is conceptually what a source does.
-# signature:
-# size_t fread(void *ptr, size_t size, size_t nmemb, FILE * stream)
+# Source functions
+# The omission of SrcArgs key indicates unconditional taint propagation,
+# which is conceptually what a source does.
+
+# Source function
+#   size_t fread(void *ptr, size_t size, size_t nmemb, FILE * stream)
 #
-# example:
-# FILE* f = fopen("file.txt");
-# char buf[1024];
-# size_t read = fread(buf, sizeof(buf[0]), sizeof(buf)/sizeof(buf[0]), f);
-# // both read and buf are tainted
+# Result example:
+#   FILE* f = fopen("file.txt");
+#   char buf[1024];
+#   size_t read = fread(buf, sizeof(buf[0]), sizeof(buf)/sizeof(buf[0]), f);
+#   // both read and buf are tainted
 - Name: fread
   DstArgs: [0, -1]
 
-  # propagations:
-  # The presence of SrcArgs key indicates conditional taint propagation,
-  # 

[PATCH] D113251: [analyzer][doc] Add user documenation for taint analysis

2021-11-18 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 updated this revision to Diff 388132.
gamesh411 added a comment.

Fix the review comments of @steakhal


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D113251/new/

https://reviews.llvm.org/D113251

Files:
  clang/docs/analyzer/checkers.rst
  clang/docs/analyzer/user-docs/TaintAnalysisConfiguration.rst

Index: clang/docs/analyzer/user-docs/TaintAnalysisConfiguration.rst
===
--- clang/docs/analyzer/user-docs/TaintAnalysisConfiguration.rst
+++ clang/docs/analyzer/user-docs/TaintAnalysisConfiguration.rst
@@ -15,9 +15,9 @@
 Overview
 
 
-Taint analysis works by checking for the occurrence of special events during the symbolic execution of the program.
-Taint analysis defines sources, sinks, and propagation rules. It identifies errors by detecting a flow of information that originates in a taint source, touches a taint sink, and propagates through the program paths via propagation rules.
-A source, sink, or an event that propagates taint is mainly domain-specific knowledge, but there are some built-in defaults provided by :ref:`alpha-security-taint-TaintPropagation`.
+Taint analysis works by checking for the occurrence of special operations during the symbolic execution of the program.
+Taint analysis defines sources, sinks, and propagation rules. It identifies errors by detecting a flow of information that originates from a taint source, reaches a taint sink, and propagates through the program paths via propagation rules.
+A source, sink, or an operation that propagates taint is mainly domain-specific knowledge, but there are some built-in defaults provided by :ref:`alpha-security-taint-TaintPropagation`.
 The checker's documentation also specifies how to provide a custom taint configuration with command-line options.
 
 .. _taint-configuration-example:
@@ -39,6 +39,8 @@
 
   Propagations:
   # sources:
+  # The omission of SrcArgs key indicates unconditional taint propagation,
+  # which is conceptually what a source does.
 # signature:
 # size_t fread(void *ptr, size_t size, size_t nmemb, FILE * stream)
 #
@@ -46,11 +48,13 @@
 # FILE* f = fopen("file.txt");
 # char buf[1024];
 # size_t read = fread(buf, sizeof(buf[0]), sizeof(buf)/sizeof(buf[0]), f);
-# // read and buf is tainted
+# // both read and buf are tainted
 - Name: fread
   DstArgs: [0, -1]
 
   # propagations:
+  # The presence of SrcArgs key indicates conditional taint propagation,
+  # which is conceptually what a propagator does.
 # signature:
 # char *dirname(char *path)
 #
@@ -73,7 +77,7 @@
   Args: [0]
 
 In the example file above, the entries under the `Propagation` key implement the conceptual sources and propagations, and sinks have their dedicated `Sinks` key.
-The user can define program points where the tainted values should be cleansed by listing entries under the `Filters` key.
+The user can define operations (function calls) where the tainted values should be cleansed by listing entries under the `Filters` key.
 Filters model the sanitization of values done by the programmer, and providing these is key to avoiding false-positive findings.
 
 Configuration file syntax and semantics
@@ -86,50 +90,54 @@
  - Propagations
  - Sinks
 
-Under the `Filters` entry, the user can specify a list of events that remove taint (see :ref:`taint-filter-details` for details).
+Under the `Filters` key, the user can specify a list of operations that remove taint (see :ref:`taint-filter-details` for details).
 
-Under the `Propagations` entry, the user can specify a list of events that generate and propagate taint (see :ref:`taint-propagation-details` for details).
-The user can identify taint sources with a `SrcArgs` key in the `Propagation` entry, while propagations have none.
+Under the `Propagations` key, the user can specify a list of operations that introduce and propagate taint (see :ref:`taint-propagation-details` for details).
+The user can mark taint sources with a `SrcArgs` key in the `Propagation` key, while propagations have none.
+The lack of the `SrcArgs` key means unconditional propagation, which is how sources are modeled.
+The semantics of propagations are such, that if any of the source arguments are tainted (specified by indexes in `SrcArgs`) then all of the destination arguments (specified by indexes in `DstArgs`) also become tainted.
 
-Under the `Sinks` entry, the user can specify a list of events where the checker should emit a bug report if taint reaches there (see :ref:`taint-sink-details` for details).
+Under the `Sinks` key, the user can specify a list of operations where the checker should emit a bug report if tainted data reaches it (see :ref:`taint-sink-details` for details).
 
 .. _taint-filter-details:
 
 Filter syntax and semantics
 ###
+
 An entry under `Filters` is a `YAML `_ object with the 

[PATCH] D113251: [analyzer][doc] Add user documenation for taint analysis

2021-11-18 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 marked 13 inline comments as done.
gamesh411 added inline comments.



Comment at: clang/docs/analyzer/checkers.rst:2351
+
+ clang --analyze ... -Xclang -analyzer-config -Xclang 
alpha.security.taint.TaintPropagation:Config=taint_config.yaml
+

steakhal wrote:
> Per https://reviews.llvm.org/D113004#inline-1078695 we should not advocate 
> users use the `-Xclang` machinery, we should rather refer to it by other 
> tools such as `scan-build`. However, we haven't reached a consensus about 
> this decision yet.
> Consider moving some parts of this doc to the proposed Configuration 
> documentation file - housing the //more// user-facing analyzer options.
Removed the command-line invocation part, and just left a mention to the 
configuration option.



Comment at: clang/docs/analyzer/user-docs/TaintAnalysisConfiguration.rst:133
+   The value of ``None`` will not consider the arguments that are part of a 
variadic argument list (this option is redundant but can be used to temporarily 
switch off handling of a particular variadic argument option without removing 
the entire variadic entry).
+ - `VariadicIndex` is a number in the range of [0..int_max]. It indicates the 
starting index of the variadic argument in the signature of the function.
+

steakhal wrote:
> It's not exactly for this patch, but we should investigate If we could infer 
> this index from the declaration of the function.
Good idea, this seems like the way forward, I agree.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D113251/new/

https://reviews.llvm.org/D113251

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


[PATCH] D113251: [analyzer][doc] Add user documenation for taint analysis

2021-11-05 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 created this revision.
gamesh411 added a reviewer: steakhal.
Herald added subscribers: manas, ASDenysPetrov, martong, dkrupp, donat.nagy, 
Szelethus, mikhail.ramalho, a.sidorin, szepet, baloghadamsoftware, xazax.hun, 
whisperity.
Herald added a reviewer: Szelethus.
gamesh411 requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Checker alpha.security.taint.TaintPropagation now has user documentation for
taint analysis with an example showing external YAML configuration format.
The format of the taint configuration file is now documented under the user
documentation of Clang SA.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D113251

Files:
  clang/docs/analyzer/checkers.rst
  clang/docs/analyzer/user-docs.rst
  clang/docs/analyzer/user-docs/TaintAnalysisConfiguration.rst

Index: clang/docs/analyzer/user-docs/TaintAnalysisConfiguration.rst
===
--- /dev/null
+++ clang/docs/analyzer/user-docs/TaintAnalysisConfiguration.rst
@@ -0,0 +1,148 @@
+
+Taint Analysis Configuration
+
+
+Clang Static Analyzer uses taint analysis to detect security-related issues in code.
+The backbone of taint analysis in Clang is the `GenericTaintChecker`, which the user can access via the :ref:`alpha-security-taint-TaintPropagation` checker alias and this checker has a default taint-related configuration.
+The checker also provides a configuration interface for extending the default settings by providing a configuration file in `YAML `_ format.
+This documentation describes the syntax of the configuration file and gives the informal semantics of the configuration options.
+
+.. contents::
+   :local:
+
+.. _taint-configuration-overview
+
+Overview
+
+
+Taint analysis works by checking for the occurrence of special events during the symbolic execution of the program.
+Taint analysis defines sources, sinks, and propagation rules. It identifies errors by detecting a flow of information that originates in a taint source, touches a taint sink, and propagates through the program paths via propagation rules.
+A source, sink, or an event that propagates taint is mainly domain-specific knowledge, but there are some built-in defaults provided by :ref:`alpha-security-taint-TaintPropagation`.
+The checker's documentation also specifies how to provide a custom taint configuration with command-line options.
+
+.. _taint-configuration-example:
+
+Example configuration file
+__
+
+.. code-block:: yaml
+
+  Filters:
+# signature:
+# void cleanse_first_arg(int* arg)
+#
+# example:
+# int x; // x is tainted
+# cleanse_first_arg(); // x is not tainted anymore
+- Name: cleanse_first_arg
+  Args: [0]
+
+  Propagations:
+  # sources:
+# signature:
+# size_t fread(void *ptr, size_t size, size_t nmemb, FILE * stream)
+#
+# example:
+# FILE* f = fopen("file.txt");
+# char buf[1024];
+# size_t read = fread(buf, sizeof(buf[0]), sizeof(buf)/sizeof(buf[0]), f);
+# // read and buf is tainted
+- Name: fread
+  DstArgs: [0, -1]
+
+  # propagations:
+# signature:
+# char *dirname(char *path)
+#
+# example:
+# char* path = read_path();
+# char* dir = dirname(path);
+# // dir is tainted if path was tainted
+- Name: dirname
+  SrcArgs: [0]
+  DstArgs: [-1]
+
+  Sinks:
+# siganture:
+# int system(const char* command)
+#
+# example:
+# const char* command = read_command();
+# system(command); // emit diagnostic if command is tainted
+- Name: system
+  Args: [0]
+
+In the example file above, the entries under the `Propagation` key implement the conceptual sources and propagations, and sinks have their dedicated `Sinks` key.
+The user can define program points where the tainted values should be cleansed by listing entries under the `Filters` key.
+Filters model the sanitization of values done by the programmer, and providing these is key to avoiding false-positive findings.
+
+Configuration file syntax and semantics
+___
+
+The configuration file should have valid `YAML `_ syntax.
+
+The configuration file can have the following top-level keys:
+ - Filters
+ - Propagations
+ - Sinks
+
+Under the `Filters` entry, the user can specify a list of events that remove taint (see :ref:`taint-filter-details` for details).
+
+Under the `Propagations` entry, the user can specify a list of events that generate and propagate taint (see :ref:`taint-propagation-details` for details).
+The user can identify taint sources with a `SrcArgs` key in the `Propagation` entry, while propagations have none.
+
+Under the `Sinks` entry, the user can specify a list of events where the checker should emit a bug report if taint reaches there (see 

[PATCH] D92103: [ASTImporter] Import the default argument of TemplateTypeParmDecl

2020-11-28 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 added a comment.

On bitcoin v0.18.1 , there is 
an assertion introduced by this change.
The TU that can be used for reproduction is `src/script/interpreter.cpp`.
Assertion message:

  CTU loaded AST file: /home/gamesh411/bitcoin/src/script/script.cpp

 
  clang: /home/gamesh411/llvm-project/clang/lib/AST/ASTContext.cpp:4411: 
clang::QualType 
clang::ASTContext::getInjectedClassNameType(clang::CXXRecordDecl*, 
clang::QualType) const: Assertion `NeedsInjectedC
  lassNameType(Decl)' failed.

Stacktrace:

  1.   parser at end of file   

  [310/31632]
  2.  While analyzing stack: 
  #0 Calling CountWitnessSigOps
  3.  /home/gamesh411/bitcoin/src/script/interpreter.cpp:1618:9: Error 
evaluating statement
  4.  /home/gamesh411/bitcoin/src/script/interpreter.cpp:1618:9: Error 
evaluating statement
#0 0x7f9063076451 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) 
(/home/gamesh411/clang-rwa/bin/../lib/libLLVMSupport.so.12git+0x1be451)
#1 0x7f9063073ff4 llvm::sys::RunSignalHandlers() 
(/home/gamesh411/clang-rwa/bin/../lib/libLLVMSupport.so.12git+0x1bbff4)
#2 0x7f9063074291 llvm::sys::CleanupOnSignal(unsigned long) 
(/home/gamesh411/clang-rwa/bin/../lib/libLLVMSupport.so.12git+0x1bc291)
#3 0x7f9062f7d0b8 CrashRecoverySignalHandler(int) 
(/home/gamesh411/clang-rwa/bin/../lib/libLLVMSupport.so.12git+0xc50b8)
#4 0x7f9062b05210 (/lib/x86_64-linux-gnu/libc.so.6+0x46210)
#5 0x7f9062b0518b raise 
/build/glibc-ZN95T4/glibc-2.31/signal/../sysdeps/unix/sysv/linux/raise.c:51:1
#6 0x7f9062ae4859 abort 
/build/glibc-ZN95T4/glibc-2.31/stdlib/abort.c:81:7
#7 0x7f9062ae4729 get_sysdep_segment_value 
/build/glibc-ZN95T4/glibc-2.31/intl/loadmsgcat.c:509:8
#8 0x7f9062ae4729 _nl_load_domain 
/build/glibc-ZN95T4/glibc-2.31/intl/loadmsgcat.c:970:34
#9 0x7f9062af5f36 (/lib/x86_64-linux-gnu/libc.so.6+0x36f36)
   #10 0x7f90612e5be0 
clang::ASTContext::getInjectedClassNameType(clang::CXXRecordDecl*, 
clang::QualType) const 
(/home/gamesh411/clang-rwa/bin/../lib/../lib/libclangAST.so.12git+0x1a4be0)
   #11 0x7f9061393933 
clang::ASTNodeImporter::VisitRecordDecl(clang::RecordDecl*) 
(/home/gamesh411/clang-rwa/bin/../lib/../lib/libclangAST.so.12git+0x252933)
   #12 0x7f9061361055 clang::declvisitor::Base >::Visit(clang::Decl*) 
(/home/gamesh411/clang-rwa/bin/../lib/../lib/libclangAST.so.
  12git+0x220055)
   #13 0x7f906136171e clang::ASTImporter::Import(clang::Decl*) 
(/home/gamesh411/clang-rwa/bin/../lib/../lib/libclangAST.so.12git+0x22071e)
   #14 0x7f906139cfad 
clang::ASTNodeImporter::VisitClassTemplateDecl(clang::ClassTemplateDecl*) 
(/home/gamesh411/clang-rwa/bin/../lib/../lib/libclangAST.so.12git+0x25bfad)
   #15 0x7f9061361125 clang::declvisitor::Base >::Visit(clang::Decl*) 
(/home/gamesh411/clang-rwa/bin/../lib/../lib/libclangAST.so.
  12git+0x220125)
   #16 0x7f906136171e clang::ASTImporter::Import(clang::Decl*) 
(/home/gamesh411/clang-rwa/bin/../lib/../lib/libclangAST.so.12git+0x22071e)
   #17 0x7f90613631cc llvm::Expected 
clang::ASTNodeImporter::import(clang::Decl*) 
(/home/gamesh411/clang-rwa/bin/../lib/../lib/libclangAST.so.12git+0x2221cc)
   #18 0x7f9061370385 
clang::ASTNodeImporter::ImportDeclContext(clang::DeclContext*, bool) 
(/home/gamesh411/clang-rwa/bin/../lib/../lib/libclangAST.so.12git+0x22f385)
   #19 0x7f906139013b 
clang::ASTNodeImporter::VisitNamespaceDecl(clang::NamespaceDecl*) 
(/home/gamesh411/clang-rwa/bin/../lib/../lib/libclangAST.so.12git+0x24f13b)
   #20 0x7f90613612b5 clang::declvisitor::Base >::Visit(clang::Decl*) 
(/home/gamesh411/clang-rwa/bin/../lib/../lib/libclangAST.so.
  12git+0x2202b5)
   #21 0x7f906136171e clang::ASTImporter::Import(clang::Decl*) 
(/home/gamesh411/clang-rwa/bin/../lib/../lib/libclangAST.so.12git+0x22071e)
   #22 0x7f90613631cc llvm::Expected 
clang::ASTNodeImporter::import(clang::Decl*) 
(/home/gamesh411/clang-rwa/bin/../lib/../lib/libclangAST.so.12git+0x2221cc)
   #23 0x7f9061370385 
clang::ASTNodeImporter::ImportDeclContext(clang::DeclContext*, bool) 
(/home/gamesh411/clang-rwa/bin/../lib/../lib/libclangAST.so.12git+0x22f385)
   #24 0x7f906139013b 
clang::ASTNodeImporter::VisitNamespaceDecl(clang::NamespaceDecl*) 
(/home/gamesh411/clang-rwa/bin/../lib/../lib/libclangAST.so.12git+0x24f13b)
   #25 0x7f90613612b5 clang::declvisitor::Base >::Visit(clang::Decl*) 
(/home/gamesh411/clang-rwa/bin/../lib/../lib/libclangAST.so.
  12git+0x2202b5)
   #26 0x7f906136171e clang::ASTImporter::Import(clang::Decl*) 

[PATCH] D89528: [clang][test] Fix prefix operator++ signature in iterators

2020-11-25 Thread Endre Fülöp via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rGdc96cc33c13e: [clang][test] Fix prefix operator++ signature 
in iterators (authored by gamesh411).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D89528/new/

https://reviews.llvm.org/D89528

Files:
  clang/test/Analysis/Inputs/system-header-simulator-cxx.h


Index: clang/test/Analysis/Inputs/system-header-simulator-cxx.h
===
--- clang/test/Analysis/Inputs/system-header-simulator-cxx.h
+++ clang/test/Analysis/Inputs/system-header-simulator-cxx.h
@@ -46,7 +46,7 @@
 
   __vector_iterator(const Ptr p = 0) : ptr(p) {}
   __vector_iterator(const iterator ): ptr(rhs.base()) {}
-  __vector_iterator operator++() { ++ ptr; return *this; }
+  __vector_iterator& operator++() { ++ ptr; return *this; }
   __vector_iterator operator++(int) {
 auto tmp = *this;
 ++ ptr;
@@ -109,7 +109,7 @@
 
   __deque_iterator(const Ptr p = 0) : ptr(p) {}
   __deque_iterator(const iterator ): ptr(rhs.base()) {}
-  __deque_iterator operator++() { ++ ptr; return *this; }
+  __deque_iterator& operator++() { ++ ptr; return *this; }
   __deque_iterator operator++(int) {
 auto tmp = *this;
 ++ ptr;
@@ -169,7 +169,7 @@
 
   __list_iterator(T* it = 0) : item(it) {}
   __list_iterator(const iterator ): item(rhs.item) {}
-  __list_iterator operator++() { item = item->next; return *this; 
}
+  __list_iterator& operator++() { item = item->next; return 
*this; }
   __list_iterator operator++(int) {
 auto tmp = *this;
 item = item->next;
@@ -212,7 +212,7 @@
 
   __fwdl_iterator(T* it = 0) : item(it) {}
   __fwdl_iterator(const iterator ): item(rhs.item) {}
-  __fwdl_iterator operator++() { item = item->next; return *this; 
}
+  __fwdl_iterator& operator++() { item = item->next; return 
*this; }
   __fwdl_iterator operator++(int) {
 auto tmp = *this;
 item = item->next;
@@ -1079,7 +1079,7 @@
 class iterator {
 public:
   iterator(Key *key): ptr(key) {}
-  iterator operator++() { ++ptr; return *this; }
+  iterator& operator++() { ++ptr; return *this; }
   bool operator!=(const iterator ) const { return ptr != other.ptr; }
   const Key *() const { return *ptr; }
 private:
@@ -1104,7 +1104,7 @@
 class iterator {
 public:
   iterator(Key *key): ptr(key) {}
-  iterator operator++() { ++ptr; return *this; }
+  iterator& operator++() { ++ptr; return *this; }
   bool operator!=(const iterator ) const { return ptr != other.ptr; }
   const Key *() const { return *ptr; }
 private:


Index: clang/test/Analysis/Inputs/system-header-simulator-cxx.h
===
--- clang/test/Analysis/Inputs/system-header-simulator-cxx.h
+++ clang/test/Analysis/Inputs/system-header-simulator-cxx.h
@@ -46,7 +46,7 @@
 
   __vector_iterator(const Ptr p = 0) : ptr(p) {}
   __vector_iterator(const iterator ): ptr(rhs.base()) {}
-  __vector_iterator operator++() { ++ ptr; return *this; }
+  __vector_iterator& operator++() { ++ ptr; return *this; }
   __vector_iterator operator++(int) {
 auto tmp = *this;
 ++ ptr;
@@ -109,7 +109,7 @@
 
   __deque_iterator(const Ptr p = 0) : ptr(p) {}
   __deque_iterator(const iterator ): ptr(rhs.base()) {}
-  __deque_iterator operator++() { ++ ptr; return *this; }
+  __deque_iterator& operator++() { ++ ptr; return *this; }
   __deque_iterator operator++(int) {
 auto tmp = *this;
 ++ ptr;
@@ -169,7 +169,7 @@
 
   __list_iterator(T* it = 0) : item(it) {}
   __list_iterator(const iterator ): item(rhs.item) {}
-  __list_iterator operator++() { item = item->next; return *this; }
+  __list_iterator& operator++() { item = item->next; return *this; }
   __list_iterator operator++(int) {
 auto tmp = *this;
 item = item->next;
@@ -212,7 +212,7 @@
 
   __fwdl_iterator(T* it = 0) : item(it) {}
   __fwdl_iterator(const iterator ): item(rhs.item) {}
-  __fwdl_iterator operator++() { item = item->next; return *this; }
+  __fwdl_iterator& operator++() { item = item->next; return *this; }
   __fwdl_iterator operator++(int) {
 auto tmp = *this;
 item = item->next;
@@ -1079,7 +1079,7 @@
 class iterator {
 public:
   iterator(Key *key): ptr(key) {}
-  iterator operator++() { ++ptr; return *this; }
+  iterator& operator++() { ++ptr; return *this; }
   bool operator!=(const iterator ) const { return ptr != other.ptr; }
   const Key *() const { return *ptr; }
 private:
@@ -1104,7 +1104,7 @@
 class iterator {
 public:
   iterator(Key *key): ptr(key) {}
-  iterator operator++() { ++ptr; return *this; }
+  iterator& operator++() { ++ptr; return *this; }
   bool operator!=(const iterator ) const { return ptr != other.ptr; }
   const Key *() const { return *ptr; }
 private:
___
cfe-commits mailing 

[PATCH] D83717: [clang-tidy] Add check fo SEI CERT item ENV32-C

2020-11-25 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 abandoned this revision.
gamesh411 added a comment.

In D83717#2370154 , @NoQ wrote:

> I don't think you actually need active support for invoking exit handlers 
> path-sensitively at the end of `main()` in order to implement your checker. 
> You can still find out in a path-insensitive manner whether any given 
> function acts as an exit handler, like you already do. Then during 
> path-sensitive analysis of that function you can warn at any invocation of 
> exit().
>
> I do believe that you want to implement this check as a path-sensitive check 
> as long as you want any sort of interprocedural analysis (i.e., warn when an 
> exit handler calls a function that calls a function ... that calls a function 
> that calls `exit()` - and you do already have such tests). This is because of 
> the following potential situation:
>
>   void foo(bool already_exiting) {
> if (!already_exiting)
>   exit();
>   }
>   
>   void bar() {
> foo(true);
>   }
>   
>   void baz() {
> foo(false);
>   }
>   
>   int main() {
> atexit(bar);
> return 0;
>   }
>
> In this case `bar()` is an exit handler that calls `foo()` that calls 
> `exit()`. However the code is correct and no warning should be emitted, 
> because `foo()` would never call `exit()` //when called from// `bar()` 
> //specifically//. Precise reasoning about such problems requires 
> path-sensitive analysis. Of course it's up to you to decide what to do with 
> these false positives - whether you'll be ok with having them, or choose to 
> suppress with an imprecise heuristic - but that's one of the possible reasons 
> to consider reimplementing the checker via path sensitive analysis that the 
> static analyzer provides.
>
> We've had a similar problem with the checker that warns on calling pure 
> virtual functions in constructors/destructors (which is undefined behavior). 
> Such checker had to be path sensitive in order to be interprocedural for the 
> exact same unobvious reason. We've decided to re-implement it with 
> path-sensitive analysis and now we're pretty happy about that decision.

Thanks! I have checked, and this is definitely doable (however the solution is 
a bit more involved in case of CTU). This check is definitely better to 
implement in a path-sensitive way.

For anyone looking to implement this (thanks to @NoQ for the original idea 
outline above) :

   This is conceptually a 2 phase solution.
  - Phase 1: detect the functions used as exit_handlers. As an approximation, 
this could be done based on syntax (with an ASTMatcher), not unlike the one 
implemented in this revision. This can be done on the whole TU in any check 
callback, so the availability of this information is not an issue. In case of 
CTU the AST is built during the analysis itself, so theoretically we would want 
to recheck the whole TU every time we use this information (but this seems 
overkill, and computationally intensive). So doing this only once is also an 
approximation.
  - Phase2: during symbolic execution, we check for call expressions of exit 
functions (`_Exit`, `exit`, `quick_exit`), and examine the call-stack to 
identify a parent function declaration, which is in the set of detected 
handler-functions (built during Phase 1). We report an error in this case.

I guess I will abandon this and will create a patch for ClangSA when I will 
have some time for it (can't really promise anything as of now).


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D83717/new/

https://reviews.llvm.org/D83717

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


[PATCH] D91948: [analyzer][doc] Add Container- and IteratorModeling developer docs

2020-11-23 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 created this revision.
Herald added subscribers: cfe-commits, steakhal, ASDenysPetrov, martong, 
Charusso, dkrupp, donat.nagy, Szelethus, mikhail.ramalho, a.sidorin, szepet, 
baloghadamsoftware, xazax.hun, whisperity.
Herald added a project: clang.
gamesh411 requested review of this revision.

Container and IteratorModeling is a feature in ClangSA which handles the 
containers and their 
iterators. Containers include arrays and STL containers, and their iterators 
implemented as either 
pointers or class instances.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D91948

Files:
  clang/docs/analyzer/developer-docs.rst
  clang/docs/analyzer/developer-docs/ContainerModeling.rst

Index: clang/docs/analyzer/developer-docs/ContainerModeling.rst
===
--- /dev/null
+++ clang/docs/analyzer/developer-docs/ContainerModeling.rst
@@ -0,0 +1,386 @@
+===
+Container and Iterator Modeling
+===
+
+The goal of checker ``alpha.cplusplus.ContainerModeling`` is to provide a
+symbolic abstraction for containers to the Clang Static Analyzer. There are
+various concepts regarding containers that help formulate static analysis
+problems more concisely. The size of the container, whether is empty or not are
+the most trivial motivating examples. Standard containers can be iterated, and
+this idiom is well-adopted in case of non-standard container implementations as
+well, because it can be used to provide a compatible interface to algorithms.
+Therefore iterator modeling is closely related to containers. Iterators extend
+the range of useful properties when it comes to finding bugs, for example, which
+container an iterator belongs to, what position inside the container it is in,
+and whether it is a valid or invalid state (see rules for `iterator invalidation
+`_).
+Iterator modeling is implemented in checker ``alpha.cplusplus.IteratorModeling``.
+
+There are also various checkers which make use if the information provided by
+the modeling checkers mentioned:
+  * :ref:`alpha-cplusplus-InvalidatedIterator`
+  * :ref:`alpha-cplusplus-IteratorRange`
+  * :ref:`alpha-cplusplus-MismatchedIterator`
+
+
+Definition of a container
+-
+
+According to ContainerModeling, a value ``c`` with type ``C`` is considered a
+container if either of the following holds:
+  * The expression ``c.begin()`` and ``c.end()`` are both valid expressions, and
+return an `iterator
+`_.
+This should be detected by type C having member functions ``T C::begin()``
+and ``T C::end()``, where T is an `iterator
+`_.
+  * The expression ``begin(c)`` and ``end(c)`` are both valid expressions in a
+given scope, and return an `iterator
+`_.
+This should be detected by checking the existence functions with the
+corresponding names, and can either be user-defined free functions or
+template specialization of the standard-defined ``template
+constexpr auto std::begin(T& t) -> decltype(t.begin())`` and
+``template constexpr auto std::end(T& t) ->
+decltype(t.end())`` function templates (see `std::begin
+`_ and `std::end
+`_).
+
+Example containers in STL (with different `invalidation properties
+`_)
+ - std::array
+ - std::vector
+ - std::deque
+ - std::list
+ - std::forward_list
+
+Example of a custom container with member functions.
+
+.. code-block:: cpp
+
+  class C {
+std::vector v;
+  public:
+using iterator = typename std::vector::iterator;
+
+iterator begin() { return v.begin(); }
+iterator end() { return v.end(); }
+  };
+
+
+Example of a custom container with free functions.
+
+.. code-block:: cpp
+
+  class C {
+std::vector v;
+  public:
+using iterator = typename std::vector::iterator;
+  
+friend iterator begin(C&);
+friend iterator end(C&);
+  };
+
+  C::iterator begin(C& c) { return c.v.begin(); }
+  C::iterator end(C& c) { return c.v.end(); }
+
+Example of a custom container with std template specialization.
+
+.. code-block:: cpp
+
+  class C {
+std::vector v;
+auto begin() { return v.begin(); }
+auto end() { return v.end(); }
+  public:
+template
+friend constexpr auto std::begin(T& t) -> decltype(t.begin());
+template
+friend constexpr auto std::end(T& t) -> decltype(t.end());
+  };
+
+Modeling of a container
+-
+
+A container is modeled if it has an associated ``MemRegion``, and this ``MemRegion``,
+or rather the ``const 

[PATCH] D83717: [clang-tidy] Add check fo SEI CERT item ENV32-C

2020-10-31 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 added a comment.

> Just to make sure we're on the same page -- the current approach is not 
> flow-sensitive, and so my concern is that it won't report any true positives 
> (not that it will be prone to false positives).

Sorry about that. You are absolutely right; what I was trying to say is 
CallGraph-based.

Just some thoughts on this example:

In D83717#2279263 , @aaron.ballman 
wrote:

> One of the concerns I have with this not being a flow-sensitive check is that 
> most of the bad situations are not going to be caught by the clang-tidy 
> version of the check. The CERT rules show contrived code examples, but the 
> more frequent issue looks like:
>
>   void cleanup(struct whatever *ptr) {
> assert(ptr); // This potentially calls abort()
> free(ptr->buffer);
> free(ptr);
>   }
>   ...

What I have in support of this approach is this reasoning:
If a handler is used where either branch can abort then that branch is expected 
to be taken. Otherwise it is dead code. I would argue then, that this abortion 
should be refactored out of the handler function to ensure well-defined 
behaviour in every possible case.

As a counter-argument; suppose that there is a function that is used as both an 
exit-handler and as a simple invocation. In this case, I can understand if one 
would not want to factor the abortion logic out, or possibly pass flags around.

Then to this remark:

> The fact that we're not looking through the call sites (even without cross-TU 
> support) means the check isn't going to catch the most problematic cases. You 
> could modify the called function collector to gather this a bit better, but 
> you'd issue false positives in flow-sensitive situations like:
>
>   void some_cleanup_func(void) {
> for (size_t idx = 0; idx < GlobalElementCount; ++idx) {
>   struct whatever *ptr = GlobalElement[idx];
>   if (ptr) {
> // Now we know abort() won't be called
> cleanup(ptr);
>   }
> }
>   }

The current approach definitely does not take 'adjacent' call-sites into 
account (not to mention CTU ones).
In this regard I also tend to see the benefit of this being a ClangSA checker 
as that would solve 3 problems at once:

1. Being path-sensitive, so we can explain how we got to the erroneous 
program-point
2. It utilizes CTU mode to take callsites from other TU-s into account
3. Runtime-stack building is implicitly done by ExprEngine as a side effect of 
symbolic execution

Counter-argument:
But using ClangSA also introduces a big challenge.
ClangSA analyzes all top-level functions during analysis. However I don't know 
if it understands the concept of exit-handlers, and I don't know a way of 
'triggering' an analysis 'on-exit' so to speak.
So AFAIK this model of analyzing only top-level functions is a limitation when 
it comes to modelling the program behaviour 'on-exit'.
sidenote:
To validate this claim I have dumped the exploded graph of the following file:

  #include 
  #include 
  
  void f() {
std::cout << "handler f";
  };
  
  int main() {
std::atexit(f);
  }

And it has no mention of std::cout being used, so I concluded, that ClangSA 
does not model the 'on-exit' behaviour.

I wanted to clear these issues before I made the documentation.
Thanks for the effort and the tips on evaluating the solution, I will do some 
more exploration.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D83717/new/

https://reviews.llvm.org/D83717

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


[PATCH] D83717: [clang-tidy] Add check fo SEI CERT item ENV32-C

2020-10-30 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 added a comment.

In D83717#2279263 , @aaron.ballman 
wrote:

> One of the concerns I have with this not being a flow-sensitive check is that 
> most of the bad situations are not going to be caught by the clang-tidy 
> version of the check. The CERT rules show contrived code examples, but the 
> more frequent issue looks like:
>
>   void cleanup(struct whatever *ptr) {
> assert(ptr); // This potentially calls abort()
> free(ptr->buffer);
> free(ptr);
>   }
>   
>   void some_cleanup_func(void) {
> for (size_t idx = 0; idx < GlobalElementCount; ++idx) {
>   cleanup(GlobalElement[idx]);
> }
>   }
>   
>   void some_exit_handler(void) {
> ...
> some_cleanup_func();
> ...
>   }
>
> The fact that we're not looking through the call sites (even without cross-TU 
> support) means the check isn't going to catch the most problematic cases. You 
> could modify the called function collector to gather this a bit better, but 
> you'd issue false positives in flow-sensitive situations like:
>
>   void some_cleanup_func(void) {
> for (size_t idx = 0; idx < GlobalElementCount; ++idx) {
>   struct whatever *ptr = GlobalElement[idx];
>   if (ptr) {
> // Now we know abort() won't be called
> cleanup(ptr);
>   }
> }
>   }
>
> Have you run this check over any large code bases to see if it currently 
> catches any true positive diagnostics?

I have tried llvm, tmux, curl and tried codesearch.com to look for other 
sources containing `atexit`, but no results were found. So it is hard to see 
whether this flow-sensitive approach would result in many false positives.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D83717/new/

https://reviews.llvm.org/D83717

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


[PATCH] D87830: [clang-tidy][test] Allow empty checks in check_clang_tidy.py

2020-10-19 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 added a comment.

In D87830#2336572 , @njames93 wrote:

> Probably not quite as verbose but should do the job
>
>   // RUN: clang-tidy %s --checks=-*,my-check-to-test --warnings-as-errors=* 
> -- -std=c++11

Thanks  ! I can live with this solution as well. If however there is a 
suggestion on how to handle this in an idiomatic way, please share, maybe I can 
help implement it.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D87830/new/

https://reviews.llvm.org/D87830

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


[PATCH] D89528: [clang][test] Fix prefix operator++ signature in iterators

2020-10-19 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 added a comment.

In D89528#2334795 , @martong wrote:

> What is the context here? Did it cause any crash/bug or were you just reading 
> through the code for a good night sleep? :D

Actually I was debugging thru iterator-related code and was making assumptions 
on the signature of operators.
Then I noticed the assymetry of return types in case of operator++ (fundamental 
types have ref return values in prefix case, but the simulator header did-not).

Note that the libc++ implementation uses reference return types:
https://github.com/llvm/llvm-project/blob/master/libcxx/include/iterator
So does the libstd++ implementation:
https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/bits/stl_iterator.h


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D89528/new/

https://reviews.llvm.org/D89528

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


[PATCH] D87830: [clang-tidy][test] Allow empty checks in check_clang_tidy.py

2020-10-16 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 added a comment.

In D87830#2298198 , @aaron.ballman 
wrote:

> 



> know of any tests that are impacted by this?

I haven't found any tidy-tests that were negative-tests (ie.: tests that assert 
that there are no diagnostics).

> ... if I understand the proposed patch, that may now be silently accepted as 
> a passing test?

This is not entirely the case. Let me demonstrate with a few cases:
Before this patch:

  // empty test
  // RUN: %check_clang_tidy %s %t
  // no CHECK lines in the entire file

In the above case the test will fail with `CHECK-FIXES, CHECK-MESSAGES or 
CHECK-NOTES not found in the input`.

  // empty test, but explicityly mention we dont want diagnostics
  // RUN: %check_clang_tidy %s %t
  // CHECK_MESSAGES_NOT: ARBITRARY STRING HERE
  // ...
  // there are *no* other CHECK messages

This passes the first round of sanity checking, but FileCheck nevertheless 
rejects the processed test file:
FileCheck error: 
'/home/gamesh411/clang-rwa/tools/clang/tools/extra/test/clang-tidy/checkers/Output/empty.cpp.tmp.cpp.msg'
 is empty.

  // empty test, but explicityly mention we dont want diagnostics
  // RUN: %check_clang_tidy %s %t
  // CHECK_MESSAGES_NOT: arbitrary string here, I prefer NO DIAG
  // ...
  // there *are* some other CHECK messages further down

This is fine, but only means that the arbitrary string diagnostic is expected 
to be *not* seen, while some others are.

After patch:
The second case above becomes fine, everything else stays the same.

> Or should this not be an issue in general because `// CHECK` lines should 
> still be present in the test and those will fail when compared against an 
> empty file?

This means that the only accidental empty test scenario is when someone 
accidentally skips the CHECK messages he wants to put in, *but* manages to put 
in the CHECK-NOT by accident as well. This can result from copy-paste, but 
still, I think this is not likely.

> I'm wondering if we want to require something like `// 
> expected-no-diagnostics` from the `-verify` command in Clang so that users 
> have to explicitly opt a test into the behavior?

My thoughts were exactly that; I need something like the DiagVerifier's 
`expected-no-diagnostics`. That was the motivation behind this patch.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D87830/new/

https://reviews.llvm.org/D87830

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


[PATCH] D89528: [clang][test] Fix prefix operator++ signature in iterators

2020-10-16 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 created this revision.
Herald added subscribers: cfe-commits, martong, Szelethus, dkrupp.
Herald added a reviewer: Szelethus.
Herald added a project: clang.
gamesh411 requested review of this revision.

Prefix operator++ should return the iterator incremented by reference.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D89528

Files:
  clang/test/Analysis/Inputs/system-header-simulator-cxx.h


Index: clang/test/Analysis/Inputs/system-header-simulator-cxx.h
===
--- clang/test/Analysis/Inputs/system-header-simulator-cxx.h
+++ clang/test/Analysis/Inputs/system-header-simulator-cxx.h
@@ -46,7 +46,7 @@
 
   __vector_iterator(const Ptr p = 0) : ptr(p) {}
   __vector_iterator(const iterator ): ptr(rhs.base()) {}
-  __vector_iterator operator++() { ++ ptr; return *this; }
+  __vector_iterator& operator++() { ++ ptr; return *this; }
   __vector_iterator operator++(int) {
 auto tmp = *this;
 ++ ptr;
@@ -109,7 +109,7 @@
 
   __deque_iterator(const Ptr p = 0) : ptr(p) {}
   __deque_iterator(const iterator ): ptr(rhs.base()) {}
-  __deque_iterator operator++() { ++ ptr; return *this; }
+  __deque_iterator& operator++() { ++ ptr; return *this; }
   __deque_iterator operator++(int) {
 auto tmp = *this;
 ++ ptr;
@@ -169,7 +169,7 @@
 
   __list_iterator(T* it = 0) : item(it) {}
   __list_iterator(const iterator ): item(rhs.item) {}
-  __list_iterator operator++() { item = item->next; return *this; 
}
+  __list_iterator& operator++() { item = item->next; return 
*this; }
   __list_iterator operator++(int) {
 auto tmp = *this;
 item = item->next;
@@ -212,7 +212,7 @@
 
   __fwdl_iterator(T* it = 0) : item(it) {}
   __fwdl_iterator(const iterator ): item(rhs.item) {}
-  __fwdl_iterator operator++() { item = item->next; return *this; 
}
+  __fwdl_iterator& operator++() { item = item->next; return 
*this; }
   __fwdl_iterator operator++(int) {
 auto tmp = *this;
 item = item->next;
@@ -1079,7 +1079,7 @@
 class iterator {
 public:
   iterator(Key *key): ptr(key) {}
-  iterator operator++() { ++ptr; return *this; }
+  iterator& operator++() { ++ptr; return *this; }
   bool operator!=(const iterator ) const { return ptr != other.ptr; }
   const Key *() const { return *ptr; }
 private:
@@ -1104,7 +1104,7 @@
 class iterator {
 public:
   iterator(Key *key): ptr(key) {}
-  iterator operator++() { ++ptr; return *this; }
+  iterator& operator++() { ++ptr; return *this; }
   bool operator!=(const iterator ) const { return ptr != other.ptr; }
   const Key *() const { return *ptr; }
 private:


Index: clang/test/Analysis/Inputs/system-header-simulator-cxx.h
===
--- clang/test/Analysis/Inputs/system-header-simulator-cxx.h
+++ clang/test/Analysis/Inputs/system-header-simulator-cxx.h
@@ -46,7 +46,7 @@
 
   __vector_iterator(const Ptr p = 0) : ptr(p) {}
   __vector_iterator(const iterator ): ptr(rhs.base()) {}
-  __vector_iterator operator++() { ++ ptr; return *this; }
+  __vector_iterator& operator++() { ++ ptr; return *this; }
   __vector_iterator operator++(int) {
 auto tmp = *this;
 ++ ptr;
@@ -109,7 +109,7 @@
 
   __deque_iterator(const Ptr p = 0) : ptr(p) {}
   __deque_iterator(const iterator ): ptr(rhs.base()) {}
-  __deque_iterator operator++() { ++ ptr; return *this; }
+  __deque_iterator& operator++() { ++ ptr; return *this; }
   __deque_iterator operator++(int) {
 auto tmp = *this;
 ++ ptr;
@@ -169,7 +169,7 @@
 
   __list_iterator(T* it = 0) : item(it) {}
   __list_iterator(const iterator ): item(rhs.item) {}
-  __list_iterator operator++() { item = item->next; return *this; }
+  __list_iterator& operator++() { item = item->next; return *this; }
   __list_iterator operator++(int) {
 auto tmp = *this;
 item = item->next;
@@ -212,7 +212,7 @@
 
   __fwdl_iterator(T* it = 0) : item(it) {}
   __fwdl_iterator(const iterator ): item(rhs.item) {}
-  __fwdl_iterator operator++() { item = item->next; return *this; }
+  __fwdl_iterator& operator++() { item = item->next; return *this; }
   __fwdl_iterator operator++(int) {
 auto tmp = *this;
 item = item->next;
@@ -1079,7 +1079,7 @@
 class iterator {
 public:
   iterator(Key *key): ptr(key) {}
-  iterator operator++() { ++ptr; return *this; }
+  iterator& operator++() { ++ptr; return *this; }
   bool operator!=(const iterator ) const { return ptr != other.ptr; }
   const Key *() const { return *ptr; }
 private:
@@ -1104,7 +1104,7 @@
 class iterator {
 public:
   iterator(Key *key): ptr(key) {}
-  iterator operator++() { ++ptr; return *this; }
+  iterator& operator++() { ++ptr; return *this; }
   bool operator!=(const iterator ) const { return ptr != other.ptr; }
   const Key *() const { return *ptr; }
 private:

[PATCH] D87830: [clang-tidy][test] Allow empty checks in check_clang_tidy.py

2020-09-28 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 added a comment.

Do you have some thoughts about this, should this be pursued, or do you think 
the use-case is not relevant?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D87830/new/

https://reviews.llvm.org/D87830

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


[PATCH] D83717: [clang-tidy] Add check fo SEI CERT item ENV32-C

2020-09-17 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 updated this revision to Diff 292488.
gamesh411 added a comment.

Update commit message


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D83717/new/

https://reviews.llvm.org/D83717

Files:
  clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp
  clang-tools-extra/clang-tidy/cert/CMakeLists.txt
  clang-tools-extra/clang-tidy/cert/ExitHandlerCheck.cpp
  clang-tools-extra/clang-tidy/cert/ExitHandlerCheck.h
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/docs/clang-tidy/checks/cert-env32-c.rst
  clang-tools-extra/docs/clang-tidy/checks/list.rst
  clang-tools-extra/test/clang-tidy/checkers/cert-env32-c-teminate.cpp
  clang-tools-extra/test/clang-tidy/checkers/cert-env32-c.c
  llvm/utils/gn/secondary/clang-tools-extra/clang-tidy/cert/BUILD.gn

Index: llvm/utils/gn/secondary/clang-tools-extra/clang-tidy/cert/BUILD.gn
===
--- llvm/utils/gn/secondary/clang-tools-extra/clang-tidy/cert/BUILD.gn
+++ llvm/utils/gn/secondary/clang-tools-extra/clang-tidy/cert/BUILD.gn
@@ -19,6 +19,7 @@
 "CommandProcessorCheck.cpp",
 "DefaultOperatorNewAlignmentCheck.cpp",
 "DontModifyStdNamespaceCheck.cpp",
+"ExitHandlerCheck.cpp",
 "FloatLoopCounter.cpp",
 "LimitedRandomnessCheck.cpp",
 "MutatingCopyCheck.cpp",
Index: clang-tools-extra/test/clang-tidy/checkers/cert-env32-c.c
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/cert-env32-c.c
@@ -0,0 +1,412 @@
+// Test as a C file.
+// RUN: %check_clang_tidy %s cert-env32-c %t -- -- -DCMODE
+//
+// Test as a C++ file.
+//
+// Test functions in global namespace.
+// RUN: %check_clang_tidy -assume-filename=%s.cpp %s cert-env32-c %t \
+// RUN: -- -- -DCPPMODE
+//
+// Test functions in std namespace.
+// RUN: %check_clang_tidy -assume-filename=%s.cpp %s cert-env32-c %t \
+// RUN: -- -- -DCPPMODE -DTEST_NS_NAME=std
+
+#if defined(CPPMODE) && defined(TEST_NS_NAME)
+namespace TEST_NS_NAME {
+#endif
+
+// --
+// EXIT FUNCTIONS
+// --
+
+// No handlers are invoked when _Exit is called.
+void _Exit(int __status);
+
+// Handlers registered by atexit are invoked in reverse order when exit is
+// called.
+void exit(int __status);
+
+// Handlers registered by at_quick_exit are invoked in reverse order when
+// quick_exit is called.
+void quick_exit(int __status);
+
+// The program is terminated without destroying any object and without calling
+// any of the functions passed to atexit or at_quick_exit.
+void abort();
+
+// 
+// HANDLER REGISTRATION
+// 
+
+// Register handlers to run when exit is called.
+int atexit(void (*__func)(void));
+
+// Register handlers to run when exit is called.
+int at_quick_exit(void (*__func)(void));
+
+// --
+// Setjmp/longjmp
+// --
+// C99 requires jmp_buf to be an array type.
+typedef int jmp_buf[1];
+int setjmp(jmp_buf);
+void longjmp(jmp_buf, int);
+
+// Compliant solutions
+
+void cleanup1() {
+  // do cleanup
+}
+
+void cleanup2() {
+  // do cleanup
+}
+
+void test_atexit_single_compliant() {
+  (void)atexit(cleanup1);
+}
+
+void test_atexit_multiple_compliant() {
+  (void)atexit(cleanup1);
+  (void)atexit(cleanup2);
+}
+
+void test_at_quick_exit_single_compliant() {
+  (void)at_quick_exit(cleanup1);
+}
+
+void test_at_quick_exit_multiple_compliant() {
+  (void)at_quick_exit(cleanup1);
+  (void)at_quick_exit(cleanup2);
+}
+
+// Non-compliant solutions calling _Exit
+
+void call__Exit() {
+  _Exit(0);
+}
+
+void call_call__Exit() {
+  call__Exit();
+}
+
+extern int unknown__Exit_flag;
+
+void call__Exit_conditionally() {
+  if (unknown__Exit_flag)
+call__Exit();
+}
+
+void call_call__Exit_conditionally() {
+  call__Exit_conditionally();
+}
+
+void test__Exit_called_directly() {
+  (void)atexit(call__Exit);
+  // CHECK-NOTES: :[[@LINE-1]]:9: warning: exit-handler potentially calls an exit function instead of terminating normally with a return [cert-env32-c]
+  // CHECK-NOTES: :[[@LINE-22]]:1: note: handler function declared here
+  // CHECK-NOTES: :[[@LINE-22]]:3: note: exit function called here
+  (void)at_quick_exit(call__Exit);
+  // CHECK-NOTES: :[[@LINE-1]]:9: warning: exit-handler potentially calls an exit function instead of terminating normally with a return [cert-env32-c]
+  // CHECK-NOTES: :[[@LINE-26]]:1: note: handler function declared here
+  // CHECK-NOTES: :[[@LINE-26]]:3: note: exit function called here
+};
+
+void test__Exit_called_indirectly() {
+  (void)atexit(call_call__Exit);
+  // CHECK-NOTES: :[[@LINE-1]]:9: warning: exit-handler potentially calls an exit function instead of terminating normally with a return [cert-env32-c]
+  // CHECK-NOTES: :[[@LINE-29]]:1: note: handler function declared here
+  // CHECK-NOTES: :[[@LINE-33]]:3: note: exit function called here
+  (void)at_quick_exit(call_call__Exit);
+  // 

[PATCH] D87830: [clang-tidy][test] Allow empty checks in check_clang_tidy.py

2020-09-17 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 updated this revision to Diff 292487.
gamesh411 added a comment.

Tidy up commit message


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D87830/new/

https://reviews.llvm.org/D87830

Files:
  clang-tools-extra/test/clang-tidy/check_clang_tidy.py


Index: clang-tools-extra/test/clang-tidy/check_clang_tidy.py
===
--- clang-tools-extra/test/clang-tidy/check_clang_tidy.py
+++ clang-tools-extra/test/clang-tidy/check_clang_tidy.py
@@ -167,7 +167,7 @@
   subprocess.check_output(
   ['FileCheck', '-input-file=' + temp_file_name, input_file_name,
'-check-prefixes=' + ','.join(check_fixes_prefixes),
-   '-strict-whitespace'],
+   '-strict-whitespace', '--allow-empty'],
   stderr=subprocess.STDOUT)
 except subprocess.CalledProcessError as e:
   print('FileCheck failed:\n' + e.output.decode())
@@ -180,7 +180,7 @@
   subprocess.check_output(
   ['FileCheck', '-input-file=' + messages_file, input_file_name,
'-check-prefixes=' + ','.join(check_messages_prefixes),
-   '-implicit-check-not={{warning|error}}:'],
+   '-implicit-check-not={{warning|error}}:', '--allow-empty'],
   stderr=subprocess.STDOUT)
 except subprocess.CalledProcessError as e:
   print('FileCheck failed:\n' + e.output.decode())
@@ -195,7 +195,7 @@
   subprocess.check_output(
   ['FileCheck', '-input-file=' + notes_file, input_file_name,
'-check-prefixes=' + ','.join(check_notes_prefixes),
-   '-implicit-check-not={{note|warning|error}}:'],
+   '-implicit-check-not={{note|warning|error}}:', '--allow-empty'],
   stderr=subprocess.STDOUT)
 except subprocess.CalledProcessError as e:
   print('FileCheck failed:\n' + e.output.decode())


Index: clang-tools-extra/test/clang-tidy/check_clang_tidy.py
===
--- clang-tools-extra/test/clang-tidy/check_clang_tidy.py
+++ clang-tools-extra/test/clang-tidy/check_clang_tidy.py
@@ -167,7 +167,7 @@
   subprocess.check_output(
   ['FileCheck', '-input-file=' + temp_file_name, input_file_name,
'-check-prefixes=' + ','.join(check_fixes_prefixes),
-   '-strict-whitespace'],
+   '-strict-whitespace', '--allow-empty'],
   stderr=subprocess.STDOUT)
 except subprocess.CalledProcessError as e:
   print('FileCheck failed:\n' + e.output.decode())
@@ -180,7 +180,7 @@
   subprocess.check_output(
   ['FileCheck', '-input-file=' + messages_file, input_file_name,
'-check-prefixes=' + ','.join(check_messages_prefixes),
-   '-implicit-check-not={{warning|error}}:'],
+   '-implicit-check-not={{warning|error}}:', '--allow-empty'],
   stderr=subprocess.STDOUT)
 except subprocess.CalledProcessError as e:
   print('FileCheck failed:\n' + e.output.decode())
@@ -195,7 +195,7 @@
   subprocess.check_output(
   ['FileCheck', '-input-file=' + notes_file, input_file_name,
'-check-prefixes=' + ','.join(check_notes_prefixes),
-   '-implicit-check-not={{note|warning|error}}:'],
+   '-implicit-check-not={{note|warning|error}}:', '--allow-empty'],
   stderr=subprocess.STDOUT)
 except subprocess.CalledProcessError as e:
   print('FileCheck failed:\n' + e.output.decode())
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D87830: [clang-tidy][test] Allow empty checks in check_clang_tidy.py

2020-09-17 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 updated this revision to Diff 292485.
gamesh411 added a comment.

Update commit msg with example


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D87830/new/

https://reviews.llvm.org/D87830

Files:
  clang-tools-extra/test/clang-tidy/check_clang_tidy.py


Index: clang-tools-extra/test/clang-tidy/check_clang_tidy.py
===
--- clang-tools-extra/test/clang-tidy/check_clang_tidy.py
+++ clang-tools-extra/test/clang-tidy/check_clang_tidy.py
@@ -167,7 +167,7 @@
   subprocess.check_output(
   ['FileCheck', '-input-file=' + temp_file_name, input_file_name,
'-check-prefixes=' + ','.join(check_fixes_prefixes),
-   '-strict-whitespace'],
+   '-strict-whitespace', '--allow-empty'],
   stderr=subprocess.STDOUT)
 except subprocess.CalledProcessError as e:
   print('FileCheck failed:\n' + e.output.decode())
@@ -180,7 +180,7 @@
   subprocess.check_output(
   ['FileCheck', '-input-file=' + messages_file, input_file_name,
'-check-prefixes=' + ','.join(check_messages_prefixes),
-   '-implicit-check-not={{warning|error}}:'],
+   '-implicit-check-not={{warning|error}}:', '--allow-empty'],
   stderr=subprocess.STDOUT)
 except subprocess.CalledProcessError as e:
   print('FileCheck failed:\n' + e.output.decode())
@@ -195,7 +195,7 @@
   subprocess.check_output(
   ['FileCheck', '-input-file=' + notes_file, input_file_name,
'-check-prefixes=' + ','.join(check_notes_prefixes),
-   '-implicit-check-not={{note|warning|error}}:'],
+   '-implicit-check-not={{note|warning|error}}:', '--allow-empty'],
   stderr=subprocess.STDOUT)
 except subprocess.CalledProcessError as e:
   print('FileCheck failed:\n' + e.output.decode())


Index: clang-tools-extra/test/clang-tidy/check_clang_tidy.py
===
--- clang-tools-extra/test/clang-tidy/check_clang_tidy.py
+++ clang-tools-extra/test/clang-tidy/check_clang_tidy.py
@@ -167,7 +167,7 @@
   subprocess.check_output(
   ['FileCheck', '-input-file=' + temp_file_name, input_file_name,
'-check-prefixes=' + ','.join(check_fixes_prefixes),
-   '-strict-whitespace'],
+   '-strict-whitespace', '--allow-empty'],
   stderr=subprocess.STDOUT)
 except subprocess.CalledProcessError as e:
   print('FileCheck failed:\n' + e.output.decode())
@@ -180,7 +180,7 @@
   subprocess.check_output(
   ['FileCheck', '-input-file=' + messages_file, input_file_name,
'-check-prefixes=' + ','.join(check_messages_prefixes),
-   '-implicit-check-not={{warning|error}}:'],
+   '-implicit-check-not={{warning|error}}:', '--allow-empty'],
   stderr=subprocess.STDOUT)
 except subprocess.CalledProcessError as e:
   print('FileCheck failed:\n' + e.output.decode())
@@ -195,7 +195,7 @@
   subprocess.check_output(
   ['FileCheck', '-input-file=' + notes_file, input_file_name,
'-check-prefixes=' + ','.join(check_notes_prefixes),
-   '-implicit-check-not={{note|warning|error}}:'],
+   '-implicit-check-not={{note|warning|error}}:', '--allow-empty'],
   stderr=subprocess.STDOUT)
 except subprocess.CalledProcessError as e:
   print('FileCheck failed:\n' + e.output.decode())
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D87830: [clang-tidy][test] Allow empty checks in check_clang_tidy.py

2020-09-17 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 created this revision.
Herald added subscribers: cfe-commits, martong, steakhal, Szelethus, dkrupp, 
xazax.hun, whisperity.
Herald added a project: clang.
gamesh411 requested review of this revision.

Currently there is no way to assert that a check does not produce warnings for 
a specific run. The CHECK-NOT directive can be used, but an empty file is 
always discarded by FileCheck. Extend the FileCheck invocation with 
'--allow-empty' to support this usecase.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D87830

Files:
  clang-tools-extra/test/clang-tidy/check_clang_tidy.py


Index: clang-tools-extra/test/clang-tidy/check_clang_tidy.py
===
--- clang-tools-extra/test/clang-tidy/check_clang_tidy.py
+++ clang-tools-extra/test/clang-tidy/check_clang_tidy.py
@@ -167,7 +167,7 @@
   subprocess.check_output(
   ['FileCheck', '-input-file=' + temp_file_name, input_file_name,
'-check-prefixes=' + ','.join(check_fixes_prefixes),
-   '-strict-whitespace'],
+   '-strict-whitespace', '--allow-empty'],
   stderr=subprocess.STDOUT)
 except subprocess.CalledProcessError as e:
   print('FileCheck failed:\n' + e.output.decode())
@@ -180,7 +180,7 @@
   subprocess.check_output(
   ['FileCheck', '-input-file=' + messages_file, input_file_name,
'-check-prefixes=' + ','.join(check_messages_prefixes),
-   '-implicit-check-not={{warning|error}}:'],
+   '-implicit-check-not={{warning|error}}:', '--allow-empty'],
   stderr=subprocess.STDOUT)
 except subprocess.CalledProcessError as e:
   print('FileCheck failed:\n' + e.output.decode())
@@ -195,7 +195,7 @@
   subprocess.check_output(
   ['FileCheck', '-input-file=' + notes_file, input_file_name,
'-check-prefixes=' + ','.join(check_notes_prefixes),
-   '-implicit-check-not={{note|warning|error}}:'],
+   '-implicit-check-not={{note|warning|error}}:', '--allow-empty'],
   stderr=subprocess.STDOUT)
 except subprocess.CalledProcessError as e:
   print('FileCheck failed:\n' + e.output.decode())


Index: clang-tools-extra/test/clang-tidy/check_clang_tidy.py
===
--- clang-tools-extra/test/clang-tidy/check_clang_tidy.py
+++ clang-tools-extra/test/clang-tidy/check_clang_tidy.py
@@ -167,7 +167,7 @@
   subprocess.check_output(
   ['FileCheck', '-input-file=' + temp_file_name, input_file_name,
'-check-prefixes=' + ','.join(check_fixes_prefixes),
-   '-strict-whitespace'],
+   '-strict-whitespace', '--allow-empty'],
   stderr=subprocess.STDOUT)
 except subprocess.CalledProcessError as e:
   print('FileCheck failed:\n' + e.output.decode())
@@ -180,7 +180,7 @@
   subprocess.check_output(
   ['FileCheck', '-input-file=' + messages_file, input_file_name,
'-check-prefixes=' + ','.join(check_messages_prefixes),
-   '-implicit-check-not={{warning|error}}:'],
+   '-implicit-check-not={{warning|error}}:', '--allow-empty'],
   stderr=subprocess.STDOUT)
 except subprocess.CalledProcessError as e:
   print('FileCheck failed:\n' + e.output.decode())
@@ -195,7 +195,7 @@
   subprocess.check_output(
   ['FileCheck', '-input-file=' + notes_file, input_file_name,
'-check-prefixes=' + ','.join(check_notes_prefixes),
-   '-implicit-check-not={{note|warning|error}}:'],
+   '-implicit-check-not={{note|warning|error}}:', '--allow-empty'],
   stderr=subprocess.STDOUT)
 except subprocess.CalledProcessError as e:
   print('FileCheck failed:\n' + e.output.decode())
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D83717: [clang-tidy] Add check fo SEI CERT item ENV32-C

2020-09-17 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 updated this revision to Diff 292419.
gamesh411 added a comment.

Reformat diagnostic message
Use explicit name longjmp instead of jump function
Fix liberal auto inside Collector


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D83717/new/

https://reviews.llvm.org/D83717

Files:
  clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp
  clang-tools-extra/clang-tidy/cert/CMakeLists.txt
  clang-tools-extra/clang-tidy/cert/ExitHandlerCheck.cpp
  clang-tools-extra/clang-tidy/cert/ExitHandlerCheck.h
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/docs/clang-tidy/checks/cert-env32-c.rst
  clang-tools-extra/docs/clang-tidy/checks/list.rst
  clang-tools-extra/test/clang-tidy/checkers/cert-env32-c-teminate.cpp
  clang-tools-extra/test/clang-tidy/checkers/cert-env32-c.c
  llvm/utils/gn/secondary/clang-tools-extra/clang-tidy/cert/BUILD.gn

Index: llvm/utils/gn/secondary/clang-tools-extra/clang-tidy/cert/BUILD.gn
===
--- llvm/utils/gn/secondary/clang-tools-extra/clang-tidy/cert/BUILD.gn
+++ llvm/utils/gn/secondary/clang-tools-extra/clang-tidy/cert/BUILD.gn
@@ -19,6 +19,7 @@
 "CommandProcessorCheck.cpp",
 "DefaultOperatorNewAlignmentCheck.cpp",
 "DontModifyStdNamespaceCheck.cpp",
+"ExitHandlerCheck.cpp",
 "FloatLoopCounter.cpp",
 "LimitedRandomnessCheck.cpp",
 "MutatingCopyCheck.cpp",
Index: clang-tools-extra/test/clang-tidy/checkers/cert-env32-c.c
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/cert-env32-c.c
@@ -0,0 +1,412 @@
+// Test as a C file.
+// RUN: %check_clang_tidy %s cert-env32-c %t -- -- -DCMODE
+//
+// Test as a C++ file.
+//
+// Test functions in global namespace.
+// RUN: %check_clang_tidy -assume-filename=%s.cpp %s cert-env32-c %t \
+// RUN: -- -- -DCPPMODE
+//
+// Test functions in std namespace.
+// RUN: %check_clang_tidy -assume-filename=%s.cpp %s cert-env32-c %t \
+// RUN: -- -- -DCPPMODE -DTEST_NS_NAME=std
+
+#if defined(CPPMODE) && defined(TEST_NS_NAME)
+namespace TEST_NS_NAME {
+#endif
+
+// --
+// EXIT FUNCTIONS
+// --
+
+// No handlers are invoked when _Exit is called.
+void _Exit(int __status);
+
+// Handlers registered by atexit are invoked in reverse order when exit is
+// called.
+void exit(int __status);
+
+// Handlers registered by at_quick_exit are invoked in reverse order when
+// quick_exit is called.
+void quick_exit(int __status);
+
+// The program is terminated without destroying any object and without calling
+// any of the functions passed to atexit or at_quick_exit.
+void abort();
+
+// 
+// HANDLER REGISTRATION
+// 
+
+// Register handlers to run when exit is called.
+int atexit(void (*__func)(void));
+
+// Register handlers to run when exit is called.
+int at_quick_exit(void (*__func)(void));
+
+// --
+// Setjmp/longjmp
+// --
+// C99 requires jmp_buf to be an array type.
+typedef int jmp_buf[1];
+int setjmp(jmp_buf);
+void longjmp(jmp_buf, int);
+
+// Compliant solutions
+
+void cleanup1() {
+  // do cleanup
+}
+
+void cleanup2() {
+  // do cleanup
+}
+
+void test_atexit_single_compliant() {
+  (void)atexit(cleanup1);
+}
+
+void test_atexit_multiple_compliant() {
+  (void)atexit(cleanup1);
+  (void)atexit(cleanup2);
+}
+
+void test_at_quick_exit_single_compliant() {
+  (void)at_quick_exit(cleanup1);
+}
+
+void test_at_quick_exit_multiple_compliant() {
+  (void)at_quick_exit(cleanup1);
+  (void)at_quick_exit(cleanup2);
+}
+
+// Non-compliant solutions calling _Exit
+
+void call__Exit() {
+  _Exit(0);
+}
+
+void call_call__Exit() {
+  call__Exit();
+}
+
+extern int unknown__Exit_flag;
+
+void call__Exit_conditionally() {
+  if (unknown__Exit_flag)
+call__Exit();
+}
+
+void call_call__Exit_conditionally() {
+  call__Exit_conditionally();
+}
+
+void test__Exit_called_directly() {
+  (void)atexit(call__Exit);
+  // CHECK-NOTES: :[[@LINE-1]]:9: warning: exit-handler potentially calls an exit function instead of terminating normally with a return [cert-env32-c]
+  // CHECK-NOTES: :[[@LINE-22]]:1: note: handler function declared here
+  // CHECK-NOTES: :[[@LINE-22]]:3: note: exit function called here
+  (void)at_quick_exit(call__Exit);
+  // CHECK-NOTES: :[[@LINE-1]]:9: warning: exit-handler potentially calls an exit function instead of terminating normally with a return [cert-env32-c]
+  // CHECK-NOTES: :[[@LINE-26]]:1: note: handler function declared here
+  // CHECK-NOTES: :[[@LINE-26]]:3: note: exit function called here
+};
+
+void test__Exit_called_indirectly() {
+  (void)atexit(call_call__Exit);
+  // CHECK-NOTES: :[[@LINE-1]]:9: warning: exit-handler potentially calls an exit function instead of terminating normally with a return [cert-env32-c]
+  // CHECK-NOTES: :[[@LINE-29]]:1: note: handler function declared here
+  // CHECK-NOTES: 

[PATCH] D83717: [clang-tidy] Add check fo SEI CERT item ENV32-C

2020-09-17 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 marked 13 inline comments as done.
gamesh411 added a comment.

Note that there are no negative test cases that assert that we do NOT report in 
case a custom or an anonymous namespace is used. For that I would need a small 
patch in the testing infrastructure.
Patch needed in check_clang_tidy.py:

  --- a/clang-tools-extra/test/clang-tidy/check_clang_tidy.py
  +++ b/clang-tools-extra/test/clang-tidy/check_clang_tidy.py
  @@ -167,7 +167,7 @@ def run_test_once(args, extra_args):
 subprocess.check_output(
 ['FileCheck', '-input-file=' + temp_file_name, input_file_name,
  '-check-prefixes=' + ','.join(check_fixes_prefixes),
  -   '-strict-whitespace'],
  +   '-strict-whitespace', '--allow-empty'],
 stderr=subprocess.STDOUT)
   except subprocess.CalledProcessError as e:
 print('FileCheck failed:\n' + e.output.decode())
  @@ -180,7 +180,7 @@ def run_test_once(args, extra_args):
 subprocess.check_output(
 ['FileCheck', '-input-file=' + messages_file, input_file_name,
  '-check-prefixes=' + ','.join(check_messages_prefixes),
  -   '-implicit-check-not={{warning|error}}:'],
  +   '-implicit-check-not={{warning|error}}:', '--allow-empty'],
 stderr=subprocess.STDOUT)
   except subprocess.CalledProcessError as e:
 print('FileCheck failed:\n' + e.output.decode())
  @@ -195,7 +195,7 @@ def run_test_once(args, extra_args):
 subprocess.check_output(
 ['FileCheck', '-input-file=' + notes_file, input_file_name,
  '-check-prefixes=' + ','.join(check_notes_prefixes),
  -   '-implicit-check-not={{note|warning|error}}:'],
  +   '-implicit-check-not={{note|warning|error}}:', '--allow-empty'],
 stderr=subprocess.STDOUT)
   except subprocess.CalledProcessError as e:
 print('FileCheck failed:\n' + e.output.decode())

And then I can assert the non-reports by adding the following runlines:

  // Functions in anonymous or custom namespace should not be considered as exit
  // functions.
  //
  // RUN: %check_clang_tidy -assume-filename=%s.cpp %s -check-suffix=CUSTOM \
  // RUN: cert-env32-c %t -- -- -DCPPMODE -DTEST_NS_NAME=custom
  // CHECK-NOTES-CUSTOM-NOT: NO DIAGS
  //
  // RUN: %check_clang_tidy -assume-filename=%s.cpp %s -check-suffix=ANONYMOUS \
  // RUN: cert-env32-c %t -- -- -DCPPMODE -DTEST_NS_NAME=''
  // CHECK-NOTES-ANONYMOUS-NOT: NO DIAGS




Comment at: clang-tools-extra/clang-tidy/cert/ExitHandlerCheck.cpp:70
+ .bind("handler_expr"));
+  Finder->addMatcher(
+  callExpr(IsRegisterFunction, HasHandlerAsFirstArg).bind("register_call"),

aaron.ballman wrote:
> I am not at all certain whether this is plausible, but I *think* this check 
> can be almost entirely implemented in the matchers rather than having to do 
> manual work. I think you can bind the argument node from the call to 
> `at_quick_exit()` and then use `equalsBoundNode()` to find the function calls 
> within the bound `functionDecl()` node.
> 
> However, if that's not workable, I think you can get rid of the 
> `CalledFunctionsCollector` entirely and just use matchers directly within the 
> `check()` function because by that point, you'll know exactly which AST nodes 
> you want to traverse through.
I have investigated, and to do that recursive matching up to indeterminate 
depth all the while keeping the already matched functions in a set is not 
something I would implement with a single matcher. I could use a standalone 
matcher, but as far as I can understand I would need to implement a callback 
function for handling the matched results out of line for that as well, so I 
think that the ASTVisitor based solution is at least as good as a standalone 
ASTMatcher would be. Therefore I'd rather keep this solution.



Comment at: clang-tools-extra/test/clang-tidy/checkers/cert-env32-c.c:31
+// --
+// C99 requires jmp_buf to be an array type.
+typedef int jmp_buf[1];

whisperity wrote:
> Which is the standard version this test file is set to analyse with? I don't 
> see any `-std=` flag in the `RUN:` line.
Right now there is a run-line for handling it as C, and 2 others for handling 
it as C++ with different namespaces. The test cases themselves are not 
dependent on the standard used (AFAIK).  The comment contains a standard 
reference for C, but that is just the first time it was standardized in C so 
the mention is there for traceability and not to restrict the standard used.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D83717/new/

https://reviews.llvm.org/D83717

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


[PATCH] D83717: [clang-tidy] Add check fo SEI CERT item ENV32-C

2020-09-17 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 updated this revision to Diff 292416.
gamesh411 marked 2 inline comments as done.
gamesh411 added a comment.

Add abort and terminate handling
Extend tests to cover every exit functions
Extract matcher bind labels


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D83717/new/

https://reviews.llvm.org/D83717

Files:
  clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp
  clang-tools-extra/clang-tidy/cert/CMakeLists.txt
  clang-tools-extra/clang-tidy/cert/ExitHandlerCheck.cpp
  clang-tools-extra/clang-tidy/cert/ExitHandlerCheck.h
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/docs/clang-tidy/checks/cert-env32-c.rst
  clang-tools-extra/docs/clang-tidy/checks/list.rst
  clang-tools-extra/test/clang-tidy/checkers/cert-env32-c-teminate.cpp
  clang-tools-extra/test/clang-tidy/checkers/cert-env32-c.c
  llvm/utils/gn/secondary/clang-tools-extra/clang-tidy/cert/BUILD.gn

Index: llvm/utils/gn/secondary/clang-tools-extra/clang-tidy/cert/BUILD.gn
===
--- llvm/utils/gn/secondary/clang-tools-extra/clang-tidy/cert/BUILD.gn
+++ llvm/utils/gn/secondary/clang-tools-extra/clang-tidy/cert/BUILD.gn
@@ -19,6 +19,7 @@
 "CommandProcessorCheck.cpp",
 "DefaultOperatorNewAlignmentCheck.cpp",
 "DontModifyStdNamespaceCheck.cpp",
+"ExitHandlerCheck.cpp",
 "FloatLoopCounter.cpp",
 "LimitedRandomnessCheck.cpp",
 "MutatingCopyCheck.cpp",
Index: clang-tools-extra/test/clang-tidy/checkers/cert-env32-c.c
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/cert-env32-c.c
@@ -0,0 +1,412 @@
+// Test as a C file.
+// RUN: %check_clang_tidy %s cert-env32-c %t -- -- -DCMODE
+//
+// Test as a C++ file.
+//
+// Test functions in global namespace.
+// RUN: %check_clang_tidy -assume-filename=%s.cpp %s cert-env32-c %t \
+// RUN: -- -- -DCPPMODE
+//
+// Test functions in std namespace.
+// RUN: %check_clang_tidy -assume-filename=%s.cpp %s cert-env32-c %t \
+// RUN: -- -- -DCPPMODE -DTEST_NS_NAME=std
+
+#if defined(CPPMODE) && defined(TEST_NS_NAME)
+namespace TEST_NS_NAME {
+#endif
+
+// --
+// EXIT FUNCTIONS
+// --
+
+// No handlers are invoked when _Exit is called.
+void _Exit(int __status);
+
+// Handlers registered by atexit are invoked in reverse order when exit is
+// called.
+void exit(int __status);
+
+// Handlers registered by at_quick_exit are invoked in reverse order when
+// quick_exit is called.
+void quick_exit(int __status);
+
+// The program is terminated without destroying any object and without calling
+// any of the functions passed to atexit or at_quick_exit.
+void abort();
+
+// 
+// HANDLER REGISTRATION
+// 
+
+// Register handlers to run when exit is called.
+int atexit(void (*__func)(void));
+
+// Register handlers to run when exit is called.
+int at_quick_exit(void (*__func)(void));
+
+// --
+// Setjmp/longjmp
+// --
+// C99 requires jmp_buf to be an array type.
+typedef int jmp_buf[1];
+int setjmp(jmp_buf);
+void longjmp(jmp_buf, int);
+
+// Compliant solutions
+
+void cleanup1() {
+  // do cleanup
+}
+
+void cleanup2() {
+  // do cleanup
+}
+
+void test_atexit_single_compliant() {
+  (void)atexit(cleanup1);
+}
+
+void test_atexit_multiple_compliant() {
+  (void)atexit(cleanup1);
+  (void)atexit(cleanup2);
+}
+
+void test_at_quick_exit_single_compliant() {
+  (void)at_quick_exit(cleanup1);
+}
+
+void test_at_quick_exit_multiple_compliant() {
+  (void)at_quick_exit(cleanup1);
+  (void)at_quick_exit(cleanup2);
+}
+
+// Non-compliant solutions calling _Exit
+
+void call__Exit() {
+  _Exit(0);
+}
+
+void call_call__Exit() {
+  call__Exit();
+}
+
+extern int unknown__Exit_flag;
+
+void call__Exit_conditionally() {
+  if (unknown__Exit_flag)
+call__Exit();
+}
+
+void call_call__Exit_conditionally() {
+  call__Exit_conditionally();
+}
+
+void test__Exit_called_directly() {
+  (void)atexit(call__Exit);
+  // CHECK-NOTES: :[[@LINE-1]]:9: warning: exit-handler potentially calls an exit function. Handlers should terminate by returning [cert-env32-c]
+  // CHECK-NOTES: :[[@LINE-22]]:1: note: handler function declared here
+  // CHECK-NOTES: :[[@LINE-22]]:3: note: exit function called here
+  (void)at_quick_exit(call__Exit);
+  // CHECK-NOTES: :[[@LINE-1]]:9: warning: exit-handler potentially calls an exit function. Handlers should terminate by returning [cert-env32-c]
+  // CHECK-NOTES: :[[@LINE-26]]:1: note: handler function declared here
+  // CHECK-NOTES: :[[@LINE-26]]:3: note: exit function called here
+};
+
+void test__Exit_called_indirectly() {
+  (void)atexit(call_call__Exit);
+  // CHECK-NOTES: :[[@LINE-1]]:9: warning: exit-handler potentially calls an exit function. Handlers should terminate by returning [cert-env32-c]
+  // CHECK-NOTES: :[[@LINE-29]]:1: note: handler function declared here
+  // 

[PATCH] D83717: [clang-tidy] Add check fo SEI CERT item ENV32-C

2020-09-02 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 updated this revision to Diff 289597.
gamesh411 added a comment.

only consider global and ::std scope handlers


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D83717/new/

https://reviews.llvm.org/D83717

Files:
  clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp
  clang-tools-extra/clang-tidy/cert/CMakeLists.txt
  clang-tools-extra/clang-tidy/cert/ExitHandlerCheck.cpp
  clang-tools-extra/clang-tidy/cert/ExitHandlerCheck.h
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/docs/clang-tidy/checks/cert-env32-c.rst
  clang-tools-extra/docs/clang-tidy/checks/list.rst
  clang-tools-extra/test/clang-tidy/checkers/cert-env32-c.c
  llvm/utils/gn/secondary/clang-tools-extra/clang-tidy/cert/BUILD.gn

Index: llvm/utils/gn/secondary/clang-tools-extra/clang-tidy/cert/BUILD.gn
===
--- llvm/utils/gn/secondary/clang-tools-extra/clang-tidy/cert/BUILD.gn
+++ llvm/utils/gn/secondary/clang-tools-extra/clang-tidy/cert/BUILD.gn
@@ -19,6 +19,7 @@
 "CommandProcessorCheck.cpp",
 "DefaultOperatorNewAlignmentCheck.cpp",
 "DontModifyStdNamespaceCheck.cpp",
+"ExitHandlerCheck.cpp",
 "FloatLoopCounter.cpp",
 "LimitedRandomnessCheck.cpp",
 "MutatingCopyCheck.cpp",
Index: clang-tools-extra/test/clang-tidy/checkers/cert-env32-c.c
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/cert-env32-c.c
@@ -0,0 +1,324 @@
+// RUN: %check_clang_tidy %s cert-env32-c %t
+
+// --
+// EXIT FUNCTIONS
+// --
+
+// No handlers are invoked when _Exit is called.
+void _Exit(int __status);
+
+// Handlers registered by atexit are invoked in reverse order when exit is
+// called.
+void exit(int __status);
+
+// Handlers registered by at_quick_exit are invoked in reverse order when
+// quick_exit is called.
+void quick_exit(int __status);
+
+// 
+// HANDLER REGISTRATION
+// 
+
+// Register handlers to run when exit is called.
+int atexit(void (*__func)(void));
+
+// Register handlers to run when exit is called.
+int at_quick_exit(void (*__func)(void));
+
+// --
+// Setjmp/longjmp
+// --
+// C99 requires jmp_buf to be an array type.
+typedef int jmp_buf[1];
+int setjmp(jmp_buf);
+void longjmp(jmp_buf, int);
+
+// Compliant solutions
+
+void cleanup1() {
+  // do cleanup
+}
+
+void cleanup2() {
+  // do cleanup
+}
+
+void test_atexit_single_compliant() {
+  (void)atexit(cleanup1);
+}
+
+void test_atexit_multiple_compliant() {
+  (void)atexit(cleanup1);
+  (void)atexit(cleanup2);
+}
+
+void test_at_quick_exit_single_compliant() {
+  (void)at_quick_exit(cleanup1);
+}
+
+void test_at_quick_exit_multiple_compliant() {
+  (void)at_quick_exit(cleanup1);
+  (void)at_quick_exit(cleanup2);
+}
+
+// Non-compliant solutions calling _Exit
+
+void call__Exit() {
+  _Exit(0);
+}
+
+void call_call__Exit() {
+  call__Exit();
+}
+
+extern int unknown__Exit_flag;
+
+void call__Exit_conditionally() {
+  if (unknown__Exit_flag)
+call__Exit();
+}
+
+void call_call__Exit_conditionally() {
+  call__Exit_conditionally();
+}
+
+void test__Exit_called_directly() {
+  (void)atexit(call__Exit);
+  // CHECK-NOTES: :[[@LINE-1]]:9: warning: exit-handler potentially calls an exit function. Handlers should terminate by returning [cert-env32-c]
+  // CHECK-NOTES: :[[@LINE-22]]:1: note: handler function declared here
+  // CHECK-NOTES: :[[@LINE-22]]:3: note: exit function called here
+  (void)at_quick_exit(call__Exit);
+  // CHECK-NOTES: :[[@LINE-1]]:9: warning: exit-handler potentially calls an exit function. Handlers should terminate by returning [cert-env32-c]
+  // CHECK-NOTES: :[[@LINE-26]]:1: note: handler function declared here
+  // CHECK-NOTES: :[[@LINE-26]]:3: note: exit function called here
+};
+
+void test__Exit_called_indirectly() {
+  (void)atexit(call_call__Exit);
+  // CHECK-NOTES: :[[@LINE-1]]:9: warning: exit-handler potentially calls an exit function. Handlers should terminate by returning [cert-env32-c]
+  // CHECK-NOTES: :[[@LINE-29]]:1: note: handler function declared here
+  // CHECK-NOTES: :[[@LINE-33]]:3: note: exit function called here
+  (void)at_quick_exit(call_call__Exit);
+  // CHECK-NOTES: :[[@LINE-1]]:9: warning: exit-handler potentially calls an exit function. Handlers should terminate by returning [cert-env32-c]
+  // CHECK-NOTES: :[[@LINE-33]]:1: note: handler function declared here
+  // CHECK-NOTES: :[[@LINE-37]]:3: note: exit function called here
+};
+
+void test_conditional__Exit_called_directly() {
+  (void)atexit(call__Exit_conditionally);
+  // CHECK-NOTES: :[[@LINE-1]]:9: warning: exit-handler potentially calls an exit function. Handlers should terminate by returning [cert-env32-c]
+  // CHECK-NOTES: :[[@LINE-34]]:1: note: handler function declared here
+  // CHECK-NOTES: :[[@LINE-44]]:3: note: exit function called here
+  

[PATCH] D85424: [Analyzer] Crash fix for alpha.cplusplus.IteratorRange

2020-08-31 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 added a comment.

`CReduce` did not manage to produce any meaningful result after a week worth of 
runtime (more than ~2000 lines of code still remaining after reduction). We 
could track this down by tracing the ExprEngine code that assigns the Undefined 
SVal but that seems a huge effort as well. That could be done by debugging the 
SVal-assigning statements, and setting conditional breakpoints (ie. only break 
when the value is Undefined). When a breakpoint is hit, we could dump the 
statement that triggered it and try to reason about the conditions at that 
point. I also recommend using the `rr` tool as it allows you to use fixed 
pointer values while debugging.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D85424/new/

https://reviews.llvm.org/D85424

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


[PATCH] D77229: [Analyzer] Avoid handling of LazyCompundVals in IteratorModeling

2020-08-14 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 accepted this revision.
gamesh411 added a comment.
This revision is now accepted and ready to land.

Thanks! LGTM now.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D77229/new/

https://reviews.llvm.org/D77229

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


[PATCH] D77229: [Analyzer] Avoid handling of LazyCompundVals in IteratorModeling

2020-08-13 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 added a comment.

Aside  from infrastructural questions which I am not qualified ( nor 
particularly knowledgeable :3 ) to address, this looks good to me.




Comment at: clang/lib/StaticAnalyzer/Checkers/STLAlgorithmModeling.cpp:77
 
+  unsigned ArgNum = 999;
+

999 seems a bit arbitrary here, consider using 
std::numeric_limits::max(), or llvm::Optional.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D77229/new/

https://reviews.llvm.org/D77229

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


[PATCH] D85728: [Analyzer] Support for the new variadic isa<> and isa_and_not_null<> in CastValueChecker

2020-08-12 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 added inline comments.



Comment at: clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp:265
+  SmallVector CastToTyVec;
+  for (unsigned idx = 0; idx < FD->getTemplateSpecializationArgs()->size() - 1;
+   ++idx) {

Do we intentionally skip the last arg with this loop boundary, or is the loop 
variable just off-by-one?


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D85728/new/

https://reviews.llvm.org/D85728

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


[PATCH] D83717: [clang-tidy] Add check fo SEI CERT item ENV32-C

2020-08-04 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 updated this revision to Diff 282837.
gamesh411 marked an inline comment as done.
gamesh411 added a comment.

rename file name in header


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D83717/new/

https://reviews.llvm.org/D83717

Files:
  clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp
  clang-tools-extra/clang-tidy/cert/CMakeLists.txt
  clang-tools-extra/clang-tidy/cert/ExitHandlerCheck.cpp
  clang-tools-extra/clang-tidy/cert/ExitHandlerCheck.h
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/docs/clang-tidy/checks/cert-env32-c.rst
  clang-tools-extra/docs/clang-tidy/checks/list.rst
  clang-tools-extra/test/clang-tidy/checkers/cert-env32-c.c
  llvm/utils/gn/secondary/clang-tools-extra/clang-tidy/cert/BUILD.gn

Index: llvm/utils/gn/secondary/clang-tools-extra/clang-tidy/cert/BUILD.gn
===
--- llvm/utils/gn/secondary/clang-tools-extra/clang-tidy/cert/BUILD.gn
+++ llvm/utils/gn/secondary/clang-tools-extra/clang-tidy/cert/BUILD.gn
@@ -19,6 +19,7 @@
 "CommandProcessorCheck.cpp",
 "DefaultOperatorNewAlignmentCheck.cpp",
 "DontModifyStdNamespaceCheck.cpp",
+"ExitHandlerCheck.cpp",
 "FloatLoopCounter.cpp",
 "LimitedRandomnessCheck.cpp",
 "MutatingCopyCheck.cpp",
Index: clang-tools-extra/test/clang-tidy/checkers/cert-env32-c.c
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/cert-env32-c.c
@@ -0,0 +1,324 @@
+// RUN: %check_clang_tidy %s cert-env32-c %t
+
+// --
+// EXIT FUNCTIONS
+// --
+
+// No handlers are invoked when _Exit is called.
+void _Exit(int __status);
+
+// Handlers registered by atexit are invoked in reverse order when exit is
+// called.
+void exit(int __status);
+
+// Handlers registered by at_quick_exit are invoked in reverse order when
+// quick_exit is called.
+void quick_exit(int __status);
+
+// 
+// HANDLER REGISTRATION
+// 
+
+// Register handlers to run when exit is called.
+int atexit(void (*__func)(void));
+
+// Register handlers to run when exit is called.
+int at_quick_exit(void (*__func)(void));
+
+// --
+// Setjmp/longjmp
+// --
+// C99 requires jmp_buf to be an array type.
+typedef int jmp_buf[1];
+int setjmp(jmp_buf);
+void longjmp(jmp_buf, int);
+
+// Compliant solutions
+
+void cleanup1() {
+  // do cleanup
+}
+
+void cleanup2() {
+  // do cleanup
+}
+
+void test_atexit_single_compliant() {
+  (void)atexit(cleanup1);
+}
+
+void test_atexit_multiple_compliant() {
+  (void)atexit(cleanup1);
+  (void)atexit(cleanup2);
+}
+
+void test_at_quick_exit_single_compliant() {
+  (void)at_quick_exit(cleanup1);
+}
+
+void test_at_quick_exit_multiple_compliant() {
+  (void)at_quick_exit(cleanup1);
+  (void)at_quick_exit(cleanup2);
+}
+
+// Non-compliant solutions calling _Exit
+
+void call__Exit() {
+  _Exit(0);
+}
+
+void call_call__Exit() {
+  call__Exit();
+}
+
+extern int unknown__Exit_flag;
+
+void call__Exit_conditionally() {
+  if (unknown__Exit_flag)
+call__Exit();
+}
+
+void call_call__Exit_conditionally() {
+  call__Exit_conditionally();
+}
+
+void test__Exit_called_directly() {
+  (void)atexit(call__Exit);
+  // CHECK-NOTES: :[[@LINE-1]]:9: warning: exit-handler potentially calls an exit function. Handlers should terminate by returning [cert-env32-c]
+  // CHECK-NOTES: :[[@LINE-22]]:1: note: handler function declared here
+  // CHECK-NOTES: :[[@LINE-22]]:3: note: exit function called here
+  (void)at_quick_exit(call__Exit);
+  // CHECK-NOTES: :[[@LINE-1]]:9: warning: exit-handler potentially calls an exit function. Handlers should terminate by returning [cert-env32-c]
+  // CHECK-NOTES: :[[@LINE-26]]:1: note: handler function declared here
+  // CHECK-NOTES: :[[@LINE-26]]:3: note: exit function called here
+};
+
+void test__Exit_called_indirectly() {
+  (void)atexit(call_call__Exit);
+  // CHECK-NOTES: :[[@LINE-1]]:9: warning: exit-handler potentially calls an exit function. Handlers should terminate by returning [cert-env32-c]
+  // CHECK-NOTES: :[[@LINE-29]]:1: note: handler function declared here
+  // CHECK-NOTES: :[[@LINE-33]]:3: note: exit function called here
+  (void)at_quick_exit(call_call__Exit);
+  // CHECK-NOTES: :[[@LINE-1]]:9: warning: exit-handler potentially calls an exit function. Handlers should terminate by returning [cert-env32-c]
+  // CHECK-NOTES: :[[@LINE-33]]:1: note: handler function declared here
+  // CHECK-NOTES: :[[@LINE-37]]:3: note: exit function called here
+};
+
+void test_conditional__Exit_called_directly() {
+  (void)atexit(call__Exit_conditionally);
+  // CHECK-NOTES: :[[@LINE-1]]:9: warning: exit-handler potentially calls an exit function. Handlers should terminate by returning [cert-env32-c]
+  // CHECK-NOTES: :[[@LINE-34]]:1: note: handler function declared here
+  // CHECK-NOTES: :[[@LINE-44]]:3: note: exit 

[PATCH] D83190: [analyzer] Model iterator random incrementation symmetrically

2020-08-04 Thread Endre Fülöp via Phabricator via cfe-commits
This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rG141cb8a1eecc: [analyzer] Model iterator random 
incrementation symmetrically (authored by gamesh411).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D83190/new/

https://reviews.llvm.org/D83190

Files:
  clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp
  clang/test/Analysis/iterator-modeling.cpp

Index: clang/test/Analysis/iterator-modeling.cpp
===
--- clang/test/Analysis/iterator-modeling.cpp
+++ clang/test/Analysis/iterator-modeling.cpp
@@ -149,7 +149,7 @@
   clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning-re {{$v.end(){{$
 }
 
-void plus(const std::vector ) {
+void plus_lhs(const std::vector ) {
   auto i1 = v.begin();
 
   clang_analyzer_denote(clang_analyzer_container_begin(v), "$v.begin()");
@@ -161,7 +161,19 @@
   clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning-re{{$v.begin() + 2{{$
 }
 
-void plus_negative(const std::vector ) {
+void plus_rhs(const std::vector ) {
+  auto i1 = v.begin();
+
+  clang_analyzer_denote(clang_analyzer_container_begin(v), "$v.begin()");
+
+  auto i2 = 2 + i1;
+
+  clang_analyzer_eval(clang_analyzer_iterator_container(i2) == ); // expected-warning{{TRUE}}
+  clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning-re{{$v.begin(){{$
+  clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning-re{{$v.begin() + 2{{$
+}
+
+void plus_lhs_negative(const std::vector ) {
   auto i1 = v.end();
 
   clang_analyzer_denote(clang_analyzer_container_end(v), "$v.end()");
@@ -173,6 +185,18 @@
   clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning-re {{$v.end() - 2{{$
 }
 
+void plus_rhs_negative(const std::vector ) {
+  auto i1 = v.end();
+
+  clang_analyzer_denote(clang_analyzer_container_end(v), "$v.end()");
+
+  auto i2 = (-2) + i1;
+
+  clang_analyzer_eval(clang_analyzer_iterator_container(i2) == ); // expected-warning{{TRUE}}
+  clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning-re {{$v.end(){{$
+  clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning-re {{$v.end() - 2{{$
+}
+
 void minus(const std::vector ) {
   auto i1 = v.end();
 
@@ -1955,7 +1979,7 @@
   i -= n; // no-crash
 }
 
-void plus_ptr_iterator(const cont_with_ptr_iterator ) {
+void plus_lhs_ptr_iterator(const cont_with_ptr_iterator ) {
   auto i1 = c.begin();
 
   clang_analyzer_denote(clang_analyzer_container_begin(c), "$c.begin()");
@@ -1967,6 +1991,18 @@
   clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning{{$c.begin() + 2}}
 }
 
+void plus_rhs_ptr_iterator(const cont_with_ptr_iterator ) {
+  auto i1 = c.begin();
+
+  clang_analyzer_denote(clang_analyzer_container_begin(c), "$c.begin()");
+
+  auto i2 = 2 + i1;
+
+  clang_analyzer_eval(clang_analyzer_iterator_container(i2) == ); // expected-warning{{TRUE}}
+  clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$c.begin()}}
+  clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning{{$c.begin() + 2}}
+}
+
 void minus_ptr_iterator(const cont_with_ptr_iterator ) {
   auto i1 = c.end();
 
Index: clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp
@@ -109,7 +109,7 @@
bool Postfix) const;
   void handleRandomIncrOrDecr(CheckerContext , const Expr *CE,
   OverloadedOperatorKind Op, const SVal ,
-  const SVal , const SVal ) const;
+  const SVal , const SVal ) const;
   void handlePtrIncrOrDecr(CheckerContext , const Expr *Iterator,
OverloadedOperatorKind OK, SVal Offset) const;
   void handleAdvance(CheckerContext , const Expr *CE, SVal RetVal, SVal Iter,
@@ -262,20 +262,30 @@
 
 void IteratorModeling::checkPostStmt(const BinaryOperator *BO,
  CheckerContext ) const {
-  ProgramStateRef State = C.getState();
-  BinaryOperatorKind OK = BO->getOpcode();
-  SVal RVal = State->getSVal(BO->getRHS(), C.getLocationContext());
+  const ProgramStateRef State = C.getState();
+  const BinaryOperatorKind OK = BO->getOpcode();
+  const Expr *const LHS = BO->getLHS();
+  const Expr *const RHS = BO->getRHS();
+  const SVal LVal = State->getSVal(LHS, C.getLocationContext());
+  const SVal RVal = State->getSVal(RHS, C.getLocationContext());
 
   if (isSimpleComparisonOperator(BO->getOpcode())) {
-SVal LVal = 

[PATCH] D84520: [Analyzer] Improve invalid dereference bug reporting in DereferenceChecker.

2020-08-04 Thread Endre Fülöp via Phabricator via cfe-commits
gamesh411 added a comment.

I would add one more test for the undefined case. Like a local array variable 
that is uninitialized. That could mirror some of the null-dereference cases.




Comment at: clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp:135
+DerefKindStr = "dereference of an undefined pointer value";
+break;
+  };

balazske wrote:
> Add "results in a " here?
IMHO I would add the "results in a " part here, as this is part of the process 
of creating the diagnostic anyway.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D84520/new/

https://reviews.llvm.org/D84520

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


  1   2   3   >