All of the succeeeding information should be considered a draft, and nothing final. Trial and error. Constantly rewriting. New information, new ideas, new learning, and new exploring. The only constant is change.

Multi-threaded Java application demo

Link to code

Preventing Buffer Overflow in C/C++

How does memory work across different levels of scope and what is a safe way to pass, store, and alter that memory given different levels of input? Well, I think this is another way of saying, how do I prevent buffer overflow?

For example, I want to create a function called int ecsGetComponentBit(componentTypeE value) that returns an integer value representing which component bit (0-32) is set. I have an enumeration representing a 32-bit mask field of the different component types. Here is the enum and struct:


// component.h
typedef enum componentTypeE {
    COMPONENT_NONE = 0,
    COMPONENT_TYPE_COUNT = 6,

    COMPONENT_SET1_RENDER2D = 1u << 0,
    COMPONENT_SET1_KEYBOARD = 1u << 1,
    COMPONENT_SET1_MOUSE = 1u << 2,
    COMPONENT_SET1_POSITION = 1u << 3,
    COMPONENT_SET1_VELOCITY = 1u << 4,
    COMPONENT_SET1_NAMETAG = 1u << 5,
} componentTypeE;

typedef struct componentT {
    componentTypeE type;
    void* data;
} componentT;
        

Now, here is the problematic code:


int ecsGetComponentBit(componentTypeE value) {
    char msg[512];
    char componentName[200];
    int position = 1;
    Uint32 i = 1;

    while (1) {
        if (i == (Uint32)value) {
            return position;
        }
        i *= 2;
        position++;
        if (position >= 32) {
            ecsGetComponentName(value, componentName);
            sprintf(msg,
                "warning in function ecsGetComponentBit() - componentType:%s is not correctly initialized",
                componentName);
            writeToLog(msg, "runlog.txt");
            break;
        }
    }
    return -1;
}

void ecsGetComponentName(componentTypeE componentType, char* name) {
    if (name == NULL) return;

    if (componentType == COMPONENT_SET1_KEYBOARD) {
        sprintf(name, "COMPONENT_SET1_KEYBOARD");
    } else if (componentType == COMPONENT_SET1_MOUSE) {
        sprintf(name, "COMPONENT_SET1_MOUSE");
    } else if (componentType == COMPONENT_SET1_RENDER2D) {
        sprintf(name, "COMPONENT_SET1_RENDER2D");
    } else if (componentType == COMPONENT_SET1_VELOCITY) {
        sprintf(name, "COMPONENT_SET1_VELOCITY");
    } else if (componentType == COMPONENT_SET1_POSITION) {
        sprintf(name, "COMPONENT_SET1_POSITION");
    } else if (componentType == COMPONENT_SET1_NAMETAG) {
        sprintf(name, "COMPONENT_SET1_NAMETAG");
    } else {
        sprintf(name, "UNKNOWN_COMPONENT(bit:%d)", ecsGetComponentBit(componentType));
    }
}
        

To be honest, I've only dug into this issue because MSVC wasn't letting me build. You set the component name here depending on the type and save it back into the char* array that was passed into the function — the problem is that if you set a string larger than the incoming buffer, you will get a buffer overflow.

In the case of ecsGetComponentBit() usage, I've allocated 200 chars of memory to be used as a buffer, which is safe in this instance, but without safeguards, it could be risky.

How do we fix it? Pretty simple — use sprintf_s() instead of sprintf(). This requires specifying the buffer size, which prevents overflow. Here’s the fixed version:


int ecsGetComponentBit(componentTypeE value) {
    char msg[512];
    char componentName[200];
    int position = 1;
    Uint32 i = 1;

    while (1) {
        if (i == (Uint32)value) return position;
        i *= 2;
        position++;
        if (position >= 32) {
            ecsGetComponentName(value, componentName, sizeof(componentName));
            sprintf_s(msg, sizeof(msg),
                "warning in function ecsGetComponentBit() - componentType:%s is not correctly initialized",
                componentName);
            writeToLog(msg, "runlog.txt");
            break;
        }
    }
    return -1;
}

void ecsGetComponentName(componentTypeE componentType, char* name, size_t nameSize) {
    if (name == NULL || nameSize == 0) return;

    if (componentType == COMPONENT_SET1_KEYBOARD) {
        sprintf_s(name, nameSize, "COMPONENT_SET1_KEYBOARD");
    } else if (componentType == COMPONENT_SET1_MOUSE) {
        sprintf_s(name, nameSize, "COMPONENT_SET1_MOUSE");
    } else if (componentType == COMPONENT_SET1_RENDER2D) {
        sprintf_s(name, nameSize, "COMPONENT_SET1_RENDER2D");
    } else if (componentType == COMPONENT_SET1_VELOCITY) {
        sprintf_s(name, nameSize, "COMPONENT_SET1_VELOCITY");
    } else if (componentType == COMPONENT_SET1_POSITION) {
        sprintf_s(name, nameSize, "COMPONENT_SET1_POSITION");
    } else if (componentType == COMPONENT_SET1_NAMETAG) {
        sprintf_s(name, nameSize, "COMPONENT_SET1_NAMETAG");
    } else {
        sprintf_s(name, nameSize, "UNKNOWN_COMPONENT(bit:%d)", ecsGetComponentBit(componentType));
    }
}
        

Doing things this way is not only fast, but safe. I hope that thinking about memory in this way was enlightening. Have a great day!

3D Interactive Cube

Your browser doesn’t support WebGL 2.0.

• F/G to increase/decrease delta
• A/S/D or Z/X/C to pick axis & apply
• R to reset

Blog Posts

About Me

Hi, I'm Tony. I recently completed my Masters degree in Computer Science from Drexel University.

Contact: tonystanell [at] gmail [dot] com