Child body: builds the store and runs the layout so a crash or hang cannot * take down the runner (alarm bounds a hang, fork isolates a SIGSEGV). * Deliberately NO memory rlimit: under a rlimit a failing calloc makes * octree_insert silently truncate and the UNFIXED code would complete — * turning this guard vacuously green. The alarm alone bounds the runaway. * Exit codes: 0 ok, 2 store setu
| 759 | * Exit codes: 0 ok, 2 store setup, 3 layout NULL, 4 node count/lookup, |
| 760 | * 5 fixture no longer coincident, 6 non-finite coordinate. Never returns. */ |
| 761 | static void layout_octree_guard_child(void) { |
| 762 | alarm(5); /* post-fix the whole child runs in milliseconds */ |
| 763 | cbm_store_t *store = cbm_store_open_memory(); |
| 764 | if (!store) |
| 765 | _exit(2); |
| 766 | if (cbm_store_upsert_project(store, "test", "/tmp/test") != CBM_STORE_OK) |
| 767 | _exit(2); |
| 768 | |
| 769 | /* Distinct QNs, one fnv1a hash — coincident after anchor + jitter. */ |
| 770 | static const char *cqn[3] = {"test::octree_c5988474", "test::octree_c11394919", |
| 771 | "test::octree_c33141700"}; |
| 772 | for (int i = 0; i < 3; i++) { |
| 773 | char name[32]; |
| 774 | snprintf(name, sizeof(name), "co%d", i); |
| 775 | cbm_node_t n = {.project = "test", |
| 776 | .label = "Function", |
| 777 | .name = name, |
| 778 | .qualified_name = cqn[i], |
| 779 | .file_path = "pkg/sub/mod/a.c", |
| 780 | .start_line = i + 1, |
| 781 | .end_line = i + 2}; |
| 782 | if (cbm_store_upsert_node(store, &n) <= 0) |
| 783 | _exit(2); |
| 784 | } |
| 785 | /* A few normally-spread nodes so the octree root box has realistic |
| 786 | * (non-degenerate) extent, as in the reported repositories. */ |
| 787 | for (int i = 0; i < 3; i++) { |
| 788 | char name[32], qn[64], fp[32]; |
| 789 | snprintf(name, sizeof(name), "fn%d", i); |
| 790 | snprintf(qn, sizeof(qn), "test::spread_fn%d", i); |
| 791 | snprintf(fp, sizeof(fp), "dir%d/f%d.c", i, i); |
| 792 | cbm_node_t n = {.project = "test", |
| 793 | .label = "Function", |
| 794 | .name = name, |
| 795 | .qualified_name = qn, |
| 796 | .file_path = fp, |
| 797 | .start_line = 1, |
| 798 | .end_line = 2}; |
| 799 | if (cbm_store_upsert_node(store, &n) <= 0) |
| 800 | _exit(2); |
| 801 | } |
| 802 | |
| 803 | cbm_layout_result_t *r = cbm_layout_compute(store, "test", CBM_LAYOUT_OVERVIEW, NULL, 0, 100); |
| 804 | if (!r) |
| 805 | _exit(3); |
| 806 | if (r->node_count != 6) |
| 807 | _exit(4); |
| 808 | |
| 809 | /* The colliding QNs must actually be coincident — identical output |
| 810 | * coordinates (identical seeds → identical positions, and coincident |
| 811 | * bodies receive identical forces every iteration, so they stay |
| 812 | * together). If a seeding change ever breaks this, the fixture no longer |
| 813 | * reproduces the bug: fail loudly instead of going vacuously green. */ |
| 814 | int ci[3], nc = 0; |
| 815 | for (int i = 0; i < r->node_count && nc < 3; i++) { |
| 816 | if (r->nodes[i].qualified_name && |
| 817 | strncmp(r->nodes[i].qualified_name, "test::octree_c", 14) == 0) |
| 818 | ci[nc++] = i; |
no test coverage detected