1// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.cstring,debug.ExprInspection -analyzer-store=region -verify %s
2// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -analyzer-checker=core,unix.cstring,debug.ExprInspection -analyzer-store=region -verify %s
3// XFAIL: *
4
5// This file is for tests that may eventually go into string.c, or may be
6// deleted outright. At one point these tests passed, but only because we
7// weren't correctly modelling the behavior of the relevant string functions.
8// The tests aren't incorrect, but require the analyzer to be smarter about
9// conjured values than it currently is.
10
11//===----------------------------------------------------------------------===
12// Declarations
13//===----------------------------------------------------------------------===
14
15// Some functions are so similar to each other that they follow the same code
16// path, such as memcpy and __memcpy_chk, or memcmp and bcmp. If VARIANT is
17// defined, make sure to use the variants instead to make sure they are still
18// checked by the analyzer.
19
20// Some functions are implemented as builtins. These should be #defined as
21// BUILTIN(f), which will prepend "__builtin_" if USE_BUILTINS is defined.
22
23// Functions that have variants and are also available as builtins should be
24// declared carefully! See memcpy() for an example.
25
26#ifdef USE_BUILTINS
27# define BUILTIN(f) __builtin_ ## f
28#else /* USE_BUILTINS */
29# define BUILTIN(f) f
30#endif /* USE_BUILTINS */
31
32#define NULL 0
33typedef typeof(sizeof(int)) size_t;
34
35void clang_analyzer_eval(int);
36
37//===----------------------------------------------------------------------===
38// strnlen()
39//===----------------------------------------------------------------------===
40
41#define strnlen BUILTIN(strnlen)
42size_t strnlen(const char *s, size_t maxlen);
43
44void strnlen_liveness(const char *x) {
45  if (strnlen(x, 10) < 5)
46    return;
47  clang_analyzer_eval(strnlen(x, 10) < 5); // expected-warning{{FALSE}}
48}
49
50void strnlen_subregion() {
51  struct two_stringsn { char a[2], b[2]; };
52  extern void use_two_stringsn(struct two_stringsn *);
53
54  struct two_stringsn z;
55  use_two_stringsn(&z);
56
57  size_t a = strnlen(z.a, 10);
58  z.b[0] = 5;
59  size_t b = strnlen(z.a, 10);
60  if (a == 0)
61    clang_analyzer_eval(b == 0); // expected-warning{{TRUE}}
62
63  use_two_stringsn(&z);
64
65  size_t c = strnlen(z.a, 10);
66  if (a == 0)
67    clang_analyzer_eval(c == 0); // expected-warning{{UNKNOWN}}
68}
69
70extern void use_stringn(char *);
71void strnlen_argument(char *x) {
72  size_t a = strnlen(x, 10);
73  size_t b = strnlen(x, 10);
74  if (a == 0)
75    clang_analyzer_eval(b == 0); // expected-warning{{TRUE}}
76
77  use_stringn(x);
78
79  size_t c = strnlen(x, 10);
80  if (a == 0)
81    clang_analyzer_eval(c == 0); // expected-warning{{UNKNOWN}}
82}
83
84extern char global_strn[];
85void strnlen_global() {
86  size_t a = strnlen(global_strn, 10);
87  size_t b = strnlen(global_strn, 10);
88  if (a == 0)
89    clang_analyzer_eval(b == 0); // expected-warning{{TRUE}}
90
91  // Call a function with unknown effects, which should invalidate globals.
92  use_stringn(0);
93
94  size_t c = strnlen(global_strn, 10);
95  if (a == 0)
96    clang_analyzer_eval(c == 0); // expected-warning{{UNKNOWN}}
97}
98
99void strnlen_indirect(char *x) {
100  size_t a = strnlen(x, 10);
101  char *p = x;
102  char **p2 = &p;
103  size_t b = strnlen(x, 10);
104  if (a == 0)
105    clang_analyzer_eval(b == 0); // expected-warning{{TRUE}}
106
107  extern void use_stringn_ptr(char*const*);
108  use_stringn_ptr(p2);
109
110  size_t c = strnlen(x, 10);
111  if (a == 0)
112    clang_analyzer_eval(c == 0); // expected-warning{{UNKNOWN}}
113}
114