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