random memes }

Building a better string class - sentinels and wrap up


One final addition to the ZString class - sentinels. One common programming error is buffer over-run, writing past the end of an allocated array, and possibly overwriting a following item. We can catch this common programming error by allocating an extra byte on both ends of the string buffer and placing known values (sentinels) in each byte. The sentinels are checked when the ZString instance is freed. This is especially important when using a free list as any normal heap validity tests on deallocation are not exercised.

Only the "debug" version of the code makes use of sentinels.


#include <stdlib.h> #include <string.h> #include "ZString.h"

#ifndef ASSERT #include <assert.h> #define ASSERT(X) assert(X) #endif

// // Out-of-line string methods and free list maintenance. //

enum { STRING_BUFFER_SIZE = 256, BOB_SENTINEL = 0x66, EOB_SENTINEL = 0x99 };

static void* g_pFreeList;

void ZString::recycle() { #ifdef _DEBUG ASSERT(BOB_SENTINEL == (255&(sBuffer-1))); ASSERT(EOB_SENTINEL == (255&(sBuffer+cbBufferMax))); #endif if (STRING_BUFFER_SIZE != cbBufferMax) { delete (sBuffer-1); sBuffer = 0; return; } ((void*)sBuffer) = g_pFreeList; g_pFreeList = sBuffer; sBuffer = 0; cbBufferMax = 0; }

void ZString::upsizeTo(int n) { // Allocate oversize strings. if (STRING_BUFFER_SIZE <= n) { // round up to a quanta n = ((n + STRING_BUFFER_SIZE + 1) / STRING_BUFFER_SIZE) * STRING_BUFFER_SIZE; #ifdef _DEBUG char* p = new char[n+2]; p[0] = (char) BOB_SENTINEL; p[1+n] = (char) EOB_SENTINEL; ++p; #else char* p = new char[n]; #endif ::strcpy(p,sBuffer); recycle(); sBuffer = p; cbBufferMax = n; return; } cbBufferMax = STRING_BUFFER_SIZE; // Grab a buffer from the free list if present (the usual case). if (g_pFreeList) { sBuffer = (char*) g_pFreeList; g_pFreeList = ((void*)g_pFreeList); } else { // Allocate a stock-sized buffer. #ifdef _DEBUG sBuffer = new char[2+STRING_BUFFER_SIZE]; *sBuffer++ = (char) BOB_SENTINEL; *(sBuffer+STRING_BUFFER_SIZE) = (char) EOB_SENTINEL; #else sBuffer = new char[STRING_BUFFER_SIZE]; #endif } *sBuffer = 0; }