| 650 | #endif /* _WIN32 */ |
| 651 | |
| 652 | int main(int argc, char **argv) { |
| 653 | /* Defense-in-depth: bind tree-sitter and sqlite3 to mimalloc so a |
| 654 | * correct binary does not rely on the fragile MI_OVERRIDE symbol override |
| 655 | * (#424). MUST be the VERY FIRST statement: SQLITE_CONFIG_MALLOC has to run |
| 656 | * before the first sqlite3_open* (cbm_mcp_server_new → cbm_store_open_memory |
| 657 | * below opens sqlite early), else sqlite3_config returns SQLITE_MISUSE and |
| 658 | * the bind is silently ignored. No-op in the test build. */ |
| 659 | cbm_alloc_init(); |
| 660 | #ifdef _WIN32 |
| 661 | /* Replace the ANSI-code-page argv the CRT handed us with a UTF-8 argv rebuilt from |
| 662 | * the wide command line, so non-ASCII CLI arguments survive (#423/#20). Falls back |
| 663 | * to the original argv if the wide rebuild fails. Done after cbm_alloc_init (which |
| 664 | * must stay the very first statement) but before argv is first read below. */ |
| 665 | { |
| 666 | int win_argc = 0; |
| 667 | char **win_argv = cbm_win_utf8_argv(&win_argc); |
| 668 | if (win_argv) { |
| 669 | argc = win_argc; |
| 670 | argv = win_argv; |
| 671 | } |
| 672 | } |
| 673 | #endif |
| 674 | /* #845: mark this process as the REAL binary so the index supervisor may |
| 675 | * wrap index_repository in a worker subprocess. Must run before any |
| 676 | * subcommand dispatch so MCP-server, CLI, and HTTP paths are all covered. |
| 677 | * Embedders of cbm_mcp_handle_tool (test binaries) never mark themselves, |
| 678 | * so they index in-process instead of re-invoking themselves as |
| 679 | * `<self> cli --index-worker …` (recursive suite re-runs / spawn chains). */ |
| 680 | cbm_index_supervisor_mark_host(); |
| 681 | cbm_cli_set_version(CBM_VERSION); |
| 682 | cbm_profile_init(); /* reads CBM_PROFILE env var, gates all prof macros */ |
| 683 | /* CBM_LOG_LEVEL support — distilled from #414 (closes #413). Apply before |
| 684 | * the first log statement so the configured level governs all output. */ |
| 685 | cbm_log_init_from_env(); |
| 686 | int subcmd = handle_subcommand(argc, argv); |
| 687 | if (subcmd >= 0) { |
| 688 | return subcmd; |
| 689 | } |
| 690 | |
| 691 | /* parent-death watchdog — distilled from #407 (fixes #406). Start it early so |
| 692 | * an orphaned server exits even if it dies before reaching the MCP loop. A |
| 693 | * thread-create failure (or ppid<=1) is non-fatal: the server still runs, it |
| 694 | * just won't auto-exit on parent death — same policy as the watcher/HTTP |
| 695 | * threads below. We deliberately do NOT exit at startup when ppid<=1 (the PR's |
| 696 | * original behaviour): a legitimately-launched server can transiently show |
| 697 | * ppid==1 (early reparent races, double-fork/container launchers), and the |
| 698 | * watchdog already no-ops safely in that case via its initial_ppid>1 guard. */ |
| 699 | #ifndef _WIN32 |
| 700 | /* main() outlives the watchdog (it joins before returning), so a stack |
| 701 | * local is a valid lifetime for the thread's argument. */ |
| 702 | pid_t initial_ppid = getppid(); |
| 703 | cbm_thread_t parent_watchdog_tid; |
| 704 | bool parent_watchdog_started = false; |
| 705 | if (cbm_thread_create(&parent_watchdog_tid, PARENT_WATCHDOG_STACK_SIZE, parent_watchdog_thread, |
| 706 | &initial_ppid) == 0) { |
| 707 | parent_watchdog_started = true; |
| 708 | } else { |
| 709 | cbm_log_warn("parent.watchdog.unavailable", "reason", "thread_create_failed"); |
nothing calls this directly
no test coverage detected