Skip to content

Watchdog is a minimal and thread safe C library for tracking memory allocations, reallocations, and frees to detect memory leaks, buffer overflows, and double frees.

License

Notifications You must be signed in to change notification settings

ragibasif/watchdog

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

85 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Watchdog


Email LinkedIn GitHub YouTube

Watchdog wraps dynamic memory functions (malloc, calloc, realloc, free) and tracks all memory activity at runtime:

  • Memory Leak Detection
  • Buffer Overflows / Out-of-Bounds Access
  • Double Free Detection
  • Thread Safe
  • Verbose Logging with Optional File Output
  • Minimal Integration – Just One Header and One C File

YouTube - Stop Memory Leaks In C With Watchdog

#define WATCHDOG_ENABLE
#include "watchdog.h"

#include <stdio.h>
#include <stdlib.h>

int main([[maybe_unused]] int argc, [[maybe_unused]] char **argv) {

    bool enable_verbose_log  = true;
    bool log_to_file         = false;
    bool enable_color_output = true;

    w_init(enable_verbose_log, log_to_file, enable_color_output);

    int *buffer = malloc(sizeof *buffer * 1024);
    free(buffer);

    return EXIT_SUCCESS;
}

./docs/demo_0.gif

Usage

Installation

Include watchdog.h and watchdog.c in your project.

Then #include watchdog.h in a source/header file and pass flag -DWATCHDOG_ENABLE to the CFLAGS of your build system to enable the debugger or add #define WATCHDOG_ENABLE to a file.

Defaults

Verbose logging is on by default, log to file is off by default, and color output is off by default.

static bool verbose_log  = true;
static bool log_to_file  = false;
static bool color_output = false;

To customize the defaults, pass appropriate boolean to w_init.

bool enable_verbose_log  = true;
bool log_to_file         = false;
bool enable_color_output = true;

w_init(enable_verbose_log, log_to_file, enable_color_output);

Enabling log_to_file will direct log output to a log file named watchdog.log. Color output is turned off if log_to_file is enabled regardless of the enable_color_output variable value.

If enable_verbose_log is set to false, only errors will be logged.

Examples

Code samples are located in a dedicated examples/ folder.

Malloc

void malloc_example(void) {

    size_t count  = 5;
    int   *buffer = malloc(sizeof *buffer * 5);
    for (size_t i = 0; i < count; i++) {
        buffer[i] = -(i - count) * count;
    }
    for (size_t i = 0; i < count; i++) {
        printf("%d ", buffer[i]);
    }

    putchar('\n');
    free(buffer);
    buffer = NULL;
}

./docs/malloc.gif

Realloc

void realloc_example(void) {
    short *buffer = malloc(34222);
    buffer        = realloc(buffer, 2342);
    buffer        = realloc(buffer, 2342342);
    buffer        = realloc(buffer, 2);
    buffer        = realloc(buffer, 10);
    buffer        = realloc(buffer, 0);
    free(buffer);
    buffer = NULL;
}

./docs/realloc.gif

Calloc

void calloc_example(void) {
    // Demonstrates correct usage of calloc
    size_t count  = 5;
    int   *buffer = calloc(count, sizeof *buffer);
    for (size_t i = 0; i < count; i++) {
        printf("%d ", buffer[i]); // should output 0
    }
    putchar('\n');
    free(buffer);
    buffer = NULL;
}

./docs/calloc.gif

Free

void free_example(void) {
    // Demonstrates correct usage of free
    size_t         count   = 5;
    short int     *buffer0 = malloc(sizeof *buffer0 * count);
    unsigned char *buffer1 = calloc(count, sizeof *buffer1);
    long double   *buffer2 = realloc(buffer2, sizeof *buffer2 * count);
    free(buffer1);
    buffer1 = NULL;
    free(buffer2);
    buffer2 = NULL;
    free(buffer0);
    buffer1 = NULL;
}

./docs/free.gif

Leak Check

void leak_example(void) {
    unsigned long long int *buffer = malloc(sizeof *buffer * 20);
    // intentionally not calling free
    // watchdog will detect this and report it
}

./docs/leak_check.gif

Overflow Check

void overflow_example(void) {
    char *buffer = malloc(sizeof *buffer * 10);
    strcpy(buffer, "This will overflow"); // out-of-bounds write
    // of buffer overflows will be detected with using canary values
}

./docs/overflow_check.gif

Double Free Check

void double_free_example(void) {
    char **buffer = malloc(sizeof *buffer * 20);
    free(buffer);
    free(buffer); // triggers a double-free error
}

./docs/double_free_check.gif

Invalid Free Check

void invalid_free_example(void) {
    float *buffer;
    free(buffer); // will trigger an error since buffer wasn't allocated
}

./docs/invalid_free_check.gif

Contributing

Interested in contributing? Please see our Contributing Guide for guidelines on how to help improve Watchdog.

License

This project is licensed under the MIT License.

FAQ

Does Watchdog work in production builds?

No. It's intended for development/debug builds.

Does it detect stack overflows?

No. It only monitors dynamic memory (heap).

What systems does it support?

POSIX-compliant systems (Linux, macOS). Windows support is limited (for now).