Skip to content

Instantly share code, notes, and snippets.

@birb007
Created April 19, 2020 23:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save birb007/a486195a9c5399a1a1851466704597ce to your computer and use it in GitHub Desktop.
Save birb007/a486195a9c5399a1a1851466704597ce to your computer and use it in GitHub Desktop.
Silent but deadly C.
/* Can you find the bug without ASan or Valgrind?
*
* $ gcc --version
* gcc (Arch Linux 9.3.0-1) 9.3.0
* $ gcc -Wall -Wextra -pedantic bug.c -o bug
*/
#include <stdio.h>
#include <stdlib.h>
enum event_type { SUCCESS, FAILURE, WARNING, DEBUG };
typedef struct _event_ctx {
int id;
enum event_type type;
const char* description;
} event_ctx;
typedef struct _event_handler_ctx {
char* name;
enum event_type type;
int n_frequency;
void (*func)(event_ctx*);
} event_handler_ctx_t;
typedef struct _logger {
event_handler_ctx_t* event_handlers;
_Bool enabled;
} logger_t;
event_ctx* create_event(enum event_type, const char*);
void success(event_ctx*);
void failure(event_ctx*);
void handle_event(logger_t*, event_ctx*);
int factorial(logger_t*, int);
void default_event_handlers(logger_t*);
event_ctx* create_event(enum event_type type, const char* description) {
static int id = 0;
event_ctx* event;
if (!(event = malloc(sizeof event))) {
perror("unable to allocate memory");
return NULL;
}
event->id = id++;
event->type = type;
event->description = description;
return event;
}
void success(event_ctx* event) {
printf("[OK] event %d completed successfully: %s\n", event->id,
event->description);
}
void failure(event_ctx* event) {
printf("[!!] event %d failed: %s\n", event->id, event->description);
}
void default_event_handlers(logger_t* logger) {
event_handler_ctx_t handlers[] = {
{.name = "success", .type = SUCCESS, .n_frequency = 0, .func = success},
{.name = "failure", .type = FAILURE, .n_frequency = 0, .func = failure},
{.name = NULL, .type = SUCCESS, .n_frequency = -1, .func = NULL}};
logger->event_handlers = handlers;
}
void handle_event(logger_t* logger, event_ctx* event) {
if (!logger->event_handlers || !logger->enabled) {
return;
}
int i = 1;
for (event_handler_ctx_t h = logger->event_handlers[0]; h.name;
h = logger->event_handlers[i++]) {
if (h.type == event->type) {
h.n_frequency++;
h.func(event);
}
}
free(event);
}
int factorial(logger_t* logger, int n) {
event_ctx* event;
if (n < 0) {
event = create_event(FAILURE, "n must be greater than 0");
handle_event(logger, event);
return -1;
}
if (n < 2) {
return 1;
}
event = create_event(SUCCESS, "factorial body");
handle_event(logger, event);
return n * factorial(logger, n - 1);
}
int main() {
int n;
logger_t logger = {.event_handlers = NULL, .enabled = 1};
default_event_handlers(&logger);
n = factorial(&logger, 10);
printf("n=%d\n", n);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment