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
22static const size_t kMapChunkSize = 4 * PAGE_SIZE;
23static const size_t kTestSize = 256 * PAGE_SIZE;
24
25static int64_t sHandledSignals = 0;
26
27static uint8_t* sMappedBase;
28static size_t sMappedSize;
29static uint8_t* sTouchedAddress;
30
31
32static void
33signal_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
67int
68main()
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