Skip to content

Instantly share code, notes, and snippets.

@kay

kay/dogtag.c

Last active Dec 17, 2015
Embed
What would you like to do?
Simple implementation of the dog tag technique to detect memory corruption.
#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;
}
#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 *);
# 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)
#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
You can’t perform that action at this time.