Cross-join pattern-with-rels into existing bindings */
| 4588 | |
| 4589 | /* Cross-join pattern-with-rels into existing bindings */ |
| 4590 | static void cross_join_with_rels(cbm_store_t *store, cbm_pattern_t *patn, binding_t **bindings, |
| 4591 | int *bind_count, cbm_node_t *extra_nodes, int extra_count, |
| 4592 | const char *nvar, bool opt) { |
| 4593 | /* size_t arithmetic: bind_count * extra_count can exceed INT_MAX on large |
| 4594 | * graphs (e.g. an unbound `c` scanned against ~29 K `f` bindings), wrapping |
| 4595 | * the int product negative and yielding a tiny/garbage malloc → heap OOB |
| 4596 | * write → SIGSEGV/SIGABRT (#627). */ |
| 4597 | size_t alloc_n = (size_t)*bind_count * (size_t)extra_count * (size_t)CYP_GROWTH_10 + SKIP_ONE; |
| 4598 | binding_t *new_bindings = malloc(alloc_n * sizeof(binding_t)); |
| 4599 | if (!new_bindings) { |
| 4600 | return; /* OOM: leave existing bindings untouched rather than corrupt */ |
| 4601 | } |
| 4602 | int new_count = 0; |
| 4603 | for (int bi = 0; bi < *bind_count; bi++) { |
| 4604 | for (int ni = 0; ni < extra_count; ni++) { |
| 4605 | binding_t nb = {0}; |
| 4606 | binding_copy(&nb, &(*bindings)[bi]); |
| 4607 | binding_set(&nb, nvar, &extra_nodes[ni]); |
| 4608 | binding_t *tmp = malloc(PAIR_LEN * sizeof(binding_t)); |
| 4609 | tmp[0] = nb; |
| 4610 | int tc = SKIP_ONE; |
| 4611 | int tcap = SKIP_ONE; |
| 4612 | const char *tv = nvar; |
| 4613 | expand_pattern_rels(store, patn, &tmp, &tc, &tcap, &tv, opt); |
| 4614 | for (int ti = 0; ti < tc; ti++) { |
| 4615 | new_bindings[new_count++] = tmp[ti]; |
| 4616 | } |
| 4617 | free(tmp); |
| 4618 | } |
| 4619 | if (opt && extra_count == 0) { |
| 4620 | binding_t nb = {0}; |
| 4621 | binding_copy(&nb, &(*bindings)[bi]); |
| 4622 | new_bindings[new_count++] = nb; |
| 4623 | } |
| 4624 | } |
| 4625 | for (int bi = 0; bi < *bind_count; bi++) { |
| 4626 | binding_free(&(*bindings)[bi]); |
| 4627 | } |
| 4628 | free(*bindings); |
| 4629 | *bindings = new_bindings; |
| 4630 | *bind_count = new_count; |
| 4631 | } |
| 4632 | |
| 4633 | /* Drive a single-relationship additional pattern from its ALREADY-BOUND |
| 4634 | * terminal node, binding the unbound START var to the edge's other endpoint. |
no test coverage detected