diff --git a/src/pipeline/pass_calls.c b/src/pipeline/pass_calls.c index 7384b8fed..15d691d3a 100644 --- a/src/pipeline/pass_calls.c +++ b/src/pipeline/pass_calls.c @@ -208,8 +208,9 @@ static void handle_route_registration(cbm_pipeline_ctx_t *ctx, const CBMCall *ca if (hres.qualified_name != NULL && hres.qualified_name[0] != '\0') { const cbm_gbuf_node_t *handler = cbm_gbuf_find_by_qn(ctx->gbuf, hres.qualified_name); if (handler != NULL) { - char hprops[CBM_SZ_256]; - char esc_h[CBM_SZ_256]; + char hprops[CBM_SZ_1K]; /* must exceed escaped value + wrapper or snprintf cuts the + closing brace */ + char esc_h[CBM_SZ_512]; cbm_json_escape(esc_h, sizeof(esc_h), hres.qualified_name); snprintf(hprops, sizeof(hprops), "{\"handler\":\"%s\"}", esc_h); cbm_gbuf_insert_edge(ctx->gbuf, handler->id, route_id, "HANDLES", hprops); diff --git a/src/pipeline/pass_parallel.c b/src/pipeline/pass_parallel.c index 8f8b90f4a..180ee85f7 100644 --- a/src/pipeline/pass_parallel.c +++ b/src/pipeline/pass_parallel.c @@ -507,7 +507,7 @@ static void insert_def_into_gbuf(extract_worker_state_t *ws, const cbm_file_info cbm_gbuf_upsert_node(ws->local_gbuf, "Route", def->route_path, route_qn, def->file_path ? def->file_path : fi->rel_path, 0, 0, rprops); char hprops[CBM_SZ_512]; - char esc_h[CBM_SZ_256]; + char esc_h[CBM_SZ_512]; cbm_json_escape(esc_h, sizeof(esc_h), def->qualified_name); snprintf(hprops, sizeof(hprops), "{\"handler\":\"%s\"}", esc_h); cbm_gbuf_insert_edge(ws->local_gbuf, func_id, route_id, "HANDLES", hprops); @@ -1279,18 +1279,23 @@ static void emit_route_registration(cbm_gbuf_t *gbuf, const cbm_gbuf_node_t *sou char rp[CBM_SZ_256]; snprintf(rp, sizeof(rp), "{\"method\":\"%s\"}", method ? method : "ANY"); int64_t rid = cbm_gbuf_upsert_node(gbuf, "Route", route_path, rqn, "", 0, 0, rp); - char props[CBM_SZ_512]; + char esc_cn[CBM_SZ_256]; /* sliced source text: escape quotes/newlines */ + char esc_rp[CBM_SZ_512]; + cbm_json_escape(esc_cn, sizeof(esc_cn), call->callee_name); + cbm_json_escape(esc_rp, sizeof(esc_rp), route_path); + char props[CBM_SZ_1K]; snprintf(props, sizeof(props), - "{\"callee\":\"%s\",\"url_path\":\"%s\",\"via\":\"route_registration\"}", - call->callee_name, route_path); + "{\"callee\":\"%s\",\"url_path\":\"%s\",\"via\":\"route_registration\"}", esc_cn, + esc_rp); cbm_gbuf_insert_edge(gbuf, source->id, rid, "CALLS", props); if (handler_ref && handler_ref[0] != '\0') { cbm_resolution_t hres = cbm_registry_resolve(registry, handler_ref, module_qn, ik, iv, ic); if (hres.qualified_name && hres.qualified_name[0] != '\0') { const cbm_gbuf_node_t *h = cbm_gbuf_find_by_qn(main_gbuf, hres.qualified_name); if (h) { - char hp[CBM_SZ_256]; - char esc_h2[CBM_SZ_256]; + char hp[CBM_SZ_1K]; /* must exceed escaped value + wrapper or snprintf cuts the + closing brace */ + char esc_h2[CBM_SZ_512]; cbm_json_escape(esc_h2, sizeof(esc_h2), hres.qualified_name); snprintf(hp, sizeof(hp), "{\"handler\":\"%s\"}", esc_h2); cbm_gbuf_insert_edge(gbuf, h->id, rid, "HANDLES", hp); diff --git a/src/pipeline/pass_route_nodes.c b/src/pipeline/pass_route_nodes.c index fdf31131e..b543aaaa2 100644 --- a/src/pipeline/pass_route_nodes.c +++ b/src/pipeline/pass_route_nodes.c @@ -16,6 +16,7 @@ */ #include "foundation/constants.h" #include "foundation/str_util.h" // cbm_json_escape +#include // validate assembled DATA_FLOWS props enum { RN_MAX_SCHEME = 12, @@ -610,6 +611,19 @@ static int try_create_data_flow(cbm_gbuf_t *gb, int64_t caller_id, int64_t handl if (n > 0 && (size_t)n < sizeof(props) - RN_PROPS_MARGIN) { finish_data_flow_props(props, sizeof(props), (size_t)n, handler_params, args_json); } + /* handler_params/args_json are sliced text fragments; truncation or stray + * quotes can leave the assembled JSON malformed, which aborts every + * json_extract consumer downstream. Validate and fall back to the minimal + * envelope rather than persisting invalid properties. */ + { + yyjson_doc *vdoc = yyjson_read(props, strlen(props), 0); + if (!vdoc) { + snprintf(props, sizeof(props), "{\"via\":\"%s\",\"edge_type\":\"%s\"}", esc_rname, + edge_type); + } else { + yyjson_doc_free(vdoc); + } + } cbm_gbuf_insert_edge(gb, caller_id, handler_id, "DATA_FLOWS", props); return SKIP_ONE; }