Cross-join pattern-with-rels into existing bindings */
| 4200 | |
| 4201 | /* Cross-join pattern-with-rels into existing bindings */ |
| 4202 | static void cross_join_with_rels(cbm_store_t *store, cbm_pattern_t *patn, binding_t **bindings, |
| 4203 | int *bind_count, cbm_node_t *extra_nodes, int extra_count, |
| 4204 | const char *nvar, bool opt) { |
| 4205 | /* size_t arithmetic: bind_count * extra_count can exceed INT_MAX on large |
| 4206 | * graphs (e.g. an unbound `c` scanned against ~29 K `f` bindings), wrapping |
| 4207 | * the int product negative and yielding a tiny/garbage malloc → heap OOB |
| 4208 | * write → SIGSEGV/SIGABRT (#627). */ |
| 4209 | size_t alloc_n = (size_t)*bind_count * (size_t)extra_count * (size_t)CYP_GROWTH_10 + SKIP_ONE; |
| 4210 | binding_t *new_bindings = malloc(alloc_n * sizeof(binding_t)); |
| 4211 | if (!new_bindings) { |
| 4212 | return; /* OOM: leave existing bindings untouched rather than corrupt */ |
| 4213 | } |
| 4214 | int new_count = 0; |
| 4215 | for (int bi = 0; bi < *bind_count; bi++) { |
| 4216 | for (int ni = 0; ni < extra_count; ni++) { |
| 4217 | binding_t nb = {0}; |
| 4218 | binding_copy(&nb, &(*bindings)[bi]); |
| 4219 | binding_set(&nb, nvar, &extra_nodes[ni]); |
| 4220 | binding_t *tmp = malloc(PAIR_LEN * sizeof(binding_t)); |
| 4221 | tmp[0] = nb; |
| 4222 | int tc = SKIP_ONE; |
| 4223 | int tcap = SKIP_ONE; |
| 4224 | const char *tv = nvar; |
| 4225 | expand_pattern_rels(store, patn, &tmp, &tc, &tcap, &tv, opt); |
| 4226 | for (int ti = 0; ti < tc; ti++) { |
| 4227 | new_bindings[new_count++] = tmp[ti]; |
| 4228 | } |
| 4229 | free(tmp); |
| 4230 | } |
| 4231 | if (opt && extra_count == 0) { |
| 4232 | binding_t nb = {0}; |
| 4233 | binding_copy(&nb, &(*bindings)[bi]); |
| 4234 | new_bindings[new_count++] = nb; |
| 4235 | } |
| 4236 | } |
| 4237 | for (int bi = 0; bi < *bind_count; bi++) { |
| 4238 | binding_free(&(*bindings)[bi]); |
| 4239 | } |
| 4240 | free(*bindings); |
| 4241 | *bindings = new_bindings; |
| 4242 | *bind_count = new_count; |
| 4243 | } |
| 4244 | |
| 4245 | /* Drive a single-relationship additional pattern from its ALREADY-BOUND |
| 4246 | * terminal node, binding the unbound START var to the edge's other endpoint. |
no test coverage detected