Fix all memory leaks

This commit is contained in:
olemorud
2023-04-24 23:44:17 +02:00
parent 3b7cc458fc
commit 2eeaa2171f
4 changed files with 69 additions and 20 deletions

View File

@@ -4,7 +4,7 @@
#include <stdbool.h> // bool #include <stdbool.h> // bool
#define OBJ_SIZE 64 #define OBJ_SIZE 32
typedef struct obj_entry { typedef struct obj_entry {
char const* key; char const* key;
@@ -25,7 +25,7 @@ struct json_value {
enum json_type type; enum json_type type;
union { union {
obj_t* object; obj_t* object;
struct json_value** array; struct json_value** array; // we need an array of pointers to allow null termination
char* string; char* string;
bool boolean; bool boolean;
double number; double number;
@@ -34,8 +34,10 @@ struct json_value {
void* obj_at(obj_t m, char* const key); void* obj_at(obj_t m, char* const key);
bool obj_insert(obj_t m, char* const key, struct json_value* value); bool obj_insert(obj_t m, char* const key, struct json_value* value);
void obj_delete(obj_t m); void obj_delete(obj_t* m);
void print_json(struct json_value val, int indent); void print_json(struct json_value val, int indent);
void json_value_delete(struct json_value val);
#endif #endif

View File

@@ -10,11 +10,12 @@
bool obj_insert(obj_t m, char* const key, struct json_value* value); bool obj_insert(obj_t m, char* const key, struct json_value* value);
size_t obj_hash(char const* str); size_t obj_hash(char const* str);
void obj_delete(obj_t m); void obj_delete(obj_t* m);
void* obj_at(obj_t m, char* const key);
void print_array(struct json_value** arr, int cur_indent, int indent_amount); void print_array(struct json_value** arr, int cur_indent, int indent_amount);
void print_json_value(struct json_value val, int cur_indent, int indent_amount); void print_json_value(struct json_value val, int cur_indent, int indent_amount);
void print_object(obj_t obj, int cur_indent, int indent_amount); void print_object(obj_t obj, int cur_indent, int indent_amount);
void* obj_at(obj_t m, char* const key);
/* /*
djb2 string hash djb2 string hash
@@ -104,7 +105,7 @@ bool obj_insert(obj_t m, char* const key, struct json_value* value)
/* populate new entry */ /* populate new entry */
cur = malloc_or_die(sizeof(struct obj_entry)); cur = malloc_or_die(sizeof(struct obj_entry));
cur->key = strdup(key); cur->key = key;
cur->val = value; cur->val = value;
cur->next = m[i]; cur->next = m[i];
@@ -114,27 +115,52 @@ bool obj_insert(obj_t m, char* const key, struct json_value* value)
return true; return true;
} }
void json_value_delete(struct json_value val)
{
switch (val.type) {
case array:
for (size_t i = 0; val.array[i] != NULL; i++) {
json_value_delete(*(val.array[i]));
free(val.array[i]);
}
free(val.array);
break;
case object:
obj_delete(val.object);
break;
case string:
free(val.string);
break;
default:
break;
}
}
/* /*
Free memory allocated for obj Free memory allocated for obj
TODO: recurively delete children objects TODO: recurively delete children objects
*/ */
void obj_delete(obj_t m) void obj_delete(obj_t* m)
{ {
for (size_t i = 0; i < OBJ_SIZE; i++) { for (size_t i = 0; i < OBJ_SIZE; i++) {
if (m[i] == NULL) struct obj_entry *e = (*m)[i], *tmp;
continue;
struct obj_entry *e = m[i], *tmp;
while (e != NULL) { while (e != NULL) {
tmp = e; json_value_delete(*(e->val));
free((char*)e->key); free((char*)e->key);
free(e->val); free(e->val);
tmp = e;
e = e->next; e = e->next;
free(tmp); free(tmp);
} }
} }
free(m);
} }
void add_indent(int n) void add_indent(int n)
@@ -181,7 +207,7 @@ void print_array(struct json_value** arr, int cur_indent, int indent_amount)
return; return;
} }
for (size_t i = 0; arr[i+1] != NULL; i++) { for (size_t i = 0; arr[i + 1] != NULL; i++) {
putchar('\n'); putchar('\n');
add_indent(cur_indent); add_indent(cur_indent);
print_json_value(*arr[i], cur_indent + indent_amount, indent_amount); print_json_value(*arr[i], cur_indent + indent_amount, indent_amount);

View File

@@ -16,9 +16,13 @@ int main(int argc, char* argv[])
FILE* fp = fopen(argv[1], "r"); FILE* fp = fopen(argv[1], "r");
volatile struct json_value x = parse_json_value(fp); struct json_value x = parse_json_value(fp);
print_json(x, 1); // print_json(x, 1);
json_value_delete(x);
fclose(fp);
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

View File

@@ -113,7 +113,7 @@ struct json_value parse_json_value(FILE* fp)
char* read_string(FILE* fp) char* read_string(FILE* fp)
{ {
int c; int c;
size_t i = 0, result_size = 16 * sizeof(char); size_t i = 0, result_size = 16;
char* result = malloc_or_die(result_size); char* result = malloc_or_die(result_size);
bool escaped = false; bool escaped = false;
@@ -141,6 +141,7 @@ char* read_string(FILE* fp)
return realloc_or_die(result, i); return realloc_or_die(result, i);
case EOF: case EOF:
free(result);
err_ctx(EARLY_EOF, fp, "(%s) unexpected EOF", __func__); err_ctx(EARLY_EOF, fp, "(%s) unexpected EOF", __func__);
default: default:
@@ -170,9 +171,11 @@ obj_t* read_object(FILE* fp)
switch (fgetc(fp)) { switch (fgetc(fp)) {
case EOF: case EOF:
free(result);
err_ctx(EARLY_EOF, fp, "(%s) unexpected EOF", __func__); err_ctx(EARLY_EOF, fp, "(%s) unexpected EOF", __func__);
default: default:
free(result);
err_ctx(UNEXPECTED_CHAR, fp, "(%s) expected \"", __func__); err_ctx(UNEXPECTED_CHAR, fp, "(%s) expected \"", __func__);
case '"': case '"':
@@ -191,9 +194,11 @@ obj_t* read_object(FILE* fp)
break; break;
case EOF: case EOF:
free(result);
err_ctx(EARLY_EOF, fp, "(%s) unexpected EOF", __func__); err_ctx(EARLY_EOF, fp, "(%s) unexpected EOF", __func__);
default: default:
free(result);
err_ctx(UNEXPECTED_CHAR, fp, "(%s) expected ':'", __func__); err_ctx(UNEXPECTED_CHAR, fp, "(%s) expected ':'", __func__);
} }
@@ -204,14 +209,19 @@ obj_t* read_object(FILE* fp)
*val = parse_json_value(fp); *val = parse_json_value(fp);
/* insert key-value pair to obj */ /* insert key-value pair to obj */
if (!obj_insert(*result, key, val)) if (!obj_insert(*result, key, val)) {
free(result);
free(val);
errx(EXIT_FAILURE, "failed to insert pair (%s, %p)", key, (void*)val); errx(EXIT_FAILURE, "failed to insert pair (%s, %p)", key, (void*)val);
}
/* read separator or end of object */ /* read separator or end of object */
discard_whitespace(fp); discard_whitespace(fp);
switch (fgetc(fp)) { switch (fgetc(fp)) {
case EOF: case EOF:
free(val);
free(result);
err_ctx(EARLY_EOF, fp, "(%s) unexpected EOF", __func__); err_ctx(EARLY_EOF, fp, "(%s) unexpected EOF", __func__);
case ',': case ',':
@@ -221,6 +231,8 @@ obj_t* read_object(FILE* fp)
return result; return result;
default: default:
free(val);
free(result);
err_ctx(UNEXPECTED_CHAR, fp, "(%s) expected ',' or '}'", __func__); err_ctx(UNEXPECTED_CHAR, fp, "(%s) expected ',' or '}'", __func__);
} }
} }
@@ -252,6 +264,11 @@ struct json_value** read_array(FILE* fp)
switch (c) { switch (c) {
case EOF: case EOF:
free(output);
for (size_t j = 0; j < i; j++)
free(output[j]);
err_ctx(EARLY_EOF, fp, "(%s) unexpected EOF", __func__); err_ctx(EARLY_EOF, fp, "(%s) unexpected EOF", __func__);
break; break;
@@ -281,7 +298,7 @@ struct json_value** read_array(FILE* fp)
void read_null(FILE* fp) void read_null(FILE* fp)
{ {
static const char ok[] = { 'n', 'u', 'l', 'l' }; static const char ok[] = { 'n', 'u', 'l', 'l' };
char buf[sizeof(ok)]; static char buf[sizeof(ok)];
size_t n_read = fread(buf, sizeof(char), sizeof(ok), fp); size_t n_read = fread(buf, sizeof(char), sizeof(ok), fp);
@@ -304,7 +321,7 @@ bool read_boolean(FILE* fp)
static const char t[] = { 't', 'r', 'u', 'e' }; static const char t[] = { 't', 'r', 'u', 'e' };
static const char f[] = { 'f', 'a', 'l', 's', 'e' }; static const char f[] = { 'f', 'a', 'l', 's', 'e' };
char buf[sizeof(f)] = { 0 }; static char buf[sizeof(f)] = { 0 };
size_t n_read = fread(buf, sizeof(char), sizeof(f), fp); size_t n_read = fread(buf, sizeof(char), sizeof(f), fp);