@@ -3434,12 +3434,13 @@ static char *handle_cross_project_links(cbm_mcp_server_t *srv, const char *args)
34343434 sqlite3_bind_text (stmt , bind_idx ++ , identifier , -1 , SQLITE_STATIC );
34353435 }
34363436
3437- /* Format output */
3438- enum { XL_BUF_SIZE = 65536 };
3439- char * buf = malloc (XL_BUF_SIZE );
3437+ /* Format output — reserve 128 bytes at start for header (filled after loop) */
3438+ enum { XL_HDR_RESERVE = 128 };
3439+ int buf_cap = 65536 ;
3440+ char * buf = malloc ((size_t )buf_cap );
34403441 if (!buf ) { sqlite3_finalize (stmt ); sqlite3_close (db );
34413442 return cbm_mcp_text_result ("alloc failed" , true); }
3442- int pos = 0 ;
3443+ int pos = XL_HDR_RESERVE ; /* start writing after header reservation */
34433444 int total = 0 ;
34443445 char cur_protocol [64 ] = {0 };
34453446 int proto_count = 0 ;
@@ -3455,26 +3456,33 @@ static char *handle_cross_project_links(cbm_mcp_server_t *srv, const char *args)
34553456 const char * fcons = (const char * )sqlite3_column_text (stmt , MCP_COL_7 );
34563457 double conf = sqlite3_column_double (stmt , 8 );
34573458
3459+ /* Grow buffer if needed (each entry is ~300 bytes max) */
3460+ if (pos + 512 > buf_cap ) {
3461+ int new_cap = buf_cap * 2 ;
3462+ char * new_buf = realloc (buf , (size_t )new_cap );
3463+ if (!new_buf ) break ; /* return what we have so far */
3464+ buf = new_buf ;
3465+ buf_cap = new_cap ;
3466+ }
3467+
34583468 /* Protocol header */
34593469 if (strcmp (cur_protocol , proto ? proto : "" ) != 0 ) {
34603470 if (proto_count > 0 ) {
3461- pos += snprintf (buf + pos , XL_BUF_SIZE - (size_t )pos , "\n" );
3471+ pos += snprintf (buf + pos , (size_t )( buf_cap - pos ) , "\n" );
34623472 }
34633473 snprintf (cur_protocol , sizeof (cur_protocol ), "%s" , proto ? proto : "" );
3464- pos += snprintf (buf + pos , XL_BUF_SIZE - (size_t )pos , "## %s\n\n" , proto );
3474+ pos += snprintf (buf + pos , (size_t )( buf_cap - pos ) , "## %s\n\n" , proto );
34653475 proto_count ++ ;
34663476 }
34673477
3468- pos += snprintf (buf + pos , XL_BUF_SIZE - (size_t )pos ,
3478+ pos += snprintf (buf + pos , (size_t )( buf_cap - pos ) ,
34693479 "%s (confidence: %.2f)\n"
34703480 " producer: %s :: %s (%s)\n"
34713481 " consumer: %s :: %s (%s)\n\n" ,
34723482 ident ? ident : "" , conf ,
34733483 pprod ? pprod : "" , qprod ? qprod : "" , fprod ? fprod : "" ,
34743484 pcons ? pcons : "" , qcons ? qcons : "" , fcons ? fcons : "" );
34753485 total ++ ;
3476-
3477- if (pos > 58000 ) break ; /* safety limit — leave headroom for header prepend */
34783486 }
34793487
34803488 sqlite3_finalize (stmt );
@@ -3486,13 +3494,14 @@ static char *handle_cross_project_links(cbm_mcp_server_t *srv, const char *args)
34863494 "No cross-project links found. Index at least 2 projects first." , false);
34873495 }
34883496
3489- /* Prepend summary */
3490- char header [128 ];
3491- snprintf (header , sizeof (header ), "# Cross-Project Links (%d total)\n\n" , total );
3492- int hlen = (int )strlen (header );
3493- if (pos + hlen >= XL_BUF_SIZE ) pos = XL_BUF_SIZE - hlen - 1 ;
3494- memmove (buf + hlen , buf , (size_t )pos + 1 );
3497+ /* Fill header in the reserved space, then shift content to close the gap */
3498+ char header [XL_HDR_RESERVE ];
3499+ int hlen = snprintf (header , sizeof (header ), "# Cross-Project Links (%d total)\n\n" , total );
3500+ int gap = XL_HDR_RESERVE - hlen ;
3501+ memmove (buf + hlen , buf + XL_HDR_RESERVE , (size_t )(pos - XL_HDR_RESERVE ) + 1 );
34953502 memcpy (buf , header , (size_t )hlen );
3503+ pos -= gap ;
3504+ buf [pos ] = '\0' ;
34963505
34973506 char * result = cbm_mcp_text_result (buf , false);
34983507 free (buf );
0 commit comments