1ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*
2ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Make sure that leak-check's pointer tracing avoids traps, i.e. tricky
3ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   memory areas where it could crash if not careful.
4ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown */
5ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <stdio.h>
7ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "memcheck/memcheck.h"
8ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "tests/sys_mman.h"
9ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <stdlib.h>
10ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <fcntl.h>
11ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <unistd.h>
12ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#if !defined(MAP_NORESERVE)
14ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  define MAP_NORESERVE 0
15ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
16ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownint main()
18ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
19ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	char **volatile ptrs;
20ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	int i;
21ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	int fd;
22ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	char *map;
23ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
24ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	/* I _think_ the point of this is to fill ptrs with a pointer
25ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   to every 4th page in the entire address space, hence
26ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   guaranteeing that at least one of them points into one of
27ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   the below traps, and so checks that the leak checker
28ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   doesn't bomb when following them.  That's fine on 32-bit
29ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   platforms, but hopeless for a 64-bit system.  So the
30ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   following settings do achieve that on a 32-bit target but
31ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   merely make a 64-bit target give the same output without
32ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   properly testing it. */
33ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        int ptrbits, stepbits, stepsize, nptrs;
34ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	if (sizeof(void*) == 8) {
35ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           /* 64-bit machine */
36ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   ptrbits = 32;   //bogus
37ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           stepbits = 14+1;  //bogus
38ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   stepsize = (1 << stepbits);
39ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   nptrs = 1 << (ptrbits - stepbits);
40ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	} else {
41ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           /* 32-bit machine */
42ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   ptrbits = 32;
43ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           stepbits = 14;
44ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   stepsize = (1 << stepbits);
45ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   nptrs = 1 << (ptrbits - stepbits);
46ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	}
47ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
48ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	ptrs = malloc(nptrs * sizeof(char *));
49ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	for (i = 0; i < nptrs; i++)
50ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		ptrs[i] = (char *)((long)i << stepbits);
51ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
52ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	/* lay some traps */
53ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        /* non-RWX memory, and MAP_NORESERVE if present */
54ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	map = mmap(0, stepsize * 2, PROT_NONE, MAP_PRIVATE|MAP_NORESERVE|MAP_ANONYMOUS, -1, 0);
55ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	if (map == (char *)-1)
56ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		perror("trap 1 failed");
57ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
58ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        /* write-only memory, and MAP_NORESERVE if supported */
59ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	map = mmap(0, stepsize * 2, PROT_WRITE, MAP_PRIVATE|MAP_NORESERVE|MAP_ANONYMOUS, -1, 0);
60ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	if (map == (char *)-1)
61ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		perror("trap 2 failed");
62ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
63ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	/* non-zero mmap of a zero-length file -> SIGBUS */
64ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	fd = open("./pointer-trace-test-file", O_RDWR | O_CREAT | O_EXCL, 0600);
65ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	unlink("./pointer-trace-test-file");
66ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	map = mmap(0, stepsize * 2, PROT_WRITE|PROT_READ, MAP_PRIVATE, fd, 0);
67ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	if (map == (char *)-1)
68ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		perror("trap 3 failed");
69ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	//printf("trap 3 = %p-%p\n", map, map+stepsize*2);
70ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
71ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        /* unmapped memory that's marked as defined */
72ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	map = mmap(0, 256*1024, PROT_NONE, MAP_PRIVATE|MAP_NORESERVE|MAP_ANONYMOUS, -1, 0);
73ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	if (map == (char *)-1)
74ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		perror("trap 4 failed");
75ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	else {
76ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		munmap(map, 256*1024);
77436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov		(void)VALGRIND_MAKE_MEM_DEFINED(map, 256*1024); /* great big fat lie */
78ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	}
79ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
80ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	VALGRIND_DO_LEAK_CHECK;
81ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
82ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	free(ptrs);
83ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
84ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        // We deliberately make a leak, it'll be obvious if something went
85ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        // wrong because the message won't be printed.
86ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        ptrs = malloc(1000);
87ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
88ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	return 0;
89ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
90