summaryrefslogtreecommitdiff
path: root/clang/test/Analysis/string.c
diff options
context:
space:
mode:
Diffstat (limited to 'clang/test/Analysis/string.c')
-rw-r--r--clang/test/Analysis/string.c104
1 files changed, 104 insertions, 0 deletions
diff --git a/clang/test/Analysis/string.c b/clang/test/Analysis/string.c
index e017aff3b4a1..cdd36275568e 100644
--- a/clang/test/Analysis/string.c
+++ b/clang/test/Analysis/string.c
@@ -1789,3 +1789,107 @@ void CWE124_Buffer_Underwrite__malloc_char_memcpy() {
free(dataBuffer);
}
#endif
+
+//===----------------------------------------------------------------------===
+// strxfrm()
+// It is not a built-in.
+//===----------------------------------------------------------------------===
+
+size_t strxfrm(char *dest, const char *src, size_t n);
+
+void strxfrm_null_dest(const char *src) {
+ strxfrm(NULL, src, 0); // no warning
+ strxfrm(NULL, src, 10); // expected-warning {{Null pointer passed as 1st argument}}
+}
+
+void strxfrm_null_source(char *dest) {
+ strxfrm(dest, NULL, 0); // expected-warning {{Null pointer passed as 2nd argument}}
+}
+
+#ifndef SUPPRESS_OUT_OF_BOUND
+void strxfrm_overflow(const char *src) {
+ char dest[10];
+ strxfrm(dest, src, 55); // expected-warning {{Locale transformation function overflows the destination buffer}}
+}
+#endif
+
+void strxfrm_source_smaller() {
+ char dest[10];
+ char source[5];
+ strxfrm(dest, source, 10);
+}
+
+void strxfrm_overlap(char *dest) {
+ strxfrm(dest, dest, 10); // expected-warning {{Arguments must not be overlapping buffers}}
+}
+
+void strxfrm_regular(const char *src) {
+ size_t n = strxfrm(NULL, src, 0);
+ char *dest = (char*)malloc(n + 1);
+ strxfrm(dest, src, n);
+ free(dest);
+}
+
+void clang_analyzer_warnIfReached();
+
+int strxfrm_dest_undef(const char *src, int oracle) {
+ char dest[5] = {0};
+ clang_analyzer_eval(dest[0] == 0); // expected-warning {{TRUE}}
+
+ size_t n = strxfrm(dest, src, sizeof(dest));
+
+ if (oracle >= sizeof(dest) || oracle < 0) {
+ return 0;
+ }
+
+ int c = 0;
+ if (n >= sizeof(dest)) {
+ // Since accessing uninitialized sinks the execution, use this trick to check all positions
+ switch (oracle) {
+ case 0:
+ c = dest[0]; // expected-warning {{Assigned value is uninitialized}}
+ break;
+ case 1:
+ c = dest[1]; // expected-warning {{Assigned value is uninitialized}}
+ break;
+ case 2:
+ c = dest[2]; // expected-warning {{Assigned value is uninitialized}}
+ break;
+ case 3:
+ c = dest[3]; // expected-warning {{Assigned value is uninitialized}}
+ break;
+ case 4:
+ c = dest[4]; // expected-warning {{Assigned value is uninitialized}}
+ break;
+ default:
+ clang_analyzer_warnIfReached();
+ }
+ } else {
+ clang_analyzer_eval(n >= 0); // expected-warning {{TRUE}}
+ clang_analyzer_eval(dest[0] == 0); // expected-warning {{UNKNOWN}}
+ clang_analyzer_eval(dest[1] == 0); // expected-warning {{UNKNOWN}}
+ clang_analyzer_eval(dest[2] == 0); // expected-warning {{UNKNOWN}}
+ clang_analyzer_eval(dest[3] == 0); // expected-warning {{UNKNOWN}}
+ clang_analyzer_eval(dest[4] == 0); // expected-warning {{UNKNOWN}}
+ }
+ return c;
+}
+
+int strxfrm_unknown_dest_undef(const char *src, int oracle) {
+ size_t n = strlen(src);
+
+ char *dest = (char*)malloc(n * 2);
+
+ size_t n2 = strxfrm(dest, src, n);
+
+ int c = 0;
+
+ if (n2 < n) {
+ c += dest[50];
+ } else {
+ c += dest[50]; // expected-warning {{Assigned value is uninitialized}}
+ }
+
+ free(dest);
+ return c;
+}