summaryrefslogtreecommitdiff
path: root/gcc/testsuite/gcc.c-torture/execute/memcheck
diff options
context:
space:
mode:
authorYamaArashi <shadow962@live.com>2016-01-06 01:47:28 -0800
committerYamaArashi <shadow962@live.com>2016-01-06 01:47:28 -0800
commitbe8b04496302184c6e8f04d6179f9c3afc50aeb6 (patch)
tree726e2468c0c07add773c0dbd86ab6386844259ae /gcc/testsuite/gcc.c-torture/execute/memcheck
initial commit
Diffstat (limited to 'gcc/testsuite/gcc.c-torture/execute/memcheck')
-rwxr-xr-xgcc/testsuite/gcc.c-torture/execute/memcheck/blkarg.c75
-rwxr-xr-xgcc/testsuite/gcc.c-torture/execute/memcheck/blkarg.x9
-rwxr-xr-xgcc/testsuite/gcc.c-torture/execute/memcheck/driver.c272
-rwxr-xr-xgcc/testsuite/gcc.c-torture/execute/memcheck/driver.h28
-rwxr-xr-xgcc/testsuite/gcc.c-torture/execute/memcheck/memcheck.exp54
-rwxr-xr-xgcc/testsuite/gcc.c-torture/execute/memcheck/t1.c27
-rwxr-xr-xgcc/testsuite/gcc.c-torture/execute/memcheck/t2.c26
-rwxr-xr-xgcc/testsuite/gcc.c-torture/execute/memcheck/t3.c25
-rwxr-xr-xgcc/testsuite/gcc.c-torture/execute/memcheck/t4.c34
-rwxr-xr-xgcc/testsuite/gcc.c-torture/execute/memcheck/t5.c33
-rwxr-xr-xgcc/testsuite/gcc.c-torture/execute/memcheck/t6.c39
-rwxr-xr-xgcc/testsuite/gcc.c-torture/execute/memcheck/t7.c40
-rwxr-xr-xgcc/testsuite/gcc.c-torture/execute/memcheck/t8.c41
-rwxr-xr-xgcc/testsuite/gcc.c-torture/execute/memcheck/t9.c40
-rwxr-xr-xgcc/testsuite/gcc.c-torture/execute/memcheck/template16
15 files changed, 759 insertions, 0 deletions
diff --git a/gcc/testsuite/gcc.c-torture/execute/memcheck/blkarg.c b/gcc/testsuite/gcc.c-torture/execute/memcheck/blkarg.c
new file mode 100755
index 0000000..4f448d6
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/memcheck/blkarg.c
@@ -0,0 +1,75 @@
+/* Must define:
+ int expect_error;
+ void test ();
+ void setup () NOCHECK; */
+
+#include "driver.h"
+
+/* Test permissions of BLKmode arguments constructed purely on the
+ stack.
+
+ Maybe we can't guarantee that we'll always wind up with stack args,
+ but if we don't, they're in registers, and permissions should just
+ always yield success. So while this test may not be effective on
+ all platforms, failure probably does indicate a real bug.
+
+ Note that because of the implementation, we do want to test BLKmode
+ arguments that live purely on the stack and are constructed there.
+ We want to test other situations of function arguments, of course,
+ but don't assume this case would be covered by using one monster
+ argument that is read from memory (including using constructor
+ syntax but constant values), or may live partially in registers. */
+
+int expect_error = 0;
+
+/* Must be BLKmode. Using only two fields gets TImode on Alpha. */
+struct S
+{
+ unsigned long long ll;
+ long xx;
+ long yy;
+};
+
+unsigned long long x = 0x12345689ULL;
+#define I2 42
+
+static int first_time = 1;
+
+/* Leading ten arguments force struct S onto the stack on both Alpha and MIPS. */
+int
+foo (int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9, int a10,
+ struct S s)
+{
+ if (a1 != 1 || a2 != 2 || a3 != 3 || a4 != 4 || a5 != 5 || a6 != 6 || a7 != 7
+ || a8 != 8 || a9 !=9 || a10 != 10)
+ abort ();
+
+ if (first_time)
+ {
+ if (s.ll != x || s.xx != I2 || s.yy != 0)
+ abort ();
+
+ first_time = 0;
+ }
+ else
+ {
+ if (s.ll != 0 || s.xx != 0 || s.yy != 0)
+ abort ();
+ }
+
+ return 0;
+}
+
+void
+test ()
+{
+ foo (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, (struct S) { x, I2 });
+ foo (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, (struct S) { 0 });
+}
+
+void
+setup () /* NOCHECK */
+{
+ mark_region (&x, sizeof (x), ACCESS_RO);
+ mark_region (&first_time, sizeof (first_time), ACCESS_RW);
+}
diff --git a/gcc/testsuite/gcc.c-torture/execute/memcheck/blkarg.x b/gcc/testsuite/gcc.c-torture/execute/memcheck/blkarg.x
new file mode 100755
index 0000000..52b53fe
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/memcheck/blkarg.x
@@ -0,0 +1,9 @@
+# The memeory checking code does not mark the stack as readable or writable
+# so this test fails. Ideally the memory checking library ought to
+# cooperate with the host OS to mark the stack as it is used or individual
+# function prologues and epilogues ought to mark their pieces of stack as
+# writable and readable-after-written.
+
+set torture_execute_xfail "*-*-*"
+
+return 0
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);
+}
diff --git a/gcc/testsuite/gcc.c-torture/execute/memcheck/driver.h b/gcc/testsuite/gcc.c-torture/execute/memcheck/driver.h
new file mode 100755
index 0000000..d8d22d2
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/memcheck/driver.h
@@ -0,0 +1,28 @@
+/* GNU C dependencies:
+ Checker support hooks
+ ISO C 9x array element initialization
+ void-pointer arithmetic */
+
+typedef __SIZE_TYPE__ size_t;
+
+extern void *malloc (size_t);
+extern int printf (const char *, ...);
+
+/* This comes from gcc internals. Should be exported. */
+enum memory_use_mode {MEMORY_USE_BAD = 0, MEMORY_USE_RO = 1,
+ MEMORY_USE_WO = 2, MEMORY_USE_RW = 3,
+ MEMORY_USE_TW = 6, MEMORY_USE_DONT = 99};
+
+enum access_mode {
+ ACCESS_NONE = 0, ACCESS_RO = 1, ACCESS_WO = 2, ACCESS_RW = 3
+};
+
+#define NOCHECK __attribute__ ((no_check_memory_usage))
+
+void mark_region (const void *, size_t, enum access_mode) NOCHECK;
+void setup () NOCHECK;
+void test ();
+extern int expect_error;
+
+void *c_malloc (size_t) NOCHECK;
+void c_free (void *) NOCHECK;
diff --git a/gcc/testsuite/gcc.c-torture/execute/memcheck/memcheck.exp b/gcc/testsuite/gcc.c-torture/execute/memcheck/memcheck.exp
new file mode 100755
index 0000000..7fb756b
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/memcheck/memcheck.exp
@@ -0,0 +1,54 @@
+# Copyright (C) 1991, 92-93, 95, 97, 1998 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+# Please email any bugs, comments, and/or additions to this file to:
+# bug-gcc@prep.ai.mit.edu
+
+# This file was written by Rob Savoye. (rob@cygnus.com)
+# Modified and maintained by Jeffrey Wheat (cassidy@cygnus.com)
+
+#
+# These tests come from Torbjorn Granlund (tege@cygnus.com)
+# C torture test suite.
+#
+
+if $tracelevel then {
+ strace $tracelevel
+}
+
+# load support procs
+load_lib c-torture.exp
+
+#
+# main test loop
+#
+
+set tests [lsort [glob -nocomplain $srcdir/$subdir/*.c]]
+set idx [lsearch $tests */driver.c]
+if $idx>=0 {
+ set tests [lreplace $tests $idx $idx]
+} else {
+ error "list can't find driver.c in $srcdir/$subdir"
+}
+gcc_target_compile $srcdir/$subdir/driver.c driver.o object {additional_flags=-w additional_flags=-g}
+foreach src $tests {
+ # If we're only testing specific files and this isn't one of them, skip it.
+ if ![runtest_file_p $runtests $src] then {
+ continue
+ }
+
+ c-torture-execute $src "-fcheck-memory-usage driver.o"
+}
diff --git a/gcc/testsuite/gcc.c-torture/execute/memcheck/t1.c b/gcc/testsuite/gcc.c-torture/execute/memcheck/t1.c
new file mode 100755
index 0000000..03b6acc
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/memcheck/t1.c
@@ -0,0 +1,27 @@
+/* Must define:
+ int expect_error;
+ void test ();
+ void setup (); -- NOCHECK */
+
+#include "driver.h"
+
+int expect_error = 0;
+
+int *ip;
+
+void test ()
+{
+ ip = c_malloc (sizeof (int));
+ *ip = 42;
+ t2 ();
+}
+
+int t2 ()
+{
+ return *ip;
+}
+
+void setup () /* NOCHECK */
+{
+ mark_region (&ip, sizeof (ip), ACCESS_RW);
+}
diff --git a/gcc/testsuite/gcc.c-torture/execute/memcheck/t2.c b/gcc/testsuite/gcc.c-torture/execute/memcheck/t2.c
new file mode 100755
index 0000000..d386eb7
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/memcheck/t2.c
@@ -0,0 +1,26 @@
+/* Must define:
+ int expect_error;
+ void test ();
+ void setup () NOCHECK; */
+
+#include "driver.h"
+
+int expect_error = 1;
+
+int *ip;
+
+void test ()
+{
+ ip = c_malloc (sizeof (int));
+ t2 ();
+}
+
+int t2 ()
+{
+ return *ip;
+}
+
+void setup () /* NOCHECK */
+{
+ mark_region (&ip, sizeof (ip), ACCESS_RW);
+}
diff --git a/gcc/testsuite/gcc.c-torture/execute/memcheck/t3.c b/gcc/testsuite/gcc.c-torture/execute/memcheck/t3.c
new file mode 100755
index 0000000..5b6333d
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/memcheck/t3.c
@@ -0,0 +1,25 @@
+/* Must define:
+ int expect_error;
+ void test ();
+ void setup () NOCHECK; */
+
+#include "driver.h"
+
+int expect_error = 0;
+
+int *ip;
+
+void test ()
+{
+ ip = c_malloc (sizeof (int));
+ t2 (ip);
+}
+
+int t2 (int *ip)
+{
+}
+
+void setup () /* NOCHECK */
+{
+ mark_region (&ip, sizeof (ip), ACCESS_RW);
+}
diff --git a/gcc/testsuite/gcc.c-torture/execute/memcheck/t4.c b/gcc/testsuite/gcc.c-torture/execute/memcheck/t4.c
new file mode 100755
index 0000000..25010a0
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/memcheck/t4.c
@@ -0,0 +1,34 @@
+/* Must define:
+ int expect_error;
+ void test ();
+ void setup () NOCHECK; */
+
+#include "driver.h"
+
+int expect_error = 0;
+
+struct s {
+ char c;
+ int a, b;
+};
+
+struct s *sp;
+
+void test ()
+{
+ sp = c_malloc (sizeof (struct s));
+ sp->c = 0;
+ sp->a = 12;
+ sp->b = 47;
+ foo (sp);
+}
+
+int foo (struct s *sp)
+{
+ return sp->c + sp->a + sp->b;
+}
+
+void setup () /* NOCHECK */
+{
+ mark_region (&sp, sizeof (sp), ACCESS_RW);
+}
diff --git a/gcc/testsuite/gcc.c-torture/execute/memcheck/t5.c b/gcc/testsuite/gcc.c-torture/execute/memcheck/t5.c
new file mode 100755
index 0000000..c3bbf64
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/memcheck/t5.c
@@ -0,0 +1,33 @@
+/* Must define:
+ int expect_error;
+ void test ();
+ void setup () NOCHECK; */
+
+#include "driver.h"
+
+int expect_error = 1;
+
+struct s {
+ char c;
+ int a, b;
+};
+
+struct s *sp;
+
+void test ()
+{
+ sp = c_malloc (sizeof (struct s));
+ sp->c = 0;
+ sp->b = 47;
+ foo (sp);
+}
+
+int foo (struct s *sp)
+{
+ return sp->c + sp->a + sp->b;
+}
+
+void setup () /* NOCHECK */
+{
+ mark_region (&sp, sizeof (sp), ACCESS_RW);
+}
diff --git a/gcc/testsuite/gcc.c-torture/execute/memcheck/t6.c b/gcc/testsuite/gcc.c-torture/execute/memcheck/t6.c
new file mode 100755
index 0000000..652d33d
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/memcheck/t6.c
@@ -0,0 +1,39 @@
+/* Must define:
+ int expect_error;
+ void test ();
+ void setup () NOCHECK; */
+
+#include "driver.h"
+
+int expect_error = 1;
+
+struct s {
+ char c;
+ int a, b;
+};
+
+struct s *sp;
+
+void test ()
+{
+ sp = c_malloc (sizeof (struct s) * 2);
+ sp->c = 0;
+ sp->b = 47;
+ cp (sp);
+ foo (sp);
+}
+
+int foo (struct s *sp)
+{
+ return sp[1].c + sp[1].a + sp[1].b;
+}
+
+int cp (struct s *sp)
+{
+ sp[1] = sp[0];
+}
+
+void setup () /* NOCHECK */
+{
+ mark_region (&sp, sizeof (sp), ACCESS_RW);
+}
diff --git a/gcc/testsuite/gcc.c-torture/execute/memcheck/t7.c b/gcc/testsuite/gcc.c-torture/execute/memcheck/t7.c
new file mode 100755
index 0000000..a7c6f51
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/memcheck/t7.c
@@ -0,0 +1,40 @@
+/* Must define:
+ int expect_error;
+ void test ();
+ void setup () NOCHECK; */
+
+#include "driver.h"
+
+int expect_error = 0;
+
+struct s {
+ char c;
+ int a, b;
+};
+
+struct s *sp;
+
+void test ()
+{
+ sp = c_malloc (sizeof (struct s) * 2);
+ sp->c = 0;
+ sp->a = 13;
+ sp->b = 47;
+ cp (sp);
+ foo (sp);
+}
+
+int foo (struct s *sp)
+{
+ return sp[1].c + sp[1].a + sp[1].b;
+}
+
+int cp (struct s *sp)
+{
+ sp[1] = sp[0];
+}
+
+void setup () /* NOCHECK */
+{
+ mark_region (&sp, sizeof (sp), ACCESS_RW);
+}
diff --git a/gcc/testsuite/gcc.c-torture/execute/memcheck/t8.c b/gcc/testsuite/gcc.c-torture/execute/memcheck/t8.c
new file mode 100755
index 0000000..01c1672
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/memcheck/t8.c
@@ -0,0 +1,41 @@
+/* Must define:
+ int expect_error;
+ void test ();
+ void setup () NOCHECK; */
+
+#include "driver.h"
+
+int expect_error = 0;
+
+typedef struct {
+ short a;
+ char b;
+} S1;
+typedef struct {
+ struct { int x; S1 *s1p; } *p;
+} S2;
+
+S1 *s1;
+S2 *s2;
+
+void test ()
+{
+ s1 = c_malloc (sizeof (S1));
+ s2 = c_malloc (sizeof (S2));
+ s2->p = c_malloc (sizeof (*s2->p));
+ s2->p->s1p = s1;
+ s1->a = 47;
+ s1->b = 3;
+ foo ();
+}
+
+int foo ()
+{
+ return s2->p->s1p->b;
+}
+
+void setup () /* NOCHECK */
+{
+ mark_region (&s1, sizeof (s1), ACCESS_RW);
+ mark_region (&s2, sizeof (s2), ACCESS_RW);
+}
diff --git a/gcc/testsuite/gcc.c-torture/execute/memcheck/t9.c b/gcc/testsuite/gcc.c-torture/execute/memcheck/t9.c
new file mode 100755
index 0000000..f32ca01
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/memcheck/t9.c
@@ -0,0 +1,40 @@
+/* Must define:
+ int expect_error;
+ void test ();
+ void setup () NOCHECK; */
+
+#include "driver.h"
+
+int expect_error = 1;
+
+typedef struct {
+ short a;
+ char b;
+} S1;
+typedef struct {
+ struct { int x; S1 *s1p; } *p;
+} S2;
+
+S1 *s1;
+S2 *s2;
+
+void test ()
+{
+ s1 = c_malloc (sizeof (S1));
+ s2 = c_malloc (sizeof (S2));
+ s2->p = c_malloc (sizeof (*s2->p));
+ s2->p->s1p = s1;
+ s1->a = 47;
+ foo ();
+}
+
+int foo ()
+{
+ return s2->p->s1p->b;
+}
+
+void setup () /* NOCHECK */
+{
+ mark_region (&s1, sizeof (s1), ACCESS_RW);
+ mark_region (&s2, sizeof (s2), ACCESS_RW);
+}
diff --git a/gcc/testsuite/gcc.c-torture/execute/memcheck/template b/gcc/testsuite/gcc.c-torture/execute/memcheck/template
new file mode 100755
index 0000000..37ebb13
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/memcheck/template
@@ -0,0 +1,16 @@
+/* Must define:
+ int expect_error;
+ void test ();
+ void setup () NOCHECK; */
+
+#include "driver.h"
+
+int expect_error = ;
+
+void test ()
+{
+}
+
+void setup () /* NOCHECK */
+{
+}