13521e43fSIngo Weinhold/*
23521e43fSIngo Weinhold * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de.
33521e43fSIngo Weinhold * Distributed under the terms of the MIT License.
43521e43fSIngo Weinhold */
53521e43fSIngo Weinhold
63521e43fSIngo Weinhold#include <errno.h>
73521e43fSIngo Weinhold#include <limits.h>
83521e43fSIngo Weinhold#include <signal.h>
93521e43fSIngo Weinhold#include <stdint.h>
103521e43fSIngo Weinhold#include <stdio.h>
113521e43fSIngo Weinhold#include <stdlib.h>
123521e43fSIngo Weinhold#include <signal.h>
133521e43fSIngo Weinhold#include <string.h>
143521e43fSIngo Weinhold#include <sys/mman.h>
153521e43fSIngo Weinhold
163521e43fSIngo Weinhold
173521e43fSIngo Weinhold#ifndef PAGE_SIZE
183521e43fSIngo Weinhold#	define PAGE_SIZE 4096
193521e43fSIngo Weinhold#endif
203521e43fSIngo Weinhold
213521e43fSIngo Weinhold
223521e43fSIngo Weinholdstatic const size_t kMapChunkSize = 4 * PAGE_SIZE;
233521e43fSIngo Weinholdstatic const size_t kTestSize = 256 * PAGE_SIZE;
243521e43fSIngo Weinhold
253521e43fSIngo Weinholdstatic int64_t sHandledSignals = 0;
263521e43fSIngo Weinhold
273521e43fSIngo Weinholdstatic uint8_t* sMappedBase;
283521e43fSIngo Weinholdstatic size_t sMappedSize;
293521e43fSIngo Weinholdstatic uint8_t* sTouchedAddress;
303521e43fSIngo Weinhold
313521e43fSIngo Weinhold
323521e43fSIngo Weinholdstatic void
333521e43fSIngo Weinholdsignal_handler(int signal)
343521e43fSIngo Weinhold{
353521e43fSIngo Weinhold	sHandledSignals++;
363521e43fSIngo Weinhold
373521e43fSIngo Weinhold	//printf("SIGSEGV at %p\n", sTouchedAddress);
383521e43fSIngo Weinhold
393521e43fSIngo Weinhold	// protect the last page of the current allocation writable
403521e43fSIngo Weinhold	if (mprotect(sMappedBase + sMappedSize - PAGE_SIZE, PAGE_SIZE,
413521e43fSIngo Weinhold			PROT_READ | PROT_WRITE) < 0) {
423521e43fSIngo Weinhold		fprintf(stderr, "SIGSEGV: mprotect() failed: %s\n", strerror(errno));
433521e43fSIngo Weinhold		exit(1);
443521e43fSIngo Weinhold	}
453521e43fSIngo Weinhold
463521e43fSIngo Weinhold	// allocate the next chunk
473521e43fSIngo Weinhold	void* mappedAddress = mmap(sMappedBase + sMappedSize, kMapChunkSize,
493521e43fSIngo Weinhold	if (mappedAddress == MAP_FAILED) {
503521e43fSIngo Weinhold		fprintf(stderr, "SIGSEGV: mmap() failed: %s\n", strerror(errno));
513521e43fSIngo Weinhold		exit(1);
523521e43fSIngo Weinhold	}
533521e43fSIngo Weinhold
543521e43fSIngo Weinhold	printf("mapped %d bytes at %p\n", (int)kMapChunkSize, mappedAddress);
553521e43fSIngo Weinhold
563521e43fSIngo Weinhold	sMappedSize += kMapChunkSize;
573521e43fSIngo Weinhold
583521e43fSIngo Weinhold	// map the last page read-only
593521e43fSIngo Weinhold	if (mprotect(sMappedBase + sMappedSize - PAGE_SIZE, PAGE_SIZE, PROT_READ)
603521e43fSIngo Weinhold			< 0) {
613521e43fSIngo Weinhold		fprintf(stderr, "SIGSEGV: mprotect() failed: %s\n", strerror(errno));
623521e43fSIngo Weinhold		exit(1);
633521e43fSIngo Weinhold	}
643521e43fSIngo Weinhold}
653521e43fSIngo Weinhold
663521e43fSIngo Weinhold
673521e43fSIngo Weinholdint
683521e43fSIngo Weinholdmain()
693521e43fSIngo Weinhold{
703521e43fSIngo Weinhold	// install signal handler
713521e43fSIngo Weinhold	if (signal(SIGSEGV, signal_handler) == SIG_ERR) {
723521e43fSIngo Weinhold		fprintf(stderr, "Error: Failed to install signal handler: %s\n",
733521e43fSIngo Weinhold			strerror(errno));
743521e43fSIngo Weinhold		exit(1);
753521e43fSIngo Weinhold	}
763521e43fSIngo Weinhold
773521e43fSIngo Weinhold	// Map the complete test size plus one chunk and unmap all but the first
783521e43fSIngo Weinhold	// chunk again, so no other memory gets into the way, when we mmap() the
793521e43fSIngo Weinhold	// other chunks with MAP_FIXED.
803521e43fSIngo Weinhold	sMappedBase = (uint8_t*)mmap(NULL, kTestSize + kMapChunkSize,
813521e43fSIngo Weinhold		PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
823521e43fSIngo Weinhold	if (sMappedBase == MAP_FAILED) {
833521e43fSIngo Weinhold		fprintf(stderr, "mmap() failed: %s\n", strerror(errno));
843521e43fSIngo Weinhold		return 1;
853521e43fSIngo Weinhold	}
863521e43fSIngo Weinhold	munmap(sMappedBase + kMapChunkSize, kTestSize);
873521e43fSIngo Weinhold
883521e43fSIngo Weinhold	sMappedSize = kMapChunkSize;
893521e43fSIngo Weinhold
903521e43fSIngo Weinhold	printf("mapped %d bytes at %p\n", (int)sMappedSize, sMappedBase);
913521e43fSIngo Weinhold
923521e43fSIngo Weinhold	if (mprotect(sMappedBase + sMappedSize - PAGE_SIZE, PAGE_SIZE, PROT_READ)
933521e43fSIngo Weinhold			< 0) {
943521e43fSIngo Weinhold		fprintf(stderr, "mprotect() failed: %s\n", strerror(errno));
953521e43fSIngo Weinhold		return 1;
963521e43fSIngo Weinhold	}
973521e43fSIngo Weinhold
983521e43fSIngo Weinhold	for (int i = 0; i < 256 * PAGE_SIZE; i++) {
993521e43fSIngo Weinhold		sTouchedAddress = sMappedBase + i;
1003521e43fSIngo Weinhold		*sTouchedAddress = 1;
1013521e43fSIngo Weinhold	}
1023521e43fSIngo Weinhold
1033521e43fSIngo Weinhold	printf("test finished successfully!\n");
1043521e43fSIngo Weinhold
1053521e43fSIngo Weinhold	return 0;
1063521e43fSIngo Weinhold}