summaryrefslogtreecommitdiff
path: root/gcc/testsuite/gcc.c-torture/execute/memcheck/driver.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/testsuite/gcc.c-torture/execute/memcheck/driver.c')
-rwxr-xr-xgcc/testsuite/gcc.c-torture/execute/memcheck/driver.c272
1 files changed, 272 insertions, 0 deletions
diff --git a/gcc/testsuite/gcc.c-torture/execute/memcheck/driver.c b/gcc/testsuite/gcc.c-torture/execute/memcheck/driver.c
new file mode 100755
index 0000000..1da22e7
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/memcheck/driver.c
@@ -0,0 +1,272 @@
+/* GNU C dependencies:
+ Checker support hooks
+ ISO C 9x array element initialization
+ void-pointer arithmetic */
+
+#include "driver.h"
+
+int verbose = 0;
+int debug = 0;
+int bad_accesses = 0;
+
+const char *const memory_use_strings[] =
+{
+#define INIT(x) [x] = #x
+ INIT (MEMORY_USE_BAD),
+ INIT (MEMORY_USE_DONT),
+ INIT (MEMORY_USE_RO),
+ INIT (MEMORY_USE_RW),
+ INIT (MEMORY_USE_TW),
+ INIT (MEMORY_USE_WO),
+#undef INIT
+};
+
+/* This won't be used for any really huge test cases, so a simple
+ linked list is adequate. We won't even worry about overlapping
+ regions; the matching entry that comes up first wins. */
+const char *const access_mode_strings[] =
+{
+ "none", "ro", "wo", "rw",
+};
+struct access_node
+{
+ struct access_node *next;
+ const void *addr;
+ size_t sz;
+ enum access_mode mode;
+};
+
+static struct access_node *access_list;
+
+void
+mark_region (const void *addr, size_t sz, enum access_mode mode)
+{
+ struct access_node *a;
+ if (debug)
+ printf ("mark_region (%p, %ld, %s)\n", addr, (long) sz,
+ access_mode_strings[mode]);
+ a = malloc (sizeof (struct access_node));
+ a->next = access_list;
+ a->addr = addr;
+ a->sz = sz;
+ a->mode = mode;
+ access_list = a;
+}
+
+void report_bad_access (void *, size_t, enum memory_use_mode) NOCHECK;
+void
+report_bad_access (void *addr, size_t sz, enum memory_use_mode mode)
+{
+ if (++bad_accesses > 100)
+ bad_accesses = 100;
+ if (verbose)
+ {
+ static char x[100];
+ const char *mode_str;
+ if (mode >= 0
+ && mode < sizeof (memory_use_strings) / sizeof (*memory_use_strings)
+ && memory_use_strings[mode] != 0)
+ mode_str = memory_use_strings[mode];
+ else
+ {
+ sprintf (x, "<bad mode %d>", mode);
+ mode_str = x;
+ }
+ printf ("bad access (%p, %ld, %s)\n", addr, (long) sz, mode_str);
+ }
+}
+
+int verify1 (void *, size_t, enum access_mode, struct access_node *) NOCHECK;
+int
+verify1 (void *addr, size_t sz, enum access_mode mode,
+ struct access_node *a)
+{
+ while (a && (addr + sz <= a->addr || addr >= a->addr + a->sz))
+ a = a->next;
+ if (a == 0)
+ return 0;
+
+ if (debug)
+ printf ("verify1 (%p, %ld, %s)\n", addr, (long) sz,
+ access_mode_strings[mode]);
+
+ if (mode & ~a->mode)
+ return 0;
+
+ if (addr < a->addr)
+ if (verify1 (a, a->addr - addr, mode, a->next) == 0)
+ return 0;
+ if (addr + sz > a->addr + a->sz)
+ if (verify1 (a->addr + a->sz, (addr + sz) - (a->addr + a->sz), mode, a->next) == 0)
+ return 0;
+
+ /* All regions okay. */
+ return 1;
+}
+
+int verify_range_permission (void *, size_t, enum access_mode) NOCHECK;
+int
+verify_range_permission (void *addr, size_t sz, enum access_mode mode)
+{
+ if (debug)
+ printf ("verify_range_permission (%p, %ld, %s)\n", addr, (long) sz,
+ access_mode_strings[mode]);
+ return verify1 (addr, sz, mode, access_list);
+}
+
+void chkr_check_addr (void *, size_t, int) NOCHECK;
+void
+chkr_check_addr (void *addr, size_t sz, int mode)
+{
+ switch (mode)
+ {
+ case MEMORY_USE_BAD:
+ case MEMORY_USE_DONT:
+ default:
+ report_bad_access (addr, sz, mode);
+ return;
+ case MEMORY_USE_RO:
+ /* verify range readable */
+ if (!verify_range_permission (addr, sz, ACCESS_RO))
+ report_bad_access (addr, sz, mode);
+ return;
+ case MEMORY_USE_WO:
+ /* verify writeable, set writeable and readable */
+ if (!verify_range_permission (addr, sz, ACCESS_WO))
+ report_bad_access (addr, sz, mode);
+ mark_region (addr, sz, ACCESS_RW);
+ return;
+ case MEMORY_USE_RW:
+ /* verify readable and writeable, no change */
+ if (!verify_range_permission (addr, sz, ACCESS_RW))
+ report_bad_access (addr, sz, mode);
+ return;
+ case MEMORY_USE_TW:
+ /* verify writeable, no change */
+ if (!verify_range_permission (addr, sz, ACCESS_WO))
+ report_bad_access (addr, sz, mode);
+ return;
+ }
+ /* All branches should return. */
+ abort ();
+}
+
+void copy1 (void *, void *, size_t, struct access_node *) NOCHECK;
+void
+copy1 (void *dest, void *src, size_t sz, struct access_node *a)
+{
+ while (a && (src + sz <= a->addr || src >= a->addr + a->sz))
+ a = a->next;
+ if (a == 0)
+ {
+ report_bad_access (src, sz, MEMORY_USE_RO);
+ return;
+ }
+
+ if (debug)
+ printf ("copy1 (%p, %p, %ld)\n", dest, src, (long) sz);
+
+ {
+ void *start, *end;
+ start = src;
+ if (start < a->addr)
+ start = a->addr;
+ end = src + sz;
+ if (end > a->addr + a->sz)
+ end = a->addr + a->sz;
+ mark_region (dest + (start - src), end - start, a->mode);
+ }
+
+ if (src < a->addr)
+ copy1 (dest, src, a->addr - src, a->next);
+ if (src + sz > a->addr + a->sz)
+ copy1 (dest + (a->addr + a->sz - src), a->addr + a->sz,
+ (src + sz) - (a->addr + a->sz), a->next);
+}
+
+void chkr_copy_bitmap (void *, void *, size_t) NOCHECK;
+void
+chkr_copy_bitmap (void *dest, void *src, size_t sz)
+{
+ if (verify_range_permission (dest, sz, MEMORY_USE_WO) == 0)
+ report_bad_access (dest, sz, MEMORY_USE_WO);
+ copy1 (dest, src, sz, access_list);
+}
+
+void chkr_set_right (void *, size_t, enum access_mode) NOCHECK;
+void
+chkr_set_right (void *addr, size_t sz, enum access_mode mode)
+{
+ mark_region (addr, sz, mode);
+}
+
+int main () NOCHECK;
+int
+main ()
+{
+ setup ();
+ test ();
+ bad_accesses = !!bad_accesses; /* get 0 or 1 */
+
+ if (bad_accesses == expect_error)
+ exit (0);
+ else
+ abort ();
+
+ return 0;
+}
+
+struct malloc_node
+{
+ struct malloc_node *next;
+ void *addr;
+ size_t sz;
+ unsigned is_free : 1;
+};
+static struct malloc_node *malloc_list;
+
+void *
+c_malloc (size_t sz)
+{
+ void *p;
+ struct malloc_node *m;
+ if (sz == 0)
+ return 0;
+ p = malloc (sz);
+ if (p == 0)
+ {
+ if (verbose)
+ printf ("malloc(%ld) failed\n", (long) sz);
+ exit (1);
+ }
+ m = malloc (sizeof (struct malloc_node));
+ if (m == 0)
+ {
+ if (verbose)
+ printf ("malloc(%ld) failed\n", (long) sizeof (struct malloc_node));
+ exit (1);
+ }
+ mark_region (p, sz, ACCESS_WO);
+ m->addr = p;
+ m->sz = sz;
+ m->is_free = 0;
+ m->next = malloc_list;
+ malloc_list = m;
+ return p;
+}
+
+void
+c_free (void *p)
+{
+ struct malloc_node *m;
+ if (p == 0)
+ return;
+ for (m = malloc_list; m; m = m->next)
+ if (m->addr == p)
+ break;
+ if (m == 0 || m->is_free)
+ /* Test is broken. */
+ abort ();
+ m->is_free = 1;
+ free (p);
+}