fix: segfalt in json_get_object_item

This commit is contained in:
2025-03-22 03:18:34 +00:00
parent bcaca5038d
commit 27e42e9010
6 changed files with 32 additions and 49 deletions

View File

@@ -311,13 +311,22 @@ char *json_print(Arena *arena, Json *item) {
/* Retrieve an object item by key (case-sensitive) */ /* Retrieve an object item by key (case-sensitive) */
Json *json_get_object_item(Json *object, const char *key) { Json *json_get_object_item(Json *object, const char *key) {
raise_debug("json get object item for %s", key);
if (!object || object->type != JSON_OBJECT) if (!object || object->type != JSON_OBJECT)
return NULL; return NULL;
Json *child = object->child; Json *child = object->child;
while (child) { while (child) {
raise_debug("child->key: %s, key: %s", child->key, key);
if (child->key && strcmp(child->key, key) == 0) if (child->key && strcmp(child->key, key) == 0)
return child; return child;
child = child->next; child = child->next;
} }
return NULL; return NULL;
} }
//bool json_is_string(const Json * const item) {
// if (item == NULL) {
// return false;
// }
// return item->type == JSON_STRING;
//}

View File

@@ -8,6 +8,7 @@
#include <time.h> #include <time.h>
#include <string.h> #include <string.h>
#include <ctype.h> #include <ctype.h>
#include <stdbool.h>
// ------------- // -------------
// -- Helpers -- // -- Helpers --

View File

@@ -1,4 +1,4 @@
{ stdenv, gcc, lib, chectic, cjson }: { stdenv, gcc, lib, chectic }:
stdenv.mkDerivation { stdenv.mkDerivation {
pname = "hmpl"; pname = "hmpl";
@@ -6,7 +6,7 @@ stdenv.mkDerivation {
src = ./.; src = ./.;
doCheck = true; doCheck = true;
buildInputs = [ chectic cjson ]; buildInputs = [ chectic ];
buildPhase = '' buildPhase = ''
mkdir -p target mkdir -p target
@@ -15,7 +15,7 @@ stdenv.mkDerivation {
${gcc}/bin/cc -Wall -Wextra -g \ ${gcc}/bin/cc -Wall -Wextra -g \
-std=c99 \ -std=c99 \
-pedantic -fsanitize=address -c hmpl.c \ -pedantic -fsanitize=address -c hmpl.c \
-lchectic -lcjson \ -lchectic \
-o target/hmpl.o -o target/hmpl.o
${gcc}/bin/ar rcs target/libhmpl.a target/hmpl.o ${gcc}/bin/ar rcs target/libhmpl.a target/hmpl.o
@@ -23,7 +23,7 @@ stdenv.mkDerivation {
${gcc}/bin/cc -Wall -Wextra -g \ ${gcc}/bin/cc -Wall -Wextra -g \
-pedantic -fsanitize=address main.c \ -pedantic -fsanitize=address main.c \
-Ltarget -lhmpl \ -Ltarget -lhmpl \
-lchectic -lcjson -o target/hmpl -lchectic -o target/hmpl
''; '';
checkPhase = '' ''; checkPhase = '' '';

View File

@@ -1,52 +1,31 @@
#include "hmpl.h" #include "hmpl.h"
Arena *cJSON_global_arena; char *eval(Arena *arena, const Json * const context, const char * const key) {
size_t last_size = 0; // tracked externally, unsafe but works for simple use
void *arena_malloc(size_t size) {
void *ptr = arena_alloc(cJSON_global_arena, size);
last_size = size;
return ptr;
}
void arena_free_stub(void *ptr) {
raise_debug("WARN: cJSON tried to free %p — ignored", ptr);
}
void init_cjson_with_arenas(Arena *arena) {
cJSON_global_arena = arena;
cJSON_InitHooks(&(cJSON_Hooks){
.malloc_fn = arena_malloc,
.free_fn = arena_free_stub,
});
}
char *eval(Arena *arena, const cJSON * const context, const char * const key) {
if (!context || !key) return NULL; if (!context || !key) return NULL;
char *key_copy = arena_strdup(arena, key); char *key_copy = arena_strdup(arena, key);
char *token, *rest = key_copy; char *token, *rest = key_copy;
cJSON *res = context; Json *res = context;
while ((token = strtok_r(rest, ".", &rest))) { while ((token = strtok_r(rest, ".", &rest))) {
raise_debug("context: %s; token: %s", cJSON_Print(res), key); raise_debug("context: %s; token: %s", json_print(arena, res), key);
res = cJSON_GetObjectItemCaseSensitive(res, token); res = json_get_object_item(res, &token);
if (!res) if (!res)
return NULL; return NULL;
} }
if (cJSON_IsString(res) && res->valuestring) if (res == JSON_STRING && res->string)
return arena_strdup(arena, res->valuestring); return arena_strdup(arena, res->string);
else if (cJSON_IsNumber(res)) { else if (res == JSON_NUMBER) {
char buf[64]; char buf[64];
snprintf(buf, sizeof(buf), "%g", res->valuedouble); snprintf(buf, sizeof(buf), "%g", res->number);
return arena_strdup(arena, buf); return arena_strdup(arena, buf);
} }
char *temp = cJSON_PrintUnformatted(res); char *temp = json_print(arena, res);
char *result = arena_strdup(arena, temp); char *result = arena_strdup(arena, temp);
free(temp); free(temp);
return result; return result;
} }
/* Modified: text is passed by reference so we can update it and free old allocations */ /* Modified: text is passed by reference so we can update it and free old allocations */
void render_template_placeholders(Arena *arena, char **text_ptr, cJSON *context, const char * const prefix) { void render_template_placeholders(Arena *arena, char **text_ptr, Json *context, const char * const prefix) {
raise_debug("render_template_placeholders"); raise_debug("render_template_placeholders");
char start_pattern[256]; char start_pattern[256];
snprintf(start_pattern, sizeof(start_pattern), "{{%s", prefix); snprintf(start_pattern, sizeof(start_pattern), "{{%s", prefix);
@@ -86,8 +65,8 @@ void render_template_placeholders(Arena *arena, char **text_ptr, cJSON *context,
} }
} }
void render_template_with_arena(Arena *arena, char **text, const cJSON * const context) { void render_template_with_arena(Arena *arena, char **text, const Json * const context) {
if (!cJSON_IsObject(context)) { if (context->type != JSON_OBJECT) {
raise_exception("Malformed context: context is not json"); raise_exception("Malformed context: context is not json");
exit(1); exit(1);
} }
@@ -95,7 +74,7 @@ void render_template_with_arena(Arena *arena, char **text, const cJSON * const c
render_template_placeholders(arena, text, context, ""); render_template_placeholders(arena, text, context, "");
} }
void render_template(char **text, const cJSON * const context) { void render_template(char **text, const Json * const context) {
Arena arena = arena_init(1024 * 1024); Arena arena = arena_init(1024 * 1024);
render_template_with_arena(&arena, text, context); render_template_with_arena(&arena, text, context);

View File

@@ -6,17 +6,16 @@
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include "chectic.h" #include "chectic.h"
#include "cjson/cJSON.h"
void init_cjson_with_arenas(Arena *arena); void init_cjson_with_arenas(Arena *arena);
char *eval(Arena *arena, const cJSON * const context, const char * const key); char *eval(Arena *arena, const Json * const context, const char * const key);
/* Modified: text is passed by reference so we can update it and free old allocations */ /* Modified: text is passed by reference so we can update it and free old allocations */
void render_template_placeholders(Arena *arena, char **text_ptr, cJSON *context, const char * const prefix); void render_template_placeholders(Arena *arena, char **text_ptr, Json *context, const char * const prefix);
void render_template_with_arena(Arena *arena, char **text, const cJSON * const ccontext); void render_template_with_arena(Arena *arena, char **text, const Json * const ccontext);
void render_template(char **text, const cJSON * const context); void render_template(char **text, const Json * const context);
#endif // EPRINTF_HMPL #endif // EPRINTF_HMPL

View File

@@ -3,7 +3,6 @@
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include "chectic.h" #include "chectic.h"
#include "cjson/cJSON.h"
#include "hmpl.h" #include "hmpl.h"
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
@@ -11,14 +10,12 @@ int main(int argc, char *argv[]) {
raise_info("start"); raise_info("start");
Arena arena = arena_init(1024 * 1024); Arena arena = arena_init(1024 * 1024);
Arena arena_for_jsons = arena_init(1024 * 1024);
init_cjson_with_arenas(&arena_for_jsons);
raise_info("read the arguments"); raise_info("read the arguments");
char *text = NULL; char *text = NULL;
const char *json_input = (argc > 1 ? argv[1] : "{}"); const char *json_input = (argc > 1 ? argv[1] : "{}");
cJSON *context = cJSON_Parse(json_input); Json *context = json_parse(&arena, &json_input);
if (!context) { if (!context) {
fprintf(stderr, "Error parsing JSON\n"); fprintf(stderr, "Error parsing JSON\n");
@@ -33,7 +30,6 @@ int main(int argc, char *argv[]) {
ssize_t len = getdelim(&heap_text, &size, '\0', stdin); ssize_t len = getdelim(&heap_text, &size, '\0', stdin);
if (len < 0) { if (len < 0) {
perror("read stdin"); perror("read stdin");
cJSON_Delete(context);
return 1; return 1;
} }
text = arena_strdup(&arena, heap_text); text = arena_strdup(&arena, heap_text);
@@ -46,6 +42,5 @@ int main(int argc, char *argv[]) {
printf("%s", text); printf("%s", text);
arena_free(&arena); arena_free(&arena);
cJSON_Delete(context);
return 0; return 0;
} }