1 /*
2 * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6 #include <errno.h>
7 #include <limits.h>
8 #include <signal.h>
9 #include <stdint.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <signal.h>
13 #include <string.h>
14 #include <sys/mman.h>
15
16
17 #ifndef PAGE_SIZE
18 # define PAGE_SIZE 4096
19 #endif
20
21
22 static const size_t kMapChunkSize = 4 * PAGE_SIZE;
23 static const size_t kTestSize = 256 * PAGE_SIZE;
24
25 static int64_t sHandledSignals = 0;
26
27 static uint8_t* sMappedBase;
28 static size_t sMappedSize;
29 static uint8_t* sTouchedAddress;
30
31
32 static void
signal_handler(int signal)33 signal_handler(int signal)
34 {
35 sHandledSignals++;
36
37 //printf("SIGSEGV at %p\n", sTouchedAddress);
38
39 // protect the last page of the current allocation writable
40 if (mprotect(sMappedBase + sMappedSize - PAGE_SIZE, PAGE_SIZE,
41 PROT_READ | PROT_WRITE) < 0) {
42 fprintf(stderr, "SIGSEGV: mprotect() failed: %s\n", strerror(errno));
43 exit(1);
44 }
45
46 // allocate the next chunk
47 void* mappedAddress = mmap(sMappedBase + sMappedSize, kMapChunkSize,
48 PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
49 if (mappedAddress == MAP_FAILED) {
50 fprintf(stderr, "SIGSEGV: mmap() failed: %s\n", strerror(errno));
51 exit(1);
52 }
53
54 printf("mapped %d bytes at %p\n", (int)kMapChunkSize, mappedAddress);
55
56 sMappedSize += kMapChunkSize;
57
58 // map the last page read-only
59 if (mprotect(sMappedBase + sMappedSize - PAGE_SIZE, PAGE_SIZE, PROT_READ)
60 < 0) {
61 fprintf(stderr, "SIGSEGV: mprotect() failed: %s\n", strerror(errno));
62 exit(1);
63 }
64 }
65
66
67 int
main()68 main()
69 {
70 // install signal handler
71 if (signal(SIGSEGV, signal_handler) == SIG_ERR) {
72 fprintf(stderr, "Error: Failed to install signal handler: %s\n",
73 strerror(errno));
74 exit(1);
75 }
76
77 // Map the complete test size plus one chunk and unmap all but the first
78 // chunk again, so no other memory gets into the way, when we mmap() the
79 // other chunks with MAP_FIXED.
80 sMappedBase = (uint8_t*)mmap(NULL, kTestSize + kMapChunkSize,
81 PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
82 if (sMappedBase == MAP_FAILED) {
83 fprintf(stderr, "mmap() failed: %s\n", strerror(errno));
84 return 1;
85 }
86 munmap(sMappedBase + kMapChunkSize, kTestSize);
87
88 sMappedSize = kMapChunkSize;
89
90 printf("mapped %d bytes at %p\n", (int)sMappedSize, sMappedBase);
91
92 if (mprotect(sMappedBase + sMappedSize - PAGE_SIZE, PAGE_SIZE, PROT_READ)
93 < 0) {
94 fprintf(stderr, "mprotect() failed: %s\n", strerror(errno));
95 return 1;
96 }
97
98 for (int i = 0; i < 256 * PAGE_SIZE; i++) {
99 sTouchedAddress = sMappedBase + i;
100 *sTouchedAddress = 1;
101 }
102
103 printf("test finished successfully!\n");
104
105 return 0;
106 }
107