Fix all memory leaks
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
25
src/parse.c
25
src/parse.c
@@ -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);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user