/home/runner/work/panackelty/panackelty/src/vm/decode.c
Line | Count | Source (jump to first uncovered line) |
1 | | #include "decode.h" |
2 | | |
3 | | #include "program.h" |
4 | | #include "utf8.h" |
5 | | |
6 | | #include <stdlib.h> |
7 | | #include <string.h> |
8 | | |
9 | | /* Bounded version-8 decoding. No runtime values or host operations are created here. */ |
10 | | |
11 | 17.6k | #define MAX_FUNCTIONS 4096u |
12 | 79.1k | #define MAX_INSTRUCTIONS 4000000u |
13 | 4.25M | #define MAX_NAME 1024u |
14 | 347k | #define MAX_TEXT (1024u * 1024u) |
15 | 339k | #define MAX_DIGITS 4096u |
16 | | |
17 | | typedef struct { |
18 | | const uint8_t *data; |
19 | | size_t len, at; |
20 | | const char *error; |
21 | | } Reader; |
22 | | |
23 | | static void fail(Reader *r, const char *message) |
24 | 6.23k | { |
25 | 6.23k | if (!r->error) { Branch (25:9): [True: 5.86k, False: 370]
|
26 | 5.86k | r->error = message; |
27 | 5.86k | } |
28 | 6.23k | } |
29 | | |
30 | | static bool take(Reader *r, size_t n, const uint8_t **out) |
31 | 9.65M | { |
32 | 9.65M | if (n > r->len - r->at) { Branch (32:9): [True: 2.24k, False: 9.65M]
|
33 | 2.24k | fail(r, "truncated data"); |
34 | 2.24k | return false; |
35 | 2.24k | } |
36 | 9.65M | *out = r->data + r->at; |
37 | 9.65M | r->at += n; |
38 | 9.65M | return true; |
39 | 9.65M | } |
40 | | |
41 | | static bool u8(Reader *r, uint8_t *out) |
42 | 4.15M | { |
43 | 4.15M | const uint8_t *p; |
44 | 4.15M | if (!take(r, 1, &p)) { Branch (44:9): [True: 633, False: 4.15M]
|
45 | 633 | return false; |
46 | 633 | } |
47 | 4.15M | *out = p[0]; |
48 | 4.15M | return true; |
49 | 4.15M | } |
50 | | |
51 | | static bool u16(Reader *r, uint16_t *out) |
52 | 2.36M | { |
53 | 2.36M | const uint8_t *p; |
54 | 2.36M | if (!take(r, 2, &p)) { Branch (54:9): [True: 635, False: 2.36M]
|
55 | 635 | return false; |
56 | 635 | } |
57 | 2.36M | *out = (uint16_t)((p[0] << 8) | p[1]); |
58 | 2.36M | return true; |
59 | 2.36M | } |
60 | | |
61 | | static bool u32(Reader *r, uint32_t *out) |
62 | 733k | { |
63 | 733k | const uint8_t *p; |
64 | 733k | if (!take(r, 4, &p)) { Branch (64:9): [True: 313, False: 732k]
|
65 | 313 | return false; |
66 | 313 | } |
67 | 732k | *out = ((uint32_t)p[0] << 24) | ((uint32_t)p[1] << 16) | ((uint32_t)p[2] << 8) | p[3]; |
68 | 732k | return true; |
69 | 733k | } |
70 | | |
71 | | static char *text(Reader *r, bool name) |
72 | 4.59M | { |
73 | 4.59M | uint32_t n32 = 0; |
74 | 4.59M | uint16_t n16 = 0; |
75 | 4.59M | size_t n; |
76 | 4.59M | if (name) { Branch (76:9): [True: 2.12M, False: 173k]
Branch (76:9): [True: 2.12M, False: 173k]
|
77 | 4.25M | if (!u16(r, &n16)) { Branch (77:13): [True: 603, False: 2.12M]
Branch (77:13): [True: 603, False: 2.12M]
|
78 | 1.20k | return NULL; |
79 | 1.20k | } |
80 | 4.25M | n = n16; |
81 | 4.25M | if (n > MAX_NAME) { Branch (81:13): [True: 581, False: 2.12M]
Branch (81:13): [True: 581, False: 2.12M]
|
82 | 1.16k | fail(r, "name exceeds limit"); |
83 | 1.16k | return NULL; |
84 | 1.16k | } |
85 | 4.25M | } else { |
86 | 347k | if (!u32(r, &n32)) { Branch (86:13): [True: 14, False: 173k]
Branch (86:13): [True: 14, False: 173k]
|
87 | 28 | return NULL; |
88 | 28 | } |
89 | 347k | n = n32; |
90 | 347k | if (n > MAX_TEXT) { Branch (90:13): [True: 104, False: 173k]
Branch (90:13): [True: 104, False: 173k]
|
91 | 208 | fail(r, "text exceeds limit"); |
92 | 208 | return NULL; |
93 | 208 | } |
94 | 347k | } |
95 | 4.59M | const uint8_t *p; |
96 | 4.59M | if (!take(r, n, &p)) { Branch (96:9): [True: 568, False: 2.29M]
Branch (96:9): [True: 568, False: 2.29M]
|
97 | 1.13k | return NULL; |
98 | 1.13k | } |
99 | 4.59M | if (!utf8(p, n)) { Branch (99:9): [True: 981, False: 2.29M]
Branch (99:9): [True: 981, False: 2.29M]
|
100 | 1.96k | fail(r, "invalid UTF-8"); |
101 | 1.96k | return NULL; |
102 | 1.96k | } |
103 | 4.59M | char *v = malloc(n + 1); |
104 | 4.59M | if (!v) { Branch (104:9): [True: 28, False: 2.29M]
Branch (104:9): [True: 28, False: 2.29M]
|
105 | 56 | fail(r, "out of memory"); |
106 | 56 | return NULL; |
107 | 56 | } |
108 | 4.59M | memcpy(v, p, n); |
109 | 4.59M | v[n] = 0; |
110 | 4.59M | return v; |
111 | 4.59M | } Line | Count | Source | 72 | 2.29M | { | 73 | 2.29M | uint32_t n32 = 0; | 74 | 2.29M | uint16_t n16 = 0; | 75 | 2.29M | size_t n; | 76 | 2.29M | if (name) { Branch (76:9): [True: 2.12M, False: 173k]
| 77 | 2.12M | if (!u16(r, &n16)) { Branch (77:13): [True: 603, False: 2.12M]
| 78 | 603 | return NULL; | 79 | 603 | } | 80 | 2.12M | n = n16; | 81 | 2.12M | if (n > MAX_NAME) { Branch (81:13): [True: 581, False: 2.12M]
| 82 | 581 | fail(r, "name exceeds limit"); | 83 | 581 | return NULL; | 84 | 581 | } | 85 | 2.12M | } else { | 86 | 173k | if (!u32(r, &n32)) { Branch (86:13): [True: 14, False: 173k]
| 87 | 14 | return NULL; | 88 | 14 | } | 89 | 173k | n = n32; | 90 | 173k | if (n > MAX_TEXT) { Branch (90:13): [True: 104, False: 173k]
| 91 | 104 | fail(r, "text exceeds limit"); | 92 | 104 | return NULL; | 93 | 104 | } | 94 | 173k | } | 95 | 2.29M | const uint8_t *p; | 96 | 2.29M | if (!take(r, n, &p)) { Branch (96:9): [True: 568, False: 2.29M]
| 97 | 568 | return NULL; | 98 | 568 | } | 99 | 2.29M | if (!utf8(p, n)) { Branch (99:9): [True: 981, False: 2.29M]
| 100 | 981 | fail(r, "invalid UTF-8"); | 101 | 981 | return NULL; | 102 | 981 | } | 103 | 2.29M | char *v = malloc(n + 1); | 104 | 2.29M | if (!v) { Branch (104:9): [True: 28, False: 2.29M]
| 105 | 28 | fail(r, "out of memory"); | 106 | 28 | return NULL; | 107 | 28 | } | 108 | 2.29M | memcpy(v, p, n); | 109 | 2.29M | v[n] = 0; | 110 | 2.29M | return v; | 111 | 2.29M | } |
Line | Count | Source | 72 | 2.29M | { | 73 | 2.29M | uint32_t n32 = 0; | 74 | 2.29M | uint16_t n16 = 0; | 75 | 2.29M | size_t n; | 76 | 2.29M | if (name) { Branch (76:9): [True: 2.12M, False: 173k]
| 77 | 2.12M | if (!u16(r, &n16)) { Branch (77:13): [True: 603, False: 2.12M]
| 78 | 603 | return NULL; | 79 | 603 | } | 80 | 2.12M | n = n16; | 81 | 2.12M | if (n > MAX_NAME) { Branch (81:13): [True: 581, False: 2.12M]
| 82 | 581 | fail(r, "name exceeds limit"); | 83 | 581 | return NULL; | 84 | 581 | } | 85 | 2.12M | } else { | 86 | 173k | if (!u32(r, &n32)) { Branch (86:13): [True: 14, False: 173k]
| 87 | 14 | return NULL; | 88 | 14 | } | 89 | 173k | n = n32; | 90 | 173k | if (n > MAX_TEXT) { Branch (90:13): [True: 104, False: 173k]
| 91 | 104 | fail(r, "text exceeds limit"); | 92 | 104 | return NULL; | 93 | 104 | } | 94 | 173k | } | 95 | 2.29M | const uint8_t *p; | 96 | 2.29M | if (!take(r, n, &p)) { Branch (96:9): [True: 568, False: 2.29M]
| 97 | 568 | return NULL; | 98 | 568 | } | 99 | 2.29M | if (!utf8(p, n)) { Branch (99:9): [True: 981, False: 2.29M]
| 100 | 981 | fail(r, "invalid UTF-8"); | 101 | 981 | return NULL; | 102 | 981 | } | 103 | 2.29M | char *v = malloc(n + 1); | 104 | 2.29M | if (!v) { Branch (104:9): [True: 28, False: 2.29M]
| 105 | 28 | fail(r, "out of memory"); | 106 | 28 | return NULL; | 107 | 28 | } | 108 | 2.29M | memcpy(v, p, n); | 109 | 2.29M | v[n] = 0; | 110 | 2.29M | return v; | 111 | 2.29M | } |
|
112 | | |
113 | | static bool read_nat(Reader *r, PnBigInt *out) |
114 | 166k | { |
115 | 166k | uint16_t n; |
116 | 166k | const uint8_t *p; |
117 | 166k | pn_big_init(out); |
118 | 166k | if (!u16(r, &n)) { Branch (118:9): [True: 5, False: 83.1k]
Branch (118:9): [True: 5, False: 83.1k]
|
119 | 10 | return false; |
120 | 10 | } |
121 | 166k | size_t max_bytes = (MAX_DIGITS * 3322u + 7999u) / 8000u; |
122 | 166k | if (n > max_bytes) { Branch (122:9): [True: 34, False: 83.0k]
Branch (122:9): [True: 34, False: 83.0k]
|
123 | 68 | fail(r, "integer exceeds digit limit"); |
124 | 68 | return false; |
125 | 68 | } |
126 | 166k | if (!take(r, n, &p)) { Branch (126:9): [True: 70, False: 83.0k]
Branch (126:9): [True: 70, False: 83.0k]
|
127 | 140 | return false; |
128 | 140 | } |
129 | 166k | if (n && p[0] == 0) { Branch (129:9): [True: 56.1k, False: 26.8k]
Branch (129:14): [True: 3, False: 56.1k]
Branch (129:9): [True: 56.1k, False: 26.8k]
Branch (129:14): [True: 3, False: 56.1k]
|
130 | 6 | fail(r, "non-minimal integer"); |
131 | 6 | return false; |
132 | 6 | } |
133 | 166k | if (!pn_big_from_bytes(out, p, n)) { Branch (133:9): [True: 10, False: 83.0k]
Branch (133:9): [True: 10, False: 83.0k]
|
134 | 20 | fail(r, "out of memory"); |
135 | 20 | return false; |
136 | 20 | } |
137 | 166k | char *digits = pn_big_string(out); |
138 | 166k | if (!digits) { Branch (138:9): [True: 2, False: 83.0k]
Branch (138:9): [True: 2, False: 83.0k]
|
139 | 4 | fail(r, "out of memory"); |
140 | 4 | return false; |
141 | 4 | } |
142 | 166k | if (strlen(digits) > MAX_DIGITS) { Branch (142:9): [True: 0, False: 83.0k]
Branch (142:9): [True: 0, False: 83.0k]
|
143 | 0 | fail(r, "integer exceeds digit limit"); |
144 | 0 | } |
145 | 166k | free(digits); |
146 | 166k | return !r->error; |
147 | 166k | } Line | Count | Source | 114 | 83.1k | { | 115 | 83.1k | uint16_t n; | 116 | 83.1k | const uint8_t *p; | 117 | 83.1k | pn_big_init(out); | 118 | 83.1k | if (!u16(r, &n)) { Branch (118:9): [True: 5, False: 83.1k]
| 119 | 5 | return false; | 120 | 5 | } | 121 | 83.1k | size_t max_bytes = (MAX_DIGITS * 3322u + 7999u) / 8000u; | 122 | 83.1k | if (n > max_bytes) { Branch (122:9): [True: 34, False: 83.0k]
| 123 | 34 | fail(r, "integer exceeds digit limit"); | 124 | 34 | return false; | 125 | 34 | } | 126 | 83.0k | if (!take(r, n, &p)) { Branch (126:9): [True: 70, False: 83.0k]
| 127 | 70 | return false; | 128 | 70 | } | 129 | 83.0k | if (n && p[0] == 0) { Branch (129:9): [True: 56.1k, False: 26.8k]
Branch (129:14): [True: 3, False: 56.1k]
| 130 | 3 | fail(r, "non-minimal integer"); | 131 | 3 | return false; | 132 | 3 | } | 133 | 83.0k | if (!pn_big_from_bytes(out, p, n)) { Branch (133:9): [True: 10, False: 83.0k]
| 134 | 10 | fail(r, "out of memory"); | 135 | 10 | return false; | 136 | 10 | } | 137 | 83.0k | char *digits = pn_big_string(out); | 138 | 83.0k | if (!digits) { Branch (138:9): [True: 2, False: 83.0k]
| 139 | 2 | fail(r, "out of memory"); | 140 | 2 | return false; | 141 | 2 | } | 142 | 83.0k | if (strlen(digits) > MAX_DIGITS) { Branch (142:9): [True: 0, False: 83.0k]
| 143 | 0 | fail(r, "integer exceeds digit limit"); | 144 | 0 | } | 145 | 83.0k | free(digits); | 146 | 83.0k | return !r->error; | 147 | 83.0k | } |
Line | Count | Source | 114 | 83.1k | { | 115 | 83.1k | uint16_t n; | 116 | 83.1k | const uint8_t *p; | 117 | 83.1k | pn_big_init(out); | 118 | 83.1k | if (!u16(r, &n)) { Branch (118:9): [True: 5, False: 83.1k]
| 119 | 5 | return false; | 120 | 5 | } | 121 | 83.1k | size_t max_bytes = (MAX_DIGITS * 3322u + 7999u) / 8000u; | 122 | 83.1k | if (n > max_bytes) { Branch (122:9): [True: 34, False: 83.0k]
| 123 | 34 | fail(r, "integer exceeds digit limit"); | 124 | 34 | return false; | 125 | 34 | } | 126 | 83.0k | if (!take(r, n, &p)) { Branch (126:9): [True: 70, False: 83.0k]
| 127 | 70 | return false; | 128 | 70 | } | 129 | 83.0k | if (n && p[0] == 0) { Branch (129:9): [True: 56.1k, False: 26.8k]
Branch (129:14): [True: 3, False: 56.1k]
| 130 | 3 | fail(r, "non-minimal integer"); | 131 | 3 | return false; | 132 | 3 | } | 133 | 83.0k | if (!pn_big_from_bytes(out, p, n)) { Branch (133:9): [True: 10, False: 83.0k]
| 134 | 10 | fail(r, "out of memory"); | 135 | 10 | return false; | 136 | 10 | } | 137 | 83.0k | char *digits = pn_big_string(out); | 138 | 83.0k | if (!digits) { Branch (138:9): [True: 2, False: 83.0k]
| 139 | 2 | fail(r, "out of memory"); | 140 | 2 | return false; | 141 | 2 | } | 142 | 83.0k | if (strlen(digits) > MAX_DIGITS) { Branch (142:9): [True: 0, False: 83.0k]
| 143 | 0 | fail(r, "integer exceeds digit limit"); | 144 | 0 | } | 145 | 83.0k | free(digits); | 146 | 83.0k | return !r->error; | 147 | 83.0k | } |
|
148 | | |
149 | | static bool read_decimal(Reader *r, Constant *out) |
150 | 7.05k | { |
151 | 7.05k | uint8_t sign; |
152 | 7.05k | uint16_t ex, digits; |
153 | 7.05k | const uint8_t *p; |
154 | 7.05k | if (!u8(r, &sign) || !u16(r, &ex) || !u16(r, &digits)) { Branch (154:9): [True: 1, False: 3.52k]
Branch (154:26): [True: 3, False: 3.52k]
Branch (154:42): [True: 2, False: 3.52k]
Branch (154:9): [True: 1, False: 3.52k]
Branch (154:26): [True: 3, False: 3.52k]
Branch (154:42): [True: 2, False: 3.52k]
|
155 | 12 | return false; |
156 | 12 | } |
157 | 7.04k | out->boolean = sign != 0; |
158 | 7.04k | out->exponent = (int16_t)ex; |
159 | 7.04k | if (sign > 1 || !digits || out->exponent > 4096 || out->exponent < -4096 || Branch (159:9): [True: 11, False: 3.51k]
Branch (159:21): [True: 1, False: 3.51k]
Branch (159:32): [True: 2, False: 3.50k]
Branch (159:56): [True: 4, False: 3.50k]
Branch (159:9): [True: 11, False: 3.51k]
Branch (159:21): [True: 1, False: 3.51k]
Branch (159:32): [True: 2, False: 3.50k]
Branch (159:56): [True: 4, False: 3.50k]
|
160 | 7.04k | digits > MAX_DIGITS) { Branch (160:9): [True: 9, False: 3.49k]
Branch (160:9): [True: 9, False: 3.49k]
|
161 | 54 | fail(r, "invalid decimal"); |
162 | 54 | return false; |
163 | 54 | } |
164 | 6.99k | size_t bytes = (digits + 1) / 2; |
165 | 6.99k | if (!take(r, bytes, &p)) { Branch (165:9): [True: 10, False: 3.48k]
Branch (165:9): [True: 10, False: 3.48k]
|
166 | 20 | return false; |
167 | 20 | } |
168 | 6.97k | char *value = malloc(digits); |
169 | 6.97k | if (!value) { Branch (169:9): [True: 2, False: 3.48k]
Branch (169:9): [True: 2, False: 3.48k]
|
170 | 4 | fail(r, "out of memory"); |
171 | 4 | return false; |
172 | 4 | } |
173 | 56.0k | for (size_t i = 0; i < digits; i++) { Branch (173:24): [True: 24.5k, False: 3.45k]
Branch (173:24): [True: 24.5k, False: 3.45k]
|
174 | 49.1k | uint8_t d = (i & 1) ? p[i / 2] & 15 : p[i / 2] >> 4; Branch (174:21): [True: 10.5k, False: 14.0k]
Branch (174:21): [True: 10.5k, False: 14.0k]
|
175 | 49.1k | if (d > 9) { Branch (175:13): [True: 26, False: 24.5k]
Branch (175:13): [True: 26, False: 24.5k]
|
176 | 52 | free(value); |
177 | 52 | fail(r, "invalid decimal digit"); |
178 | 52 | return false; |
179 | 52 | } |
180 | 49.1k | value[i] = (char)('0' + d); |
181 | 49.1k | } |
182 | 6.91k | if ((digits & 1) && (p[bytes - 1] & 15) != 15) { Branch (182:9): [True: 3.43k, False: 26]
Branch (182:25): [True: 12, False: 3.41k]
Branch (182:9): [True: 3.43k, False: 26]
Branch (182:25): [True: 12, False: 3.41k]
|
183 | 24 | free(value); |
184 | 24 | fail(r, "invalid decimal padding"); |
185 | 24 | return false; |
186 | 24 | } |
187 | 6.89k | if (digits > 1 && value[0] == '0') { Branch (187:9): [True: 3.42k, False: 16]
Branch (187:23): [True: 4, False: 3.42k]
Branch (187:9): [True: 3.42k, False: 16]
Branch (187:23): [True: 4, False: 3.42k]
|
188 | 8 | free(value); |
189 | 8 | fail(r, "non-minimal decimal coefficient"); |
190 | 8 | return false; |
191 | 8 | } |
192 | 6.88k | bool ok = pn_big_from_digits(&out->number, value, digits, sign ? -1 : 1); Branch (192:63): [True: 3.38k, False: 61]
Branch (192:63): [True: 3.38k, False: 61]
|
193 | 6.88k | free(value); |
194 | 6.88k | if (!ok) { Branch (194:9): [True: 2, False: 3.43k]
Branch (194:9): [True: 2, False: 3.43k]
|
195 | 4 | fail(r, "out of memory"); |
196 | 4 | } |
197 | 6.88k | return ok; |
198 | 6.89k | } Line | Count | Source | 150 | 3.52k | { | 151 | 3.52k | uint8_t sign; | 152 | 3.52k | uint16_t ex, digits; | 153 | 3.52k | const uint8_t *p; | 154 | 3.52k | if (!u8(r, &sign) || !u16(r, &ex) || !u16(r, &digits)) { Branch (154:9): [True: 1, False: 3.52k]
Branch (154:26): [True: 3, False: 3.52k]
Branch (154:42): [True: 2, False: 3.52k]
| 155 | 6 | return false; | 156 | 6 | } | 157 | 3.52k | out->boolean = sign != 0; | 158 | 3.52k | out->exponent = (int16_t)ex; | 159 | 3.52k | if (sign > 1 || !digits || out->exponent > 4096 || out->exponent < -4096 || Branch (159:9): [True: 11, False: 3.51k]
Branch (159:21): [True: 1, False: 3.51k]
Branch (159:32): [True: 2, False: 3.50k]
Branch (159:56): [True: 4, False: 3.50k]
| 160 | 3.52k | digits > MAX_DIGITS) { Branch (160:9): [True: 9, False: 3.49k]
| 161 | 27 | fail(r, "invalid decimal"); | 162 | 27 | return false; | 163 | 27 | } | 164 | 3.49k | size_t bytes = (digits + 1) / 2; | 165 | 3.49k | if (!take(r, bytes, &p)) { Branch (165:9): [True: 10, False: 3.48k]
| 166 | 10 | return false; | 167 | 10 | } | 168 | 3.48k | char *value = malloc(digits); | 169 | 3.48k | if (!value) { Branch (169:9): [True: 2, False: 3.48k]
| 170 | 2 | fail(r, "out of memory"); | 171 | 2 | return false; | 172 | 2 | } | 173 | 28.0k | for (size_t i = 0; i < digits; i++) { Branch (173:24): [True: 24.5k, False: 3.45k]
| 174 | 24.5k | uint8_t d = (i & 1) ? p[i / 2] & 15 : p[i / 2] >> 4; Branch (174:21): [True: 10.5k, False: 14.0k]
| 175 | 24.5k | if (d > 9) { Branch (175:13): [True: 26, False: 24.5k]
| 176 | 26 | free(value); | 177 | 26 | fail(r, "invalid decimal digit"); | 178 | 26 | return false; | 179 | 26 | } | 180 | 24.5k | value[i] = (char)('0' + d); | 181 | 24.5k | } | 182 | 3.45k | if ((digits & 1) && (p[bytes - 1] & 15) != 15) { Branch (182:9): [True: 3.43k, False: 26]
Branch (182:25): [True: 12, False: 3.41k]
| 183 | 12 | free(value); | 184 | 12 | fail(r, "invalid decimal padding"); | 185 | 12 | return false; | 186 | 12 | } | 187 | 3.44k | if (digits > 1 && value[0] == '0') { Branch (187:9): [True: 3.42k, False: 16]
Branch (187:23): [True: 4, False: 3.42k]
| 188 | 4 | free(value); | 189 | 4 | fail(r, "non-minimal decimal coefficient"); | 190 | 4 | return false; | 191 | 4 | } | 192 | 3.44k | bool ok = pn_big_from_digits(&out->number, value, digits, sign ? -1 : 1); Branch (192:63): [True: 3.38k, False: 61]
| 193 | 3.44k | free(value); | 194 | 3.44k | if (!ok) { Branch (194:9): [True: 2, False: 3.43k]
| 195 | 2 | fail(r, "out of memory"); | 196 | 2 | } | 197 | 3.44k | return ok; | 198 | 3.44k | } |
Line | Count | Source | 150 | 3.52k | { | 151 | 3.52k | uint8_t sign; | 152 | 3.52k | uint16_t ex, digits; | 153 | 3.52k | const uint8_t *p; | 154 | 3.52k | if (!u8(r, &sign) || !u16(r, &ex) || !u16(r, &digits)) { Branch (154:9): [True: 1, False: 3.52k]
Branch (154:26): [True: 3, False: 3.52k]
Branch (154:42): [True: 2, False: 3.52k]
| 155 | 6 | return false; | 156 | 6 | } | 157 | 3.52k | out->boolean = sign != 0; | 158 | 3.52k | out->exponent = (int16_t)ex; | 159 | 3.52k | if (sign > 1 || !digits || out->exponent > 4096 || out->exponent < -4096 || Branch (159:9): [True: 11, False: 3.51k]
Branch (159:21): [True: 1, False: 3.51k]
Branch (159:32): [True: 2, False: 3.50k]
Branch (159:56): [True: 4, False: 3.50k]
| 160 | 3.52k | digits > MAX_DIGITS) { Branch (160:9): [True: 9, False: 3.49k]
| 161 | 27 | fail(r, "invalid decimal"); | 162 | 27 | return false; | 163 | 27 | } | 164 | 3.49k | size_t bytes = (digits + 1) / 2; | 165 | 3.49k | if (!take(r, bytes, &p)) { Branch (165:9): [True: 10, False: 3.48k]
| 166 | 10 | return false; | 167 | 10 | } | 168 | 3.48k | char *value = malloc(digits); | 169 | 3.48k | if (!value) { Branch (169:9): [True: 2, False: 3.48k]
| 170 | 2 | fail(r, "out of memory"); | 171 | 2 | return false; | 172 | 2 | } | 173 | 28.0k | for (size_t i = 0; i < digits; i++) { Branch (173:24): [True: 24.5k, False: 3.45k]
| 174 | 24.5k | uint8_t d = (i & 1) ? p[i / 2] & 15 : p[i / 2] >> 4; Branch (174:21): [True: 10.5k, False: 14.0k]
| 175 | 24.5k | if (d > 9) { Branch (175:13): [True: 26, False: 24.5k]
| 176 | 26 | free(value); | 177 | 26 | fail(r, "invalid decimal digit"); | 178 | 26 | return false; | 179 | 26 | } | 180 | 24.5k | value[i] = (char)('0' + d); | 181 | 24.5k | } | 182 | 3.45k | if ((digits & 1) && (p[bytes - 1] & 15) != 15) { Branch (182:9): [True: 3.43k, False: 26]
Branch (182:25): [True: 12, False: 3.41k]
| 183 | 12 | free(value); | 184 | 12 | fail(r, "invalid decimal padding"); | 185 | 12 | return false; | 186 | 12 | } | 187 | 3.44k | if (digits > 1 && value[0] == '0') { Branch (187:9): [True: 3.42k, False: 16]
Branch (187:23): [True: 4, False: 3.42k]
| 188 | 4 | free(value); | 189 | 4 | fail(r, "non-minimal decimal coefficient"); | 190 | 4 | return false; | 191 | 4 | } | 192 | 3.44k | bool ok = pn_big_from_digits(&out->number, value, digits, sign ? -1 : 1); Branch (192:63): [True: 3.38k, False: 61]
| 193 | 3.44k | free(value); | 194 | 3.44k | if (!ok) { Branch (194:9): [True: 2, False: 3.43k]
| 195 | 2 | fail(r, "out of memory"); | 196 | 2 | } | 197 | 3.44k | return ok; | 198 | 3.44k | } |
|
199 | | |
200 | | static bool read_constant(Reader *r, Constant *out) |
201 | 454k | { |
202 | 454k | uint8_t sign; |
203 | 454k | memset(out, 0, sizeof(*out)); |
204 | 454k | pn_big_init(&out->number); |
205 | 454k | if (!u8(r, &out->tag)) { Branch (205:9): [True: 9, False: 454k]
|
206 | 9 | return false; |
207 | 9 | } |
208 | 454k | switch (out->tag) { |
209 | 79.5k | case 0: Branch (209:5): [True: 79.5k, False: 374k]
|
210 | 79.5k | return read_nat(r, &out->number); |
211 | 3.56k | case 1: Branch (211:5): [True: 3.56k, False: 450k]
|
212 | 3.56k | if (!u8(r, &sign) || sign > 1) { Branch (212:13): [True: 2, False: 3.56k]
Branch (212:30): [True: 19, False: 3.54k]
|
213 | 21 | fail(r, "invalid integer sign"); |
214 | 21 | return false; |
215 | 21 | } |
216 | 3.54k | if (!read_nat(r, &out->number)) { Branch (216:13): [True: 42, False: 3.50k]
|
217 | 42 | return false; |
218 | 42 | } |
219 | 3.50k | if (sign && pn_big_is_zero(&out->number)) { Branch (219:13): [True: 3.50k, False: 4]
Branch (219:21): [True: 2, False: 3.49k]
|
220 | 2 | fail(r, "negative zero integer"); |
221 | 2 | return false; |
222 | 2 | } |
223 | 3.50k | if (sign) { Branch (223:13): [True: 3.49k, False: 4]
|
224 | 3.49k | out->number.sign = -1; |
225 | 3.49k | } |
226 | 3.50k | return true; |
227 | 3.52k | case 2: Branch (227:5): [True: 3.52k, False: 450k]
|
228 | 3.52k | return read_decimal(r, out); |
229 | 134k | case 3: { Branch (229:5): [True: 134k, False: 319k]
|
230 | 134k | size_t start = r->at; |
231 | 134k | out->text = text(r, false); |
232 | 134k | if (out->text) { Branch (232:13): [True: 134k, False: 116]
|
233 | 134k | out->text_length = r->at - start - 4; |
234 | 134k | } |
235 | 134k | return out->text != NULL; |
236 | 3.50k | } |
237 | 93.5k | case 4: Branch (237:5): [True: 93.5k, False: 360k]
|
238 | 93.5k | if (!u8(r, &sign) || sign > 1) { Branch (238:13): [True: 1, False: 93.5k]
Branch (238:30): [True: 47, False: 93.4k]
|
239 | 48 | fail(r, "invalid Bool constant"); |
240 | 48 | return false; |
241 | 48 | } |
242 | 93.4k | out->boolean = sign != 0; |
243 | 93.4k | return true; |
244 | 138k | case 5: Branch (244:5): [True: 138k, False: 315k]
|
245 | 138k | return true; |
246 | 350 | default: Branch (246:5): [True: 350, False: 453k]
|
247 | 350 | fail(r, "unknown constant tag"); |
248 | 350 | return false; |
249 | 454k | } |
250 | 454k | } |
251 | | |
252 | | static char **strings(Reader *r, uint16_t count, bool names) |
253 | 99.5k | { |
254 | 99.5k | char **items = calloc(count, sizeof(char *)); |
255 | 99.5k | if (count && !items) { Branch (255:9): [True: 49.7k, False: 5]
Branch (255:18): [True: 2, False: 49.7k]
Branch (255:9): [True: 49.7k, False: 5]
Branch (255:18): [True: 2, False: 49.7k]
|
256 | 4 | fail(r, "out of memory"); |
257 | 4 | return NULL; |
258 | 4 | } |
259 | 364k | for (uint16_t i = 0; i < count && !r->error; i++) { Branch (259:26): [True: 132k, False: 49.6k]
Branch (259:39): [True: 132k, False: 168]
Branch (259:26): [True: 132k, False: 49.6k]
Branch (259:39): [True: 132k, False: 168]
|
260 | 265k | items[i] = text(r, names); |
261 | 265k | } |
262 | 99.5k | if (r->error) { Branch (262:9): [True: 285, False: 49.5k]
Branch (262:9): [True: 285, False: 49.5k]
|
263 | 1.31M | for (uint16_t i = 0; i < count; i++) { Branch (263:30): [True: 659k, False: 285]
Branch (263:30): [True: 659k, False: 285]
|
264 | 1.31M | free(items[i]); |
265 | 1.31M | } |
266 | 570 | free(items); |
267 | 570 | return NULL; |
268 | 570 | } |
269 | 99.0k | return items; |
270 | 99.5k | } Line | Count | Source | 253 | 49.7k | { | 254 | 49.7k | char **items = calloc(count, sizeof(char *)); | 255 | 49.7k | if (count && !items) { Branch (255:9): [True: 49.7k, False: 5]
Branch (255:18): [True: 2, False: 49.7k]
| 256 | 2 | fail(r, "out of memory"); | 257 | 2 | return NULL; | 258 | 2 | } | 259 | 182k | for (uint16_t i = 0; i < count && !r->error; i++) { Branch (259:26): [True: 132k, False: 49.6k]
Branch (259:39): [True: 132k, False: 168]
| 260 | 132k | items[i] = text(r, names); | 261 | 132k | } | 262 | 49.7k | if (r->error) { Branch (262:9): [True: 285, False: 49.5k]
| 263 | 659k | for (uint16_t i = 0; i < count; i++) { Branch (263:30): [True: 659k, False: 285]
| 264 | 659k | free(items[i]); | 265 | 659k | } | 266 | 285 | free(items); | 267 | 285 | return NULL; | 268 | 285 | } | 269 | 49.5k | return items; | 270 | 49.7k | } |
Line | Count | Source | 253 | 49.7k | { | 254 | 49.7k | char **items = calloc(count, sizeof(char *)); | 255 | 49.7k | if (count && !items) { Branch (255:9): [True: 49.7k, False: 5]
Branch (255:18): [True: 2, False: 49.7k]
| 256 | 2 | fail(r, "out of memory"); | 257 | 2 | return NULL; | 258 | 2 | } | 259 | 182k | for (uint16_t i = 0; i < count && !r->error; i++) { Branch (259:26): [True: 132k, False: 49.6k]
Branch (259:39): [True: 132k, False: 168]
| 260 | 132k | items[i] = text(r, names); | 261 | 132k | } | 262 | 49.7k | if (r->error) { Branch (262:9): [True: 285, False: 49.5k]
| 263 | 659k | for (uint16_t i = 0; i < count; i++) { Branch (263:30): [True: 659k, False: 285]
| 264 | 659k | free(items[i]); | 265 | 659k | } | 266 | 285 | free(items); | 267 | 285 | return NULL; | 268 | 285 | } | 269 | 49.5k | return items; | 270 | 49.7k | } |
|
271 | | |
272 | | static bool instruction(Reader *r, Instruction *in) |
273 | 3.09M | { |
274 | 3.09M | uint16_t count; |
275 | 3.09M | uint32_t ignored; |
276 | 3.09M | memset(in, 0, sizeof(*in)); |
277 | 3.09M | if (!u8(r, &in->op)) { Branch (277:9): [True: 603, False: 3.09M]
|
278 | 603 | return false; |
279 | 603 | } |
280 | 3.09M | switch (in->op) { |
281 | 454k | case OP_CONST: Branch (281:5): [True: 454k, False: 2.64M]
|
282 | 454k | return read_constant(r, &in->constant); |
283 | 824k | case OP_LOAD: Branch (283:5): [True: 824k, False: 2.27M]
|
284 | 1.18M | case OP_STORE: Branch (284:5): [True: 363k, False: 2.73M]
|
285 | 1.20M | case OP_ITER_INIT: Branch (285:5): [True: 19.9k, False: 3.07M]
|
286 | 1.39M | case OP_FIELD_GET: Branch (286:5): [True: 182k, False: 2.91M]
|
287 | 1.39M | in->name = text(r, true); |
288 | 1.39M | return !r->error; |
289 | 74.6k | case OP_POP: Branch (289:5): [True: 74.6k, False: 3.02M]
|
290 | 78.0k | case OP_MAKE_RANGE: Branch (290:5): [True: 3.47k, False: 3.09M]
|
291 | 107k | case OP_INDEX_GET: Branch (291:5): [True: 29.2k, False: 3.06M]
|
292 | 132k | case OP_MATCH_FAIL: Branch (292:5): [True: 25.4k, False: 3.06M]
|
293 | 169k | case OP_RETURN: Branch (293:5): [True: 36.9k, False: 3.05M]
|
294 | 169k | return true; |
295 | 7 | case OP_AWAIT_VALUE: Branch (295:5): [True: 7, False: 3.09M]
|
296 | 2.15k | case OP_CALL_VALUE: Branch (296:5): [True: 2.14k, False: 3.09M]
|
297 | 2.15k | return u8(r, &in->arity); |
298 | 13.8k | case OP_UNARY: Branch (298:5): [True: 13.8k, False: 3.08M]
|
299 | 13.8k | if (!u8(r, &in->code) || in->code > 1) { Branch (299:13): [True: 2, False: 13.8k]
Branch (299:34): [True: 23, False: 13.8k]
|
300 | 25 | fail(r, "unknown unary operator"); |
301 | 25 | return false; |
302 | 25 | } |
303 | 13.8k | return true; |
304 | 169k | case OP_BINARY: Branch (304:5): [True: 169k, False: 2.92M]
|
305 | 169k | if (!u8(r, &in->code) || in->code > 12) { Branch (305:13): [True: 2, False: 169k]
Branch (305:34): [True: 18, False: 169k]
|
306 | 20 | fail(r, "unknown binary operator"); |
307 | 20 | return false; |
308 | 20 | } |
309 | 169k | return true; |
310 | 25.1k | case OP_MAKE_ARRAY: Branch (310:5): [True: 25.1k, False: 3.06M]
|
311 | 25.1k | if (!u16(r, &count)) { Branch (311:13): [True: 3, False: 25.1k]
|
312 | 3 | return false; |
313 | 3 | } |
314 | 25.1k | in->count = count; |
315 | 25.1k | return true; |
316 | 15.8k | case OP_INTERPOLATE: Branch (316:5): [True: 15.8k, False: 3.07M]
|
317 | 15.8k | if (!u16(r, &count)) { Branch (317:13): [True: 3, False: 15.8k]
|
318 | 3 | return false; |
319 | 3 | } |
320 | 15.8k | in->count = count; |
321 | 15.8k | in->items = strings(r, count, false); |
322 | 15.8k | return !r->error; |
323 | 19.8k | case OP_ITER_NEXT: Branch (323:5): [True: 19.8k, False: 3.07M]
|
324 | 19.8k | in->name = text(r, true); |
325 | 19.8k | in->name2 = text(r, true); |
326 | 19.8k | return in->name && in->name2 && u32(r, &in->target); Branch (326:16): [True: 19.7k, False: 64]
Branch (326:28): [True: 19.6k, False: 56]
Branch (326:41): [True: 19.6k, False: 4]
|
327 | 33.9k | case OP_MAKE_RECORD: Branch (327:5): [True: 33.9k, False: 3.06M]
|
328 | 33.9k | in->name = text(r, true); |
329 | 33.9k | if (!in->name || !u16(r, &count)) { Branch (329:13): [True: 44, False: 33.9k]
Branch (329:26): [True: 2, False: 33.9k]
|
330 | 46 | return false; |
331 | 46 | } |
332 | 33.9k | in->count = count; |
333 | 33.9k | in->items = strings(r, count, true); |
334 | 33.9k | return !r->error; |
335 | 58.7k | case OP_MAKE_VARIANT: Branch (335:5): [True: 58.7k, False: 3.03M]
|
336 | 58.7k | in->name = text(r, true); |
337 | 58.7k | in->name2 = text(r, true); |
338 | 58.7k | if (!in->name || !in->name2 || !u16(r, &count)) { Branch (338:13): [True: 55, False: 58.6k]
Branch (338:26): [True: 50, False: 58.6k]
Branch (338:40): [True: 2, False: 58.6k]
|
339 | 107 | return false; |
340 | 107 | } |
341 | 58.6k | in->count = count; |
342 | 58.6k | return true; |
343 | 97.4k | case OP_MATCH_VARIANT: Branch (343:5): [True: 97.4k, False: 2.99M]
|
344 | 97.4k | in->name = text(r, true); |
345 | 97.4k | return in->name && u32(r, &in->target); Branch (345:16): [True: 97.3k, False: 50]
Branch (345:28): [True: 97.3k, False: 4]
|
346 | 16 | case OP_AWAIT_CALL: Branch (346:5): [True: 16, False: 3.09M]
|
347 | 242k | case OP_CALL: Branch (347:5): [True: 242k, False: 2.85M]
|
348 | 242k | in->name = text(r, true); |
349 | 242k | return in->name && u8(r, &in->arity); Branch (349:16): [True: 242k, False: 74]
Branch (349:28): [True: 242k, False: 1]
|
350 | 154k | case OP_JUMP_FALSE: Branch (350:5): [True: 154k, False: 2.94M]
|
351 | 401k | case OP_JUMP: Branch (351:5): [True: 246k, False: 2.84M]
|
352 | 401k | return u32(r, &in->target); |
353 | 778 | default: Branch (353:5): [True: 778, False: 3.09M]
|
354 | 778 | (void)ignored; |
355 | 778 | fail(r, "unknown bytecode opcode"); |
356 | 778 | return false; |
357 | 3.09M | } |
358 | 3.09M | } |
359 | | |
360 | | bool decode(const uint8_t *data, size_t length, Program *p, const char **error) |
361 | 23.6k | { |
362 | 23.6k | memset(p, 0, sizeof(*p)); |
363 | 23.6k | Reader r = {data, length, 0, NULL}; |
364 | 23.6k | const uint8_t *magic; |
365 | 23.6k | uint16_t version, count; |
366 | 23.6k | if (length > MAX_ARTIFACT) { Branch (366:9): [True: 1, False: 11.8k]
Branch (366:9): [True: 1, False: 11.8k]
|
367 | 2 | *error = "artifact exceeds size limit"; |
368 | 2 | return false; |
369 | 2 | } |
370 | 23.6k | if (!take(&r, 9, &magic) || memcmp(magic, "PANACKBC\0", 9)) { Branch (370:9): [True: 18, False: 11.7k]
Branch (370:33): [True: 2.42k, False: 9.37k]
Branch (370:9): [True: 18, False: 11.7k]
Branch (370:33): [True: 2.42k, False: 9.37k]
|
371 | 4.87k | *error = "not a Panackelty bytecode file"; |
372 | 4.87k | return false; |
373 | 4.87k | } |
374 | 18.7k | if (!u16(&r, &version)) { Branch (374:9): [True: 6, False: 9.36k]
Branch (374:9): [True: 6, False: 9.36k]
|
375 | 12 | *error = r.error; |
376 | 12 | return false; |
377 | 12 | } |
378 | 18.7k | if (version != 9) { Branch (378:9): [True: 537, False: 8.82k]
Branch (378:9): [True: 537, False: 8.82k]
|
379 | 1.07k | *error = "unsupported bytecode version"; |
380 | 1.07k | return false; |
381 | 1.07k | } |
382 | 17.6k | if (!u16(&r, &count)) { Branch (382:9): [True: 6, False: 8.82k]
Branch (382:9): [True: 6, False: 8.82k]
|
383 | 12 | *error = r.error; |
384 | 12 | return false; |
385 | 12 | } |
386 | 17.6k | if (count > MAX_FUNCTIONS) { Branch (386:9): [True: 248, False: 8.57k]
Branch (386:9): [True: 248, False: 8.57k]
|
387 | 496 | *error = "function count exceeds limit"; |
388 | 496 | return false; |
389 | 496 | } |
390 | 17.1k | p->count = count; |
391 | 17.1k | p->functions = calloc(count, sizeof(Function)); |
392 | 17.1k | if (count && !p->functions) { Branch (392:9): [True: 8.57k, False: 3]
Branch (392:18): [True: 4, False: 8.56k]
Branch (392:9): [True: 8.57k, False: 3]
Branch (392:18): [True: 4, False: 8.56k]
|
393 | 8 | *error = "out of memory"; |
394 | 8 | return false; |
395 | 8 | } |
396 | 17.1k | size_t total = 0; |
397 | 96.2k | for (size_t i = 0; i < count && !r.error; i++) { Branch (397:24): [True: 42.2k, False: 5.83k]
Branch (397:37): [True: 42.1k, False: 136]
Branch (397:24): [True: 42.2k, False: 5.83k]
Branch (397:37): [True: 42.1k, False: 136]
|
398 | 84.2k | Function *f = &p->functions[i]; |
399 | 84.2k | uint8_t flags, params; |
400 | 84.2k | uint32_t ins; |
401 | 84.2k | f->name = text(&r, true); |
402 | 84.2k | if (!f->name || !u8(&r, &flags) || flags > 2 || !u8(&r, ¶ms)) { Branch (402:13): [True: 1.42k, False: 40.7k]
Branch (402:25): [True: 5, False: 40.7k]
Branch (402:44): [True: 288, False: 40.4k]
Branch (402:57): [True: 4, False: 40.4k]
Branch (402:13): [True: 1.42k, False: 40.7k]
Branch (402:25): [True: 5, False: 40.7k]
Branch (402:44): [True: 288, False: 40.4k]
Branch (402:57): [True: 4, False: 40.4k]
|
403 | 3.44k | if (!r.error) { Branch (403:17): [True: 288, False: 1.43k]
Branch (403:17): [True: 288, False: 1.43k]
|
404 | 576 | fail(&r, "invalid function flags"); |
405 | 576 | } |
406 | 3.44k | break; |
407 | 3.44k | } |
408 | 80.8k | f->pure = flags == 1; |
409 | 80.8k | f->is_async = flags == 2; |
410 | 80.8k | f->param_count = params; |
411 | 80.8k | f->params = calloc(params, sizeof(char *)); |
412 | 80.8k | if (params && !f->params) { Branch (412:13): [True: 33.5k, False: 6.88k]
Branch (412:23): [True: 2, False: 33.5k]
Branch (412:13): [True: 33.5k, False: 6.88k]
Branch (412:23): [True: 2, False: 33.5k]
|
413 | 4 | fail(&r, "out of memory"); |
414 | 4 | break; |
415 | 4 | } |
416 | 219k | for (size_t j = 0; j < params && !r.error; j++) { Branch (416:28): [True: 69.8k, False: 40.1k]
Branch (416:42): [True: 69.5k, False: 277]
Branch (416:28): [True: 69.8k, False: 40.1k]
Branch (416:42): [True: 69.5k, False: 277]
|
417 | 139k | f->params[j] = text(&r, true); |
418 | 139k | } |
419 | 80.8k | if (!u32(&r, &ins)) { Branch (419:13): [True: 279, False: 40.1k]
Branch (419:13): [True: 279, False: 40.1k]
|
420 | 558 | break; |
421 | 558 | } |
422 | 80.2k | if (ins > 1000000u || total + ins > MAX_INSTRUCTIONS) { Branch (422:13): [True: 592, False: 39.5k]
Branch (422:31): [True: 0, False: 39.5k]
Branch (422:13): [True: 592, False: 39.5k]
Branch (422:31): [True: 0, False: 39.5k]
|
423 | 1.18k | fail(&r, "instruction count exceeds limit"); |
424 | 1.18k | break; |
425 | 1.18k | } |
426 | 79.1k | total += ins; |
427 | 79.1k | f->ins_count = ins; |
428 | 79.1k | f->ins = calloc(ins, sizeof(Instruction)); |
429 | 79.1k | if (ins && !f->ins) { Branch (429:13): [True: 39.5k, False: 5]
Branch (429:20): [True: 6, False: 39.5k]
Branch (429:13): [True: 39.5k, False: 5]
Branch (429:20): [True: 6, False: 39.5k]
|
430 | 12 | fail(&r, "out of memory"); |
431 | 12 | break; |
432 | 12 | } |
433 | 6.27M | for (size_t j = 0; j < ins && !r.error; j++) { Branch (433:28): [True: 3.09M, False: 36.6k]
Branch (433:39): [True: 3.09M, False: 2.89k]
Branch (433:28): [True: 3.09M, False: 36.6k]
Branch (433:39): [True: 3.09M, False: 2.89k]
|
434 | 6.19M | instruction(&r, &f->ins[j]); |
435 | 6.19M | } |
436 | 79.0k | } |
437 | 17.1k | if (!r.error && r.at != r.len) { Branch (437:9): [True: 2.77k, False: 5.79k]
Branch (437:21): [True: 33, False: 2.74k]
Branch (437:9): [True: 2.77k, False: 5.79k]
Branch (437:21): [True: 33, False: 2.74k]
|
438 | 66 | fail(&r, "trailing data"); |
439 | 66 | } |
440 | 17.1k | if (r.error) { Branch (440:9): [True: 5.83k, False: 2.74k]
Branch (440:9): [True: 5.83k, False: 2.74k]
|
441 | 11.6k | *error = r.error; |
442 | 11.6k | free_program(p); |
443 | 11.6k | return false; |
444 | 11.6k | } |
445 | 5.48k | return true; |
446 | 17.1k | } Line | Count | Source | 361 | 11.8k | { | 362 | 11.8k | memset(p, 0, sizeof(*p)); | 363 | 11.8k | Reader r = {data, length, 0, NULL}; | 364 | 11.8k | const uint8_t *magic; | 365 | 11.8k | uint16_t version, count; | 366 | 11.8k | if (length > MAX_ARTIFACT) { Branch (366:9): [True: 1, False: 11.8k]
| 367 | 1 | *error = "artifact exceeds size limit"; | 368 | 1 | return false; | 369 | 1 | } | 370 | 11.8k | if (!take(&r, 9, &magic) || memcmp(magic, "PANACKBC\0", 9)) { Branch (370:9): [True: 18, False: 11.7k]
Branch (370:33): [True: 2.42k, False: 9.37k]
| 371 | 2.43k | *error = "not a Panackelty bytecode file"; | 372 | 2.43k | return false; | 373 | 2.43k | } | 374 | 9.37k | if (!u16(&r, &version)) { Branch (374:9): [True: 6, False: 9.36k]
| 375 | 6 | *error = r.error; | 376 | 6 | return false; | 377 | 6 | } | 378 | 9.36k | if (version != 9) { Branch (378:9): [True: 537, False: 8.82k]
| 379 | 537 | *error = "unsupported bytecode version"; | 380 | 537 | return false; | 381 | 537 | } | 382 | 8.82k | if (!u16(&r, &count)) { Branch (382:9): [True: 6, False: 8.82k]
| 383 | 6 | *error = r.error; | 384 | 6 | return false; | 385 | 6 | } | 386 | 8.82k | if (count > MAX_FUNCTIONS) { Branch (386:9): [True: 248, False: 8.57k]
| 387 | 248 | *error = "function count exceeds limit"; | 388 | 248 | return false; | 389 | 248 | } | 390 | 8.57k | p->count = count; | 391 | 8.57k | p->functions = calloc(count, sizeof(Function)); | 392 | 8.57k | if (count && !p->functions) { Branch (392:9): [True: 8.57k, False: 3]
Branch (392:18): [True: 4, False: 8.56k]
| 393 | 4 | *error = "out of memory"; | 394 | 4 | return false; | 395 | 4 | } | 396 | 8.57k | size_t total = 0; | 397 | 48.1k | for (size_t i = 0; i < count && !r.error; i++) { Branch (397:24): [True: 42.2k, False: 5.83k]
Branch (397:37): [True: 42.1k, False: 136]
| 398 | 42.1k | Function *f = &p->functions[i]; | 399 | 42.1k | uint8_t flags, params; | 400 | 42.1k | uint32_t ins; | 401 | 42.1k | f->name = text(&r, true); | 402 | 42.1k | if (!f->name || !u8(&r, &flags) || flags > 2 || !u8(&r, ¶ms)) { Branch (402:13): [True: 1.42k, False: 40.7k]
Branch (402:25): [True: 5, False: 40.7k]
Branch (402:44): [True: 288, False: 40.4k]
Branch (402:57): [True: 4, False: 40.4k]
| 403 | 1.72k | if (!r.error) { Branch (403:17): [True: 288, False: 1.43k]
| 404 | 288 | fail(&r, "invalid function flags"); | 405 | 288 | } | 406 | 1.72k | break; | 407 | 1.72k | } | 408 | 40.4k | f->pure = flags == 1; | 409 | 40.4k | f->is_async = flags == 2; | 410 | 40.4k | f->param_count = params; | 411 | 40.4k | f->params = calloc(params, sizeof(char *)); | 412 | 40.4k | if (params && !f->params) { Branch (412:13): [True: 33.5k, False: 6.88k]
Branch (412:23): [True: 2, False: 33.5k]
| 413 | 2 | fail(&r, "out of memory"); | 414 | 2 | break; | 415 | 2 | } | 416 | 109k | for (size_t j = 0; j < params && !r.error; j++) { Branch (416:28): [True: 69.8k, False: 40.1k]
Branch (416:42): [True: 69.5k, False: 277]
| 417 | 69.5k | f->params[j] = text(&r, true); | 418 | 69.5k | } | 419 | 40.4k | if (!u32(&r, &ins)) { Branch (419:13): [True: 279, False: 40.1k]
| 420 | 279 | break; | 421 | 279 | } | 422 | 40.1k | if (ins > 1000000u || total + ins > MAX_INSTRUCTIONS) { Branch (422:13): [True: 592, False: 39.5k]
Branch (422:31): [True: 0, False: 39.5k]
| 423 | 592 | fail(&r, "instruction count exceeds limit"); | 424 | 592 | break; | 425 | 592 | } | 426 | 39.5k | total += ins; | 427 | 39.5k | f->ins_count = ins; | 428 | 39.5k | f->ins = calloc(ins, sizeof(Instruction)); | 429 | 39.5k | if (ins && !f->ins) { Branch (429:13): [True: 39.5k, False: 5]
Branch (429:20): [True: 6, False: 39.5k]
| 430 | 6 | fail(&r, "out of memory"); | 431 | 6 | break; | 432 | 6 | } | 433 | 3.13M | for (size_t j = 0; j < ins && !r.error; j++) { Branch (433:28): [True: 3.09M, False: 36.6k]
Branch (433:39): [True: 3.09M, False: 2.89k]
| 434 | 3.09M | instruction(&r, &f->ins[j]); | 435 | 3.09M | } | 436 | 39.5k | } | 437 | 8.57k | if (!r.error && r.at != r.len) { Branch (437:9): [True: 2.77k, False: 5.79k]
Branch (437:21): [True: 33, False: 2.74k]
| 438 | 33 | fail(&r, "trailing data"); | 439 | 33 | } | 440 | 8.57k | if (r.error) { Branch (440:9): [True: 5.83k, False: 2.74k]
| 441 | 5.83k | *error = r.error; | 442 | 5.83k | free_program(p); | 443 | 5.83k | return false; | 444 | 5.83k | } | 445 | 2.74k | return true; | 446 | 8.57k | } |
Line | Count | Source | 361 | 11.8k | { | 362 | 11.8k | memset(p, 0, sizeof(*p)); | 363 | 11.8k | Reader r = {data, length, 0, NULL}; | 364 | 11.8k | const uint8_t *magic; | 365 | 11.8k | uint16_t version, count; | 366 | 11.8k | if (length > MAX_ARTIFACT) { Branch (366:9): [True: 1, False: 11.8k]
| 367 | 1 | *error = "artifact exceeds size limit"; | 368 | 1 | return false; | 369 | 1 | } | 370 | 11.8k | if (!take(&r, 9, &magic) || memcmp(magic, "PANACKBC\0", 9)) { Branch (370:9): [True: 18, False: 11.7k]
Branch (370:33): [True: 2.42k, False: 9.37k]
| 371 | 2.43k | *error = "not a Panackelty bytecode file"; | 372 | 2.43k | return false; | 373 | 2.43k | } | 374 | 9.37k | if (!u16(&r, &version)) { Branch (374:9): [True: 6, False: 9.36k]
| 375 | 6 | *error = r.error; | 376 | 6 | return false; | 377 | 6 | } | 378 | 9.36k | if (version != 9) { Branch (378:9): [True: 537, False: 8.82k]
| 379 | 537 | *error = "unsupported bytecode version"; | 380 | 537 | return false; | 381 | 537 | } | 382 | 8.82k | if (!u16(&r, &count)) { Branch (382:9): [True: 6, False: 8.82k]
| 383 | 6 | *error = r.error; | 384 | 6 | return false; | 385 | 6 | } | 386 | 8.82k | if (count > MAX_FUNCTIONS) { Branch (386:9): [True: 248, False: 8.57k]
| 387 | 248 | *error = "function count exceeds limit"; | 388 | 248 | return false; | 389 | 248 | } | 390 | 8.57k | p->count = count; | 391 | 8.57k | p->functions = calloc(count, sizeof(Function)); | 392 | 8.57k | if (count && !p->functions) { Branch (392:9): [True: 8.57k, False: 3]
Branch (392:18): [True: 4, False: 8.56k]
| 393 | 4 | *error = "out of memory"; | 394 | 4 | return false; | 395 | 4 | } | 396 | 8.57k | size_t total = 0; | 397 | 48.1k | for (size_t i = 0; i < count && !r.error; i++) { Branch (397:24): [True: 42.2k, False: 5.83k]
Branch (397:37): [True: 42.1k, False: 136]
| 398 | 42.1k | Function *f = &p->functions[i]; | 399 | 42.1k | uint8_t flags, params; | 400 | 42.1k | uint32_t ins; | 401 | 42.1k | f->name = text(&r, true); | 402 | 42.1k | if (!f->name || !u8(&r, &flags) || flags > 2 || !u8(&r, ¶ms)) { Branch (402:13): [True: 1.42k, False: 40.7k]
Branch (402:25): [True: 5, False: 40.7k]
Branch (402:44): [True: 288, False: 40.4k]
Branch (402:57): [True: 4, False: 40.4k]
| 403 | 1.72k | if (!r.error) { Branch (403:17): [True: 288, False: 1.43k]
| 404 | 288 | fail(&r, "invalid function flags"); | 405 | 288 | } | 406 | 1.72k | break; | 407 | 1.72k | } | 408 | 40.4k | f->pure = flags == 1; | 409 | 40.4k | f->is_async = flags == 2; | 410 | 40.4k | f->param_count = params; | 411 | 40.4k | f->params = calloc(params, sizeof(char *)); | 412 | 40.4k | if (params && !f->params) { Branch (412:13): [True: 33.5k, False: 6.88k]
Branch (412:23): [True: 2, False: 33.5k]
| 413 | 2 | fail(&r, "out of memory"); | 414 | 2 | break; | 415 | 2 | } | 416 | 109k | for (size_t j = 0; j < params && !r.error; j++) { Branch (416:28): [True: 69.8k, False: 40.1k]
Branch (416:42): [True: 69.5k, False: 277]
| 417 | 69.5k | f->params[j] = text(&r, true); | 418 | 69.5k | } | 419 | 40.4k | if (!u32(&r, &ins)) { Branch (419:13): [True: 279, False: 40.1k]
| 420 | 279 | break; | 421 | 279 | } | 422 | 40.1k | if (ins > 1000000u || total + ins > MAX_INSTRUCTIONS) { Branch (422:13): [True: 592, False: 39.5k]
Branch (422:31): [True: 0, False: 39.5k]
| 423 | 592 | fail(&r, "instruction count exceeds limit"); | 424 | 592 | break; | 425 | 592 | } | 426 | 39.5k | total += ins; | 427 | 39.5k | f->ins_count = ins; | 428 | 39.5k | f->ins = calloc(ins, sizeof(Instruction)); | 429 | 39.5k | if (ins && !f->ins) { Branch (429:13): [True: 39.5k, False: 5]
Branch (429:20): [True: 6, False: 39.5k]
| 430 | 6 | fail(&r, "out of memory"); | 431 | 6 | break; | 432 | 6 | } | 433 | 3.13M | for (size_t j = 0; j < ins && !r.error; j++) { Branch (433:28): [True: 3.09M, False: 36.6k]
Branch (433:39): [True: 3.09M, False: 2.89k]
| 434 | 3.09M | instruction(&r, &f->ins[j]); | 435 | 3.09M | } | 436 | 39.5k | } | 437 | 8.57k | if (!r.error && r.at != r.len) { Branch (437:9): [True: 2.77k, False: 5.79k]
Branch (437:21): [True: 33, False: 2.74k]
| 438 | 33 | fail(&r, "trailing data"); | 439 | 33 | } | 440 | 8.57k | if (r.error) { Branch (440:9): [True: 5.83k, False: 2.74k]
| 441 | 5.83k | *error = r.error; | 442 | 5.83k | free_program(p); | 443 | 5.83k | return false; | 444 | 5.83k | } | 445 | 2.74k | return true; | 446 | 8.57k | } |
|