Skip to content

Commit

Permalink
[clang][analyzer] Improve bug reports of StdLibraryFunctionsChecker.
Browse files Browse the repository at this point in the history
Add an additional explanation of what is wrong if a constraint is
not satisfied, in some cases.
Additionally the bug report generation is changed to use raw_ostream.

Reviewed By: Szelethus, NoQ

Differential Revision: https://reviews.llvm.org/D144003
  • Loading branch information
balazske committed Apr 12, 2023
1 parent ac02bf6 commit ce1fb03
Show file tree
Hide file tree
Showing 8 changed files with 351 additions and 222 deletions.
336 changes: 207 additions & 129 deletions clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp

Large diffs are not rendered by default.

Expand Up @@ -19,7 +19,7 @@ int clang_analyzer_getExtent(void *);
// Check NotNullConstraint assumption notes.
int __not_null(int *);
int test_not_null_note(int *x, int y) {
__not_null(x); // expected-note{{Assuming the 1st argument to '__not_null' is not NULL}}
__not_null(x); // expected-note{{Assuming that the 1st argument to '__not_null' is not NULL}}
if (x) // expected-note{{'x' is non-null}} \
// expected-note{{Taking true branch}}
if (!y) // expected-note{{Assuming 'y' is 0}} \
Expand All @@ -33,15 +33,15 @@ int test_not_null_note(int *x, int y) {
// Check the RangeConstraint assumption notes.
int __single_val_0(int); // [0, 0]
int test_range_constraint_note(int x, int y) {
__single_val_0(x); // expected-note{{Assuming the 1st argument to '__single_val_0' is zero}}
__single_val_0(x); // expected-note{{Assuming that the 1st argument to '__single_val_0' is zero}}
return y / x; // expected-warning{{Division by zero}} \
// expected-note{{Division by zero}}
}

// Check the BufferSizeConstraint assumption notes.
int __buf_size_arg_constraint_concrete(const void *buf); // size of buf must be >= 10
void test_buffer_size_note(char *buf, int y) {
__buf_size_arg_constraint_concrete(buf); // expected-note {{Assuming the size of the 1st argument to '__buf_size_arg_constraint_concrete' is equal to or greater than 10}}
__buf_size_arg_constraint_concrete(buf); // expected-note {{Assuming that the 1st argument to '__buf_size_arg_constraint_concrete' is a buffer with size equal to or greater than 10}}
clang_analyzer_eval(clang_analyzer_getExtent(buf) >= 10); // expected-warning{{TRUE}} \
// expected-note{{TRUE}}

Expand Down
117 changes: 84 additions & 33 deletions clang/test/Analysis/std-c-library-functions-arg-constraints-notes.cpp
Expand Up @@ -15,7 +15,7 @@
int __not_null(int *);
void test_not_null(int *x) {
__not_null(nullptr); // \
// expected-warning{{The 1st argument to '__not_null' should not be NULL}}
// expected-warning{{The 1st argument to '__not_null' is NULL but should not be NULL [}}
}

// Check the BufferSizeConstraint violation notes.
Expand All @@ -28,19 +28,19 @@ void test_buffer_size(int x) {
case 1: {
char buf[9];
__buf_size_arg_constraint_concrete(buf); // \
// expected-warning{{The size of the 1st argument to '__buf_size_arg_constraint_concrete' should be equal to or greater than 10}}
// expected-warning{{The 1st argument to '__buf_size_arg_constraint_concrete' is out of the accepted range; It should be a buffer with size equal to or greater than 10 [}}
break;
}
case 2: {
char buf[3];
__buf_size_arg_constraint(buf, 4); // \
// expected-warning{{The size of the 1st argument to '__buf_size_arg_constraint' should be equal to or greater than the value of the 2nd argument}}
// expected-warning{{The 1st argument to '__buf_size_arg_constraint' is out of the accepted range; It should be a buffer with size equal to or greater than the value of the 2nd argument}}
break;
}
case 3: {
char buf[3];
__buf_size_arg_constraint_mul(buf, 4, 2); // \
// expected-warning{{The size of the 1st argument to '__buf_size_arg_constraint_mul' should be equal to or greater than the value of the 2nd argument times the 3rd argument}}
// expected-warning{{The 1st argument to '__buf_size_arg_constraint_mul' is out of the accepted range; It should be a buffer with size equal to or greater than the value of the 2nd argument times the 3rd argument}}
break;
}
}
Expand Down Expand Up @@ -78,109 +78,160 @@ int __range_out_minf_1(int); // [-inf, 1]
int __range_out_1_2__4_6(int); // [1, 2], [4, 6]
int __range_out_1_2__4_inf(int); // [1, 2], [4, inf]

int __test_case_range_1_2__4_6(int);

void test_range_values(int x) {
switch (x) {
case 0:
__single_val_0(1); // expected-warning{{should be zero}}
__single_val_0(1); // expected-warning{{is 1 but should be zero}}
break;
case 1:
__single_val_1(2); // expected-warning{{should be 1}}
__single_val_1(2); // expected-warning{{is 2 but should be 1}}
break;
case 2:
__range_1_2(3); // expected-warning{{should be 1 or 2}}
__range_1_2(3); // expected-warning{{is 3 but should be 1 or 2}}
break;
case 3:
__range_m1_1(3); // expected-warning{{should be between -1 and 1}}
__range_m1_1(3); // expected-warning{{is 3 but should be between -1 and 1}}
break;
case 4:
__range_m2_m1(1); // expected-warning{{should be -2 or -1}}
__range_m2_m1(1); // expected-warning{{is 1 but should be -2 or -1}}
break;
case 5:
__range_m10_10(11); // expected-warning{{should be between -10 and 10}}
__range_m10_10(11); // expected-warning{{is 11 but should be between -10 and 10}}
break;
case 6:
__range_m10_10(-11); // expected-warning{{should be between -10 and 10}}
__range_m10_10(-11); // expected-warning{{is -11 but should be between -10 and 10}}
break;
case 7:
__range_1_2__4_6(3); // expected-warning{{should be 1 or 2 or 4, 5 or 6}}
__range_1_2__4_6(3); // expected-warning{{is 3 but should be 1 or 2 or between 4 and 6}}
break;
case 8:
__range_1_2__4_inf(3); // expected-warning{{should be 1 or 2 or >= 4}}
__range_1_2__4_inf(3); // expected-warning{{is 3 but should be 1 or 2 or >= 4}}
break;
}
}

void test_range_values_inf(int x) {
switch (x) {
case 1:
__range_m1_inf(-2); // expected-warning{{should be >= -1}}
__range_m1_inf(-2); // expected-warning{{is -2 but should be >= -1}}
break;
case 2:
__range_0_inf(-1); // expected-warning{{should be >= 0}}
__range_0_inf(-1); // expected-warning{{is -1 but should be >= 0}}
break;
case 3:
__range_1_inf(0); // expected-warning{{should be > 0}}
__range_1_inf(0); // expected-warning{{is 0 but should be > 0}}
break;
case 4:
__range_minf_m1(0); // expected-warning{{should be < 0}}
__range_minf_m1(0); // expected-warning{{is 0 but should be < 0}}
break;
case 5:
__range_minf_0(1); // expected-warning{{should be <= 0}}
__range_minf_0(1); // expected-warning{{is 1 but should be <= 0}}
break;
case 6:
__range_minf_1(2); // expected-warning{{should be <= 1}}
__range_minf_1(2); // expected-warning{{is 2 but should be <= 1}}
break;
}
}

void test_range_values_out(int x) {
switch (x) {
case 0:
__single_val_out_0(0); // expected-warning{{should be nonzero}}
__single_val_out_0(0); // expected-warning{{is 0 but should be nonzero}}
break;
case 1:
__single_val_out_1(1); // expected-warning{{should be not equal to 1}}
__single_val_out_1(1); // expected-warning{{is 1 but should be not equal to 1}}
break;
case 2:
__range_out_1_2(2); // expected-warning{{should be not 1 and not 2}}
__range_out_1_2(2); // expected-warning{{is 2 but should be not 1 and not 2}}
break;
case 3:
__range_out_m1_1(-1); // expected-warning{{should be not between -1 and 1}}
__range_out_m1_1(-1); // expected-warning{{is -1 but should be not between -1 and 1}}
break;
case 4:
__range_out_m2_m1(-2); // expected-warning{{should be not -2 and not -1}}
__range_out_m2_m1(-2); // expected-warning{{is -2 but should be not -2 and not -1}}
break;
case 5:
__range_out_m10_10(0); // expected-warning{{should be not between -10 and 10}}
__range_out_m10_10(0); // expected-warning{{is 0 but should be not between -10 and 10}}
break;
case 6:
__range_out_1_2__4_6(1); // expected-warning{{should be not 1 and not 2 and not between 4 and 6}}
__range_out_1_2__4_6(1); // expected-warning{{is 1 but should be not 1 and not 2 and not between 4 and 6}}
break;
case 7:
__range_out_1_2__4_inf(4); // expected-warning{{should be not 1 and not 2 and < 4}}
__range_out_1_2__4_inf(4); // expected-warning{{is 4 but should be not 1 and not 2 and < 4}}
break;
}
}

void test_range_values_out_inf(int x) {
switch (x) {
case 1:
__range_out_minf_m1(-1); // expected-warning{{should be >= 0}}
__range_out_minf_m1(-1); // expected-warning{{is -1 but should be >= 0}}
break;
case 2:
__range_out_minf_0(0); // expected-warning{{should be > 0}}
__range_out_minf_0(0); // expected-warning{{is 0 but should be > 0}}
break;
case 3:
__range_out_minf_1(1); // expected-warning{{should be > 1}}
__range_out_minf_1(1); // expected-warning{{is 1 but should be > 1}}
break;
case 4:
__range_out_m1_inf(-1); // expected-warning{{should be < -1}}
__range_out_m1_inf(-1); // expected-warning{{is -1 but should be < -1}}
break;
case 5:
__range_out_0_inf(0); // expected-warning{{should be < 0}}
__range_out_0_inf(0); // expected-warning{{is 0 but should be < 0}}
break;
case 6:
__range_out_1_inf(1); // expected-warning{{should be <= 0}}
__range_out_1_inf(1); // expected-warning{{is 1 but should be <= 0}}
break;
}
}

void test_explanation(int x, int y) {
switch (y) {
case 1:
if (x > 0)
__single_val_0(x); // expected-warning{{is > 0 but should be zero [}}
return;
case 2:
if (x < 0)
__single_val_0(x); // expected-warning{{is < 0 but should be zero [}}
return;
case 3:
if (x < -1)
__single_val_0(x); // expected-warning{{is < 0 but should be zero [}}
return;
case 4:
if (x != 0)
__single_val_0(x); // expected-warning{{is out of the accepted range; It should be zero [}}
return;
case 5:
if (x == 3)
__range_1_2__4_6(x); // expected-warning{{is 3 but should be 1 or 2 or between 4 and 6 [}}
return;
case 6:
if (x > 6)
__range_1_2__4_6(x); // expected-warning{{is >= 7 but should be 1 or 2 or between 4 and 6 [}}
return;
case 7:
if (x < 1)
__range_1_2__4_6(x); // expected-warning{{is <= 0 but should be 1 or 2 or between 4 and 6 [}}
return;
case 8:
if (__test_case_range_1_2__4_6(x) == 1)
__range_1_2__4_6(x); // expected-warning{{is 3 or <= 0 but should be 1 or 2 or between 4 and 6 [}}
return;
case 9:
if (__test_case_range_1_2__4_6(x) == 2)
__range_1_2__4_6(x); // expected-warning{{is 3 or >= 7 but should be 1 or 2 or between 4 and 6 [}}
return;
case 10:
if (__test_case_range_1_2__4_6(x) == 3)
__range_1_2__4_6(x); // expected-warning{{is <= 0 or >= 7 but should be 1 or 2 or between 4 and 6 [}}
return;
case 11:
if (__test_case_range_1_2__4_6(x) == 4)
__range_1_2__4_6(x); // expected-warning{{is out of the accepted range; It should be 1 or 2 or between 4 and 6 [}}
return;
}
}
Expand Up @@ -16,8 +16,8 @@ void test_buf_size_concrete(void) {
char buf[3]; // bugpath-note{{'buf' initialized here}}
int s = 4; // bugpath-note{{'s' initialized to 4}}
__buf_size_arg_constraint(buf, s); // \
// bugpath-warning{{The size of the 1st argument to '__buf_size_arg_constraint' should be equal to or greater than the value of the 2nd argument}} \
// bugpath-note{{The size of the 1st argument to '__buf_size_arg_constraint' should be equal to or greater than the value of the 2nd argument}}
// bugpath-warning{{The 1st argument to '__buf_size_arg_constraint' is out of the accepted range; It should be a buffer with size equal to or greater than the value of the 2nd argument}} \
// bugpath-note{{The 1st argument to '__buf_size_arg_constraint' is out of the accepted range; It should be a buffer with size equal to or greater than the value of the 2nd argument}}
}

int __buf_size_arg_constraint_mul(const void *, size_t, size_t);
Expand All @@ -26,6 +26,6 @@ void test_buf_size_concrete_with_multiplication(void) {
int s1 = 4; // bugpath-note{{'s1' initialized to 4}}
int s2 = sizeof(short); // bugpath-note{{'s2' initialized to}}
__buf_size_arg_constraint_mul(buf, s1, s2); // \
// bugpath-warning{{The size of the 1st argument to '__buf_size_arg_constraint_mul' should be equal to or greater than the value of the 2nd argument times the 3rd argument}} \
// bugpath-note{{The size of the 1st argument to '__buf_size_arg_constraint_mul' should be equal to or greater than the value of the 2nd argument times the 3rd argument}}
// bugpath-warning{{The 1st argument to '__buf_size_arg_constraint_mul' is out of the accepted range; It should be a buffer with size equal to or greater than the value of the 2nd argument times the 3rd argument}} \
// bugpath-note{{The 1st argument to '__buf_size_arg_constraint_mul' is out of the accepted range; It should be a buffer with size equal to or greater than the value of the 2nd argument times the 3rd argument}}
}

0 comments on commit ce1fb03

Please sign in to comment.