Add a bunch of overflow checks around malloc()
[clav.git] / quiver.c
blob24392e24730bf74c98c79e4c7263ed61bc83a8e8
1 /*
2 * Copyright (c) 2017, S. Gilles <sgilles@math.umd.edu>
4 * Permission to use, copy, modify, and/or distribute this software
5 * for any purpose with or without fee is hereby granted, provided
6 * that the above copyright notice and this permission notice appear
7 * in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
13 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
14 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
15 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 #include <errno.h>
19 #include <stddef.h>
20 #include <stdint.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
25 #include "macros.h"
26 #include "quiver.h"
28 #define MAX_SUPPORTED_EDGE_NUM (((size_t) -1) >> 2)
29 #define MAX_SUPPORTED_VERTEX_NUM (((size_t) -1) >> 2)
31 /* Primes for reducing fractions */
32 static uint32_t primes[] = {
33 /* */
34 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67,
35 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139,
36 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223,
37 227, 229, 233, 239, 241, 251
40 /* GCD */
41 static int gcd(uint_fast8_t x, uint_fast8_t y)
43 uint_fast8_t r = 0;
45 if (!x &&
46 !y) {
47 return 1;
50 while (y) {
51 r = x % y;
52 x = y;
53 y = r;
56 return x;
59 /* Attempt to store a fraction in out, reducing if possible */
60 static int reduce_fraction(int_fast32_t n, uint_fast32_t d, struct
61 rational *out, const char **out_errstr)
63 if (!n &&
64 d) {
65 *out = (struct rational) { .p = 0, .q = 1 };
67 return 0;
70 /* We special-case 1-3 since, in those cases, this actually needs to go fast */
71 if (d == 1) {
72 goto calculated;
73 } else if (d == 2) {
74 if (n % 2) {
75 } else {
76 n /= 2;
77 d = 1;
80 goto calculated;
81 } else if (d == 3) {
82 if (n % 3) {
83 } else {
84 n /= 3;
85 d = 1;
88 goto calculated;
91 for (size_t j = 0; j < ((sizeof primes) / (sizeof primes[0])); ++j) {
92 uint32_t p = primes[j];
94 if (j &&
95 p > d) {
96 break;
99 while (n % p == 0 &&
100 d % p == 0) {
101 n = n / p;
102 d = d / p;
106 calculated:
108 if (n > INT_FAST8_MAX ||
109 n < INT_FAST8_MIN ||
110 d == 0 ||
111 d > UINT_FAST8_MAX) {
112 IF_NZ_SET(out_errstr, L("unrepresentable fraction"));
114 return EDOM;
117 *out = (struct rational) { .p = n, .q = d };
119 return 0;
122 /* out += a/b */
123 static int add_to_fraction(int_fast8_t a, uint_fast8_t b, struct rational *out,
124 const char **out_errstr)
126 int_fast32_t n = a * out->q + out->p * b;
127 uint_fast32_t d = b * out->q;
129 return reduce_fraction(n, d, out, out_errstr);
132 /* Add an arrow of weight a/b from i -> j, affecting e(i,j) and e(j,i) */
133 int quiver_add_to_edge(struct quiver *q, size_t i, size_t j, int_fast8_t a,
134 uint_fast8_t b, const char **out_errstr)
136 int ret = 0;
138 if (!q) {
139 IF_NZ_SET(out_errstr, L("nonexistant quiver"));
141 return EINVAL;
144 if (i >= q->v_num ||
145 j >= q->v_num) {
146 IF_NZ_SET(out_errstr, L("edge includes nonexistant vertex"));
148 return EINVAL;
151 if (i == j) {
152 IF_NZ_SET(out_errstr, L("loops are not allowed"));
154 return EINVAL;
157 struct rational *eij = &(q->e[i * q->v_len + j]);
158 struct rational *eji = &(q->e[j * q->v_len + i]);
159 uint_fast8_t d = gcd(q->v[i].fatness, q->v[j].fatness);
161 if ((ret = add_to_fraction(a * q->v[j].fatness, b * d, eij,
162 out_errstr))) {
163 return ret;
166 if ((ret = add_to_fraction(-1 * a * q->v[i].fatness, b * d, eji,
167 out_errstr))) {
168 return ret;
171 return 0;
174 /* Add a vertex with a name and weight */
175 int quiver_add_vertex(struct quiver *q, size_t *out_i, const char *name,
176 uint_fast16_t fatness, int x, int y, const
177 char **out_errstr)
179 void *newmem = 0;
180 char *newname;
181 size_t len = 0;
183 if (!q) {
184 IF_NZ_SET(out_errstr, L("invalid quiver"));
186 return EINVAL;
189 if (!name) {
190 len = snprintf(0, 0, "%zu", q->v_num);
192 if (len + 1 < len) {
193 IF_NZ_SET(out_errstr, L("overflow"));
195 return EOVERFLOW;
198 if (!(newname = malloc(len + 1))) {
199 int sv_err = errno;
201 IF_NZ_SET(out_errstr, L("malloc"));
203 return sv_err;
206 sprintf(newname, "%zu", q->v_num);
207 } else {
209 * Should be no need to check overflow, either name
210 * was malloc'd, or came from a file which was read
211 * in with a length cap.
213 if (!(newname = malloc(strlen(name) + 1))) {
214 int sv_err = errno;
216 IF_NZ_SET(out_errstr, L("malloc"));
218 return sv_err;
221 strcpy(newname, name);
224 if (q->v_num >= q->v_len) {
225 size_t newlen = q->v_len + 8;
227 if (newlen >= ((size_t) -1) / newlen ||
228 (newlen * newlen) / newlen != newlen) {
229 IF_NZ_SET(out_errstr, L("too many vertices"));
231 return EDOM;
234 if (!(newmem = calloc(newlen * newlen, sizeof (*q->e)))) {
235 int sv_err = errno;
237 IF_NZ_SET(out_errstr, L("too many vertices"));
239 return sv_err;
242 for (size_t j = 0; j < q->v_num; ++j) {
243 for (size_t k = 0; k < q->v_num; ++k) {
244 ((struct rational *) newmem)[j * newlen + k] =
245 q->e[j * q->v_len + k];
248 for (size_t k = q->v_num; k < newlen; ++k) {
249 ((struct rational *) newmem)[j * newlen + k] =
250 (struct rational) { .p = 0, .q = 1 };
254 for (size_t j = q->v_num; j < newlen; ++j) {
255 for (size_t k = 0; k < newlen; ++k) {
256 ((struct rational *) newmem)[j * newlen + k] =
257 (struct rational) { .p = 0, .q = 1 };
261 if (q->e) {
262 free(q->e);
265 q->e = newmem;
267 if (!(newmem = (realloc(q->v, newlen * sizeof (*q->v))))) {
268 int sv_err = errno;
270 IF_NZ_SET(out_errstr, L("too many vertices"));
272 return sv_err;
275 q->v = newmem;
276 q->v_len = newlen;
279 for (size_t k = 0; k <= q->v_num; ++k) {
280 q->e[k * q->v_len + q->v_num] = (struct rational) { .p = 0, .q =
281 1 };
282 q->e[q->v_num * q->v_len + k] = (struct rational) { .p = 0, .q =
283 1 };
286 q->v[q->v_num] = (struct vertex) { .name = newname, .fatness = fatness,
287 .x = x, .y = y };
289 if (out_i) {
290 *out_i = q->v_num;
293 q->v_num++;
295 return 0;
298 /* Increase or decrease the fatness of a vertex, readjusting edges as well */
299 int quiver_adjust_fatness(struct quiver *q, size_t i, int_fast8_t fatness_adj,
300 const char **out_errstr)
302 int ret = 0;
304 if (i >= q->v_num) {
305 IF_NZ_SET(out_errstr, L("invalid vertex"));
307 return EINVAL;
310 int new_fatness = q->v[i].fatness + fatness_adj;
312 if (new_fatness <= 0 ||
313 new_fatness > UINT_FAST8_MAX) {
314 IF_NZ_SET(out_errstr, L("invalid new fatness"));
316 return EINVAL;
319 for (size_t j = 0; j < q->v_num; ++j) {
320 if (i == j) {
321 continue;
324 uint_fast8_t d_orig = gcd(q->v[i].fatness, q->v[j].fatness);
325 uint_fast8_t d_new = gcd(new_fatness, q->v[j].fatness);
326 size_t k = i * q->v_len + j;
328 if ((ret = reduce_fraction(q->e[k].p * d_orig, q->e[k].q *
329 d_new, &(q->e[k]), out_errstr))) {
330 return ret;
333 k = j * q->v_len + i;
335 if ((ret = reduce_fraction(q->e[k].p * d_orig * q->v[i].fatness,
336 q->e[k].q * d_new * new_fatness,
337 &(q->e[k]), out_errstr))) {
338 return ret;
342 q->v[i].fatness = new_fatness;
344 return ret;
347 /* Free all memory used by this quiver, resetting it to { 0 } */
348 int quiver_clean(struct quiver *q)
350 if (!q) {
351 return 0;
354 for (size_t j = 0; j < q->v_num; ++j) {
355 free(q->v[j].name);
358 free(q->v);
359 free(q->e);
360 *q = (struct quiver) { 0 };
362 return 0;
365 /* Delete a vertex (and all associated edges) */
366 int quiver_delete_vertex(struct quiver *q, size_t i, const char **out_errstr)
368 if (i >= q->v_num) {
369 IF_NZ_SET(out_errstr, L("invalid vertex"));
371 return EINVAL;
374 if (q->v_num == 1) {
375 q->v_num = 0;
376 free(q->v[0].name);
377 q->v[0].name = 0;
379 return 0;
382 /* First, shift everything over to the left */
383 for (size_t j = 0; j < q->v_num; ++j) {
384 for (size_t k = i + 1; k < q->v_num; ++k) {
385 q->e[q->v_len * j + k - 1] = q->e[q->v_len * j + k];
389 /* Second, shift everything below row i up */
390 for (size_t j = i + 1; j < q->v_num; ++j) {
391 for (size_t k = 0; k < q->v_num; ++k) {
392 q->e[q->v_len * (j - 1) + k] = q->e[q->v_len * j + k];
396 /* Now shift the vertex names/lengths over */
397 free(q->v[i].name);
398 q->v[i].name = 0;
400 for (size_t j = i + 1; j < q->v_num; ++j) {
401 q->v[j - 1] = q->v[j];
404 q->v_num--;
405 q->v[q->v_num] = (struct vertex) { 0 };
407 return 0;
410 /* Read quiver from file */
411 int quiver_load_from_file(struct quiver *q, FILE *f, const char **out_errstr)
413 if (!q) {
414 IF_NZ_SET(out_errstr, L("invalid quiver"));
416 return EINVAL;
419 int ret = 0;
421 for (size_t k = 0; k < q->v_num; ++k) {
422 struct vertex *v = &(q->v[k]);
424 free(v->name);
425 v->name = 0;
428 q->v_num = 0;
429 size_t new_vnum = 0;
430 char *p = 0;
432 if (fscanf(f, "%zu Vertices\n", &new_vnum) != 1) {
433 IF_NZ_SET(out_errstr, L("Invalid file (|V| unspecified)"));
435 return EINVAL;
438 for (size_t k = 0; k < new_vnum; ++k) {
439 size_t j = 0;
440 size_t fatness = 0;
441 int x = 0;
442 int y = 0;
443 size_t len = 0;
445 if (fscanf(f, " v[%zu] f:%zu x:%d y:%d l:%zu n:", &j, &fatness,
446 &x, &y, &len) != 5) {
447 IF_NZ_SET(out_errstr, L("Invalid file"));
449 return EINVAL;
450 } else if (j != k) {
451 IF_NZ_SET(out_errstr, L(
452 "Invalid file (vertices out of order)"));
454 return EINVAL;
455 } else if (fatness >= UINT_FAST16_MAX) {
456 IF_NZ_SET(out_errstr, L(
457 "Invalid file (fatness unsupported)"));
459 return EINVAL;
462 if (p) {
463 free(p);
464 p = 0;
467 if (!len) {
468 IF_NZ_SET(out_errstr, L(
469 "Invalid file (nameless vertex)"));
471 return EINVAL;
474 if (len > 1024) {
475 IF_NZ_SET(out_errstr, L(
476 "Invalid file (vertex with name too large)"));
478 return EINVAL;
481 if (!(p = malloc(len + 1))) {
482 ret = errno;
483 perror(L("malloc"));
484 IF_NZ_SET(out_errstr, L("malloc error"));
486 return ret;
489 if (fread(p, sizeof *p, len, f) != (sizeof *p) * len) {
490 IF_NZ_SET(out_errstr, L(
491 "Invalid file (short vertex name)"));
493 return EINVAL;
496 p[len] = '\0';
498 if ((ret = quiver_add_vertex(q, 0, p, (uint_fast16_t) fatness,
499 x, y, out_errstr))) {
500 goto done;
504 while (!feof(f)) {
505 size_t i = 0;
506 size_t j = 0;
507 long n = 0;
508 size_t d = 0;
510 if (fscanf(f, " e[%zu][%zu] %ld/%zu ", &i, &j, &n, &d) != 4) {
511 IF_NZ_SET(out_errstr, L("Invalid file (bad edge)"));
512 ret = EINVAL;
513 goto done;
516 if (i >= q->v_num ||
517 j >= q->v_num) {
518 IF_NZ_SET(out_errstr, L(
519 "Invalid file (edge between nonexistent vertices)"));
520 ret = EINVAL;
521 goto done;
524 struct rational *e = &(q->e[i * q->v_len + j]);
526 if (n <= INT_FAST32_MIN ||
527 n >= INT_FAST32_MAX ||
528 d > UINT_FAST32_MAX) {
529 IF_NZ_SET(out_errstr, L(
530 "Invalid file (edge weight out of range)"));
531 ret = EINVAL;
532 goto done;
535 if ((ret = reduce_fraction((int_fast32_t) n, (uint_fast32_t) d,
536 e, out_errstr))) {
537 goto done;
541 ret = 0;
542 done:
543 free(p);
545 return ret;
548 /* Rename a vertex */
549 int quiver_rename_vertex(struct quiver *q, size_t i, const char *new_name, const
550 char **out_errstr)
552 if (!q) {
553 IF_NZ_SET(out_errstr, L("invalid quiver"));
555 return EINVAL;
558 if (i >= q->v_num) {
559 IF_NZ_SET(out_errstr, L("vertex out of range"));
561 return EINVAL;
564 void *newmem = 0;
565 int ret = 0;
567 if (!(newmem = strdup(new_name))) {
568 ret = errno;
569 IF_NZ_SET(out_errstr, L("cannot strdup()"));
570 goto done;
573 free(q->v[i].name);
574 q->v[i].name = newmem;
575 done:
577 return ret;
580 /* Serialize the quiver */
581 int quiver_save_to_file(struct quiver *q, FILE *f, const char **out_errstr)
583 if (!q) {
584 IF_NZ_SET(out_errstr, L("invalid quiver"));
586 return EINVAL;
589 int ret = 0;
591 if (fprintf(f, "%zu Vertices\n", q->v_num) < 0) {
592 ret = errno;
593 IF_NZ_SET(out_errstr, L("write failed"));
594 goto done;
597 for (size_t k = 0; k < q->v_num; ++k) {
598 struct vertex *v = &(q->v[k]);
600 if (fprintf(f, "v[%zu] f:%zu x:%d y:%d l:%zu n:%s\n", k,
601 (size_t) v->fatness, v->x, v->y, strlen(v->name),
602 v->name) <
603 0) {
604 ret = errno;
605 IF_NZ_SET(out_errstr, L("write failed"));
606 goto done;
610 for (size_t i = 0; i < q->v_num; ++i) {
611 for (size_t j = 0; j < q->v_num; ++j) {
612 struct rational *e = &(q->e[i * q->v_len + j]);
614 if (!e->p) {
615 continue;
618 if (fprintf(f, "e[%zu][%zu] %d/%u\n", i, j, (int) e->p,
619 (unsigned) e->q) < 0) {
620 ret = errno;
621 IF_NZ_SET(out_errstr, L("write failed"));
622 goto done;
627 if (fflush(f)) {
628 ret = errno;
629 IF_NZ_SET(out_errstr, L("flush failed"));
632 done:
634 return ret;
637 /* Set threshold: if quiver_mutate() creates an edge above, warn_out is set */
638 int quiver_set_warning_threshold(struct quiver *q, unsigned int warn_threshold,
639 const char **out_errstr)
641 if (!q) {
642 IF_NZ_SET(out_errstr, L("invalid quiver"));
644 return EINVAL;
647 q->edge_weight_threshold = warn_threshold;
649 return 0;
652 /* Mutate the quiver at vertex k */
653 int quiver_mutate(struct quiver *q, size_t k, int *out_warn, const
654 char **out_errstr)
656 int ret = 0;
658 if (!q) {
659 IF_NZ_SET(out_errstr, L("invalid quiver"));
661 return EINVAL;
664 /* Step one: complete all triangles */
665 for (size_t i = 0; i < q->v_num; ++i) {
666 if (i == k) {
667 continue;
670 struct rational *eik = &(q->e[i * q->v_len + k]);
672 for (size_t j = 0; j < q->v_num; ++j) {
673 if (j == k ||
674 j == i) {
675 continue;
678 struct rational *eij = &(q->e[i * q->v_len + j]);
679 struct rational *ekj = &(q->e[k * q->v_len + j]);
681 if (eik->p * ekj->p <= 0) {
682 continue;
685 if ((ret = add_to_fraction(abs(eik->p) * ekj->p,
686 eik->q * ekj->q, eij,
687 out_errstr))) {
688 return ret;
691 if (out_warn &&
692 q->edge_weight_threshold &&
693 eij->q * q->edge_weight_threshold <= (unsigned
694 int) abs(
695 eij->p)) {
696 *out_warn = 1;
701 /* Step two: invert all edges that touch k */
702 for (size_t i = 0; i < q->v_num; ++i) {
703 if (i == k) {
704 continue;
707 struct rational *eik = &(q->e[i * q->v_len + k]);
708 struct rational *eki = &(q->e[k * q->v_len + i]);
710 eik->p = -eik->p;
711 eki->p = -eki->p;
714 return 0;