Created
April 19, 2020 23:09
-
-
Save birb007/a486195a9c5399a1a1851466704597ce to your computer and use it in GitHub Desktop.
Silent but deadly C.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* 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