Last active
December 17, 2015 19:09
-
-
Save kay/5658481 to your computer and use it in GitHub Desktop.
Simple implementation of the dog tag technique to detect memory corruption.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "dogtag.h" | |
bool tag_alloc(memory_t * memory, size_t size) { | |
void * ptr = malloc(size + (2 * TAG_SIZE)); | |
if (ptr == NULL) { | |
return false; | |
} | |
TAG_TYPE * startPtr = ptr; | |
*startPtr = VALID_START_TAG; | |
ptr += TAG_SIZE; | |
// Advance the first tag and the remainder of the buffer | |
TAG_TYPE * endPtr = ptr + size; | |
*endPtr = VALID_END_TAG; | |
memory->ptr = ptr; | |
memory->size = size; | |
return true; | |
} | |
bool tag_underran(memory_t * memory) { | |
return *PTR_START_TAG(memory) != VALID_START_TAG; | |
} | |
bool tag_overran(memory_t * memory) { | |
return *PTR_END_TAG(memory) != VALID_END_TAG; | |
} | |
void tag_invalidate(memory_t * memory) { | |
TAG_TYPE * start = PTR_START_TAG(memory); | |
*start = TAG_INVALID_VALUE; | |
TAG_TYPE * end = PTR_END_TAG(memory); | |
*end = TAG_INVALID_VALUE; | |
} | |
bool tag_free(memory_t * memory) { | |
if (tag_underran(memory) || tag_overran(memory)) { | |
return false; | |
} | |
tag_invalidate(memory); | |
TAG_TYPE * start = PTR_START_TAG(memory); | |
free(start); | |
return true; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdlib.h> | |
#include <stdio.h> | |
#include <string.h> | |
#include <stdbool.h> | |
// Dog tag type | |
#define TAG_TYPE int | |
#define TAG_SIZE sizeof(TAG_TYPE) | |
// Dog tag value | |
#define VALID_START_TAG 0xDEADBEEF | |
#define VALID_END_TAG 0xCAFEBABE | |
#define TAG_INVALID_VALUE 0xBADC0DE5 | |
#define PTR_START_TAG(memory) (TAG_TYPE *)(memory->ptr - TAG_SIZE) | |
#define PTR_END_TAG(memory) (TAG_TYPE *)(memory->ptr + memory->size) | |
typedef struct memory { | |
void * ptr; | |
size_t size; | |
} memory_t; | |
bool tag_alloc(memory_t *, size_t); | |
bool tag_underran(memory_t *); | |
bool tag_overran(memory_t *); | |
void tag_invalidate(memory_t *); | |
bool tag_free(memory_t *); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Change extension to .so on Unix | |
LIB=libdogtag.dll | |
# Compiler settings | |
C = gcc | |
CFLAGS = -g -std=c99 | |
all: runner $(LIB) | |
$(LIB): dogtag.o | |
$(CC) $(LDFLAGS) -shared -W1,-soname,libdogtag.so.1 -o $@ $^ | |
dogtag.o: dogtag.c | |
$(CC) $(CFLAGS) -fPIC -c -o $@ $< | |
runner: runner.o $(LIB) | |
$(CC) $(LDFLAGS) -o $@ $^ | |
runner.o: runner.c | |
$(CC) $(CFLAGS) -c -o $@ $< | |
clean: | |
rm -f dogtag dogtag.o | |
rm -f runner runner.o | |
rm -f $(LIB) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "dogtag.h" | |
#define PCOND(x) x ? "true" : "false" | |
void print_and_alloc(const char * name, memory_t * mem) { | |
if (!tag_alloc(mem, 6)) { | |
printf("Cannot allocate '%s'\n", name); | |
} | |
} | |
void print_real_memory(memory_t * mem) { | |
void * endPtr = mem->ptr + mem->size + TAG_SIZE; | |
for(void * ptr = mem->ptr - TAG_SIZE; ptr != endPtr; ptr++) { | |
printf("%02X ", *((unsigned char*)ptr)); | |
} | |
} | |
void print_and_check(const char * name, memory_t * mem) { | |
printf("%s {\n", name); | |
printf(" contents=%s\n", mem->ptr); | |
printf(" size=%d\n", mem->size); | |
printf(" underran? %s\n", PCOND(tag_underran(mem))); | |
printf(" overran? %s\n", PCOND(tag_overran(mem))); | |
printf(" real="); | |
print_real_memory(mem); | |
printf("\n"); | |
printf("}\n"); | |
} | |
void print_and_free(const char * name, memory_t * mem) { | |
if (!tag_free(mem)) { | |
printf("Cannot free '%s' due to corruption: ", name); | |
print_real_memory(mem); | |
printf("\n"); | |
} | |
} | |
int main(char **args) { | |
memory_t healthy; | |
memory_t underran; | |
memory_t overran; | |
memory_t totally_buggered; | |
printf("tag_size=%d\n", TAG_SIZE); | |
print_and_alloc("healthy", &healthy); | |
strcpy(healthy.ptr, "55555"); | |
print_and_alloc("underran", &underran); | |
strcpy(underran.ptr - TAG_SIZE, "BLAT55555"); | |
print_and_alloc("overran", &overran); | |
strcpy(overran.ptr, "55555BLAT"); | |
print_and_alloc("totally buggered", &totally_buggered); | |
strcpy(totally_buggered.ptr - TAG_SIZE, "BLAT55555BLAT"); | |
print_and_check("healthy", &healthy); | |
print_and_check("underran", &underran); | |
print_and_check("overran", &overran); | |
print_and_check("totally buggered", &totally_buggered); | |
print_and_free("healthy", &healthy); | |
print_and_free("underran", &underran); | |
print_and_free("overran", &overran); | |
print_and_free("totally buggered", &totally_buggered); | |
return 0; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment