Hi,
since the last libsanitizer merge happened, we have new string
interceptors in libasan: strstr, strcasestr, strspn, strcspn and
strpbrk. This patch migrates corresponding tests for them from LLVM.
Also, asan_intercepted_p predicate is updated to handle corresponding
builtin codes.
Regtested and bootstrapped on x86_64-unknown-linux-gnu, OK to apply?
-Maxim
gcc/ChangeLog:
2015-10-28 Maxim Ostapenko <m.ostape...@partner.samsung.com>
* asan.h (asan_intercepted_p): Handle BUILT_IN_STRCSPN,
BUILT_IN_STRPBRK, BUILT_IN_STRSPN and BUILT_IN_STRSTR.
gcc/testsuite/ChangeLog:
2015-10-28 Maxim Ostapenko <m.ostape...@partner.samsung.com>
* c-c++-common/asan/strcasestr-1.c: New test.
* c-c++-common/asan/strcasestr-2.c: Likewise.
* c-c++-common/asan/strcspn-1.c: Likewise.
* c-c++-common/asan/strcspn-2.c: Likewise.
* c-c++-common/asan/strpbrk-1.c: Likewise.
* c-c++-common/asan/strpbrk-2.c: Likewise.
* c-c++-common/asan/strspn-1.c: Likewise.
* c-c++-common/asan/strspn-2.c: Likewise.
* c-c++-common/asan/strstr-1.c: Likewise.
* c-c++-common/asan/strstr-2.c: Likewise.
Index: gcc/asan.h
===================================================================
--- gcc/asan.h (revision 229169)
+++ gcc/asan.h (working copy)
@@ -103,6 +103,10 @@
|| fcode == BUILT_IN_STRNCASECMP
|| fcode == BUILT_IN_STRNCAT
|| fcode == BUILT_IN_STRNCMP
+ || fcode == BUILT_IN_STRCSPN
+ || fcode == BUILT_IN_STRPBRK
+ || fcode == BUILT_IN_STRSPN
+ || fcode == BUILT_IN_STRSTR
|| fcode == BUILT_IN_STRNCPY;
}
#endif /* TREE_ASAN */
Index: gcc/testsuite/c-c++-common/asan/strcasestr-1.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/strcasestr-1.c (revision 0)
+++ gcc/testsuite/c-c++-common/asan/strcasestr-1.c (working copy)
@@ -0,0 +1,29 @@
+/* { dg-do run } */
+/* { dg-set-target-env-var ASAN_OPTIONS "strict_string_checks=true" } */
+/* { dg-shouldfail "asan" } */
+
+#include <assert.h>
+#include <sanitizer/asan_interface.h>
+
+#ifndef __cplusplus
+#define _GNU_SOURCE
+#else
+extern "C"
+#endif
+char *
+strcasestr(const char *haystack, const char *needle);
+
+int main(int argc, char **argv) {
+ char *r = 0;
+ char s2[] = "c";
+ char s1[4] = "abC";
+ __asan_poison_memory_region ((char *)&s1[2], 2);
+ r = strcasestr(s1, s2);
+ assert(r == s1 + 2);
+ return 0;
+}
+
+/* { dg-output "READ of size 4 at .* thread T0.*" } */
+/* { dg-output ".*(main)?.*strcasestr-1.(c:21)?.*" } */
+/* { dg-output "is located in stack of thread T0 at offset.*" } */
+/* { dg-output "\'s1\' <== Memory access at offset \[0-9\]+ partially overflows this variable" } */
Index: gcc/testsuite/c-c++-common/asan/strcasestr-2.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/strcasestr-2.c (revision 0)
+++ gcc/testsuite/c-c++-common/asan/strcasestr-2.c (working copy)
@@ -0,0 +1,30 @@
+/* { dg-do run } */
+/* { dg-set-target-env-var ASAN_OPTIONS "strict_string_checks=true" } */
+/* { dg-shouldfail "asan" } */
+
+#include <assert.h>
+#include <sanitizer/asan_interface.h>
+
+#ifndef __cplusplus
+#define _GNU_SOURCE
+#else
+extern "C"
+#endif
+char *
+strcasestr(const char *haystack, const char *needle);
+
+int main(int argc, char **argv) {
+ char *r = 0;
+ char s1[] = "ab";
+ char s2[4] = "cba";
+ __asan_poison_memory_region ((char *)&s2[2], 2);
+ r = strcasestr(s1, s2);
+ assert(r == 0);
+ return 0;
+}
+
+/* { dg-output "READ of size 4 at .* thread T0.*" } */
+/* { dg-output ".*(main)?.*strcasestr-2.(c:21)?.*" } */
+/* { dg-output "is located in stack of thread T0 at offset.*" } */
+/* { dg-output "\'s2\' <== Memory access at offset \[0-9\]+ partially overflows this variable" } */
Index: gcc/testsuite/c-c++-common/asan/strcspn-1.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/strcspn-1.c (revision 0)
+++ gcc/testsuite/c-c++-common/asan/strcspn-1.c (working copy)
@@ -0,0 +1,26 @@
+/* { dg-do run } */
+/* { dg-set-target-env-var ASAN_OPTIONS "strict_string_checks=true" } */
+/* { dg-shouldfail "asan" } */
+
+#include <assert.h>
+#include <sanitizer/asan_interface.h>
+#ifdef __cplusplus
+extern "C"
+#endif
+__SIZE_TYPE__
+strcspn (const char *s, const char *reject);
+
+int main(int argc, char **argv) {
+ __SIZE_TYPE__ r;
+ char s2[] = "ab";
+ char s1[4] = "caB";
+ __asan_poison_memory_region ((char *)&s1[2], 2);
+ r = strcspn(s1, s2);
+ assert(r == 1);
+ return 0;
+}
+
+/* { dg-output "READ of size 4 at .* thread T0.*" } */
+/* { dg-output ".*(main)?.*strcspn-1.(c:18)?.*" } */
+/* { dg-output "is located in stack of thread T0 at offset.*" } */
+/* { dg-output "\'s1\' <== Memory access at offset \[0-9\]+ partially overflows this variable" } */
Index: gcc/testsuite/c-c++-common/asan/strcspn-2.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/strcspn-2.c (revision 0)
+++ gcc/testsuite/c-c++-common/asan/strcspn-2.c (working copy)
@@ -0,0 +1,26 @@
+/* { dg-do run } */
+/* { dg-set-target-env-var ASAN_OPTIONS "strict_string_checks=true" } */
+/* { dg-shouldfail "asan" } */
+
+#include <assert.h>
+#include <sanitizer/asan_interface.h>
+#ifdef __cplusplus
+extern "C"
+#endif
+__SIZE_TYPE__
+strcspn (const char *s, const char *reject);
+
+int main(int argc, char **argv) {
+ __SIZE_TYPE__ r;
+ char s1[] = "ab";
+ char s2[4] = "abc";
+ __asan_poison_memory_region ((char *)&s2[2], 2);
+ r = strcspn(s1, s2);
+ assert(r == 0);
+ return 0;
+}
+
+/* { dg-output "READ of size 4 at .* thread T0.*" } */
+/* { dg-output ".*(main)?.*strcspn-2.(c:18)?.*" } */
+/* { dg-output "is located in stack of thread T0 at offset.*" } */
+/* { dg-output "\'s2\' <== Memory access at offset \[0-9\]+ partially overflows this variable" } */
Index: gcc/testsuite/c-c++-common/asan/strpbrk-1.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/strpbrk-1.c (revision 0)
+++ gcc/testsuite/c-c++-common/asan/strpbrk-1.c (working copy)
@@ -0,0 +1,26 @@
+/* { dg-do run } */
+/* { dg-set-target-env-var ASAN_OPTIONS "strict_string_checks=true" } */
+/* { dg-shouldfail "asan" } */
+
+#include <assert.h>
+#include <sanitizer/asan_interface.h>
+#ifdef __cplusplus
+extern "C"
+#endif
+char *
+strpbrk(const char *s, const char *accept);
+
+int main(int argc, char **argv) {
+ char *r;
+ char s2[] = "ab";
+ char s1[4] = "cab";
+ __asan_poison_memory_region ((char *)&s1[2], 2);
+ r = strpbrk(s1, s2);
+ assert(r == s1 + 1);
+ return 0;
+}
+
+/* { dg-output "READ of size 4 at .* thread T0.*" } */
+/* { dg-output ".*(main)?.*strpbrk-1.(c:18)?.*" } */
+/* { dg-output "is located in stack of thread T0 at offset.*" } */
+/* { dg-output "\'s1\' <== Memory access at offset \[0-9\]+ partially overflows this variable" } */
Index: gcc/testsuite/c-c++-common/asan/strpbrk-2.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/strpbrk-2.c (revision 0)
+++ gcc/testsuite/c-c++-common/asan/strpbrk-2.c (working copy)
@@ -0,0 +1,26 @@
+/* { dg-do run } */
+/* { dg-set-target-env-var ASAN_OPTIONS "strict_string_checks=true" } */
+/* { dg-shouldfail "asan" } */
+
+#include <assert.h>
+#include <sanitizer/asan_interface.h>
+#ifdef __cplusplus
+extern "C"
+#endif
+char *
+strpbrk(const char *s, const char *accept);
+
+int main(int argc, char **argv) {
+ char *r;
+ char s1[] = "c";
+ char s2[4] = "bca";
+ __asan_poison_memory_region ((char *)&s2[2], 2);
+ r = strpbrk(s1, s2);
+ assert(r == s1);
+ return 0;
+}
+
+/* { dg-output "READ of size 4 at .* thread T0.*" } */
+/* { dg-output ".*(main)?.*strpbrk-2.(c:18)?.*" } */
+/* { dg-output "is located in stack of thread T0 at offset.*" } */
+/* { dg-output "\'s2\' <== Memory access at offset \[0-9\]+ partially overflows this variable" } */
Index: gcc/testsuite/c-c++-common/asan/strspn-1.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/strspn-1.c (revision 0)
+++ gcc/testsuite/c-c++-common/asan/strspn-1.c (working copy)
@@ -0,0 +1,26 @@
+/* { dg-do run } */
+/* { dg-set-target-env-var ASAN_OPTIONS "strict_string_checks=true" } */
+/* { dg-shouldfail "asan" } */
+
+#include <assert.h>
+#include <sanitizer/asan_interface.h>
+#ifdef __cplusplus
+extern "C"
+#endif
+__SIZE_TYPE__
+strspn (const char *s, const char *reject);
+
+int main(int argc, char **argv) {
+ __SIZE_TYPE__ r;
+ char s2[] = "ab";
+ char s1[4] = "acb";
+ __asan_poison_memory_region ((char *)&s1[2], 2);
+ r = strspn(s1, s2);
+ assert(r == 1);
+ return 0;
+}
+
+/* { dg-output "READ of size 4 at .* thread T0.*" } */
+/* { dg-output ".*(main)?.*strspn-1.(c:18)?.*" } */
+/* { dg-output "is located in stack of thread T0 at offset.*" } */
+/* { dg-output "\'s1\' <== Memory access at offset \[0-9\]+ partially overflows this variable" } */
Index: gcc/testsuite/c-c++-common/asan/strspn-2.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/strspn-2.c (revision 0)
+++ gcc/testsuite/c-c++-common/asan/strspn-2.c (working copy)
@@ -0,0 +1,26 @@
+/* { dg-do run } */
+/* { dg-set-target-env-var ASAN_OPTIONS "strict_string_checks=true" } */
+/* { dg-shouldfail "asan" } */
+
+#include <assert.h>
+#include <sanitizer/asan_interface.h>
+#ifdef __cplusplus
+extern "C"
+#endif
+__SIZE_TYPE__
+strspn (const char *s, const char *reject);
+
+int main(int argc, char **argv) {
+ size_t r;
+ char s1[] = "bbc";
+ char s2[5] = "abcd";
+ __asan_poison_memory_region ((char *)&s2[3], 2);
+ r = strspn(s1, s2);
+ assert(r >= 2);
+ return 0;
+}
+
+/* { dg-output "READ of size 5 at .* thread T0.*" } */
+/* { dg-output ".*(main)?.*strspn-2.(c:18)?.*" } */
+/* { dg-output "is located in stack of thread T0 at offset.*" } */
+/* { dg-output "\'s2\' <== Memory access at offset \[0-9\]+ partially overflows this variable" } */
Index: gcc/testsuite/c-c++-common/asan/strstr-1.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/strstr-1.c (revision 0)
+++ gcc/testsuite/c-c++-common/asan/strstr-1.c (working copy)
@@ -0,0 +1,27 @@
+/* { dg-do run } */
+/* { dg-set-target-env-var ASAN_OPTIONS "strict_string_checks=true" } */
+/* { dg-shouldfail "asan" } */
+
+#include <assert.h>
+#include <sanitizer/asan_interface.h>
+
+#ifdef __cplusplus
+extern "C"
+#endif
+char *
+strstr(const char *haystack, const char *needle);
+
+int main(int argc, char **argv) {
+ char *r = 0;
+ char s2[] = "c";
+ char s1[4] = "acb";
+ __asan_poison_memory_region ((char *)&s1[2], 2);
+ r = strstr(s1, s2);
+ assert(r == s1 + 1);
+ return 0;
+}
+
+/* { dg-output "READ of size 4 at .* thread T0.*" } */
+/* { dg-output ".*(main)?.*strstr-1.(c:19)?.*" } */
+/* { dg-output "is located in stack of thread T0 at offset.*" } */
+/* { dg-output "\'s1\' <== Memory access at offset \[0-9\]+ partially overflows this variable" } */
Index: gcc/testsuite/c-c++-common/asan/strstr-2.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/strstr-2.c (revision 0)
+++ gcc/testsuite/c-c++-common/asan/strstr-2.c (working copy)
@@ -0,0 +1,27 @@
+/* { dg-do run } */
+/* { dg-set-target-env-var ASAN_OPTIONS "strict_string_checks=true" } */
+/* { dg-shouldfail "asan" } */
+
+#include <assert.h>
+#include <sanitizer/asan_interface.h>
+
+#ifdef __cplusplus
+extern "C"
+#endif
+char *
+strstr(const char *haystack, const char *needle);
+
+int main(int argc, char **argv) {
+ char *r = 0;
+ char s1[] = "ab";
+ char s2[4] = "cab";
+ __asan_poison_memory_region ((char *)&s2[2], 2);
+ r = strstr(s1, s2);
+ assert(r == 0);
+ return 0;
+}
+
+/* { dg-output "READ of size 4 at .* thread T0.*" } */
+/* { dg-output ".*(main)?.*strstr-2.(c:19)?.*" } */
+/* { dg-output "is located in stack of thread T0 at offset.*" } */
+/* { dg-output "\'s2\' <== Memory access at offset \[0-9\]+ partially overflows this variable" } */