Skip to content

Commit b3fd01f

Browse files
authored
Merge pull request #1 from Neumenon/codex
Harden glyph codecs across runtimes
2 parents 4ddd2c2 + 0c6e97a commit b3fd01f

46 files changed

Lines changed: 4448 additions & 702 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

c/glyph-codec/src/decimal128.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,9 +103,10 @@ decimal128_t decimal128_from_int(int64_t value) {
103103
decimal128_t d;
104104
d.scale = 0;
105105
if (value < 0) {
106+
uint64_t magnitude = ((uint64_t)(-(value + 1))) + 1;
106107
d.negative = true;
107108
d.coef_high = 0;
108-
d.coef_low = (uint64_t)(-value);
109+
d.coef_low = magnitude;
109110
} else {
110111
d.negative = false;
111112
d.coef_high = 0;
@@ -206,10 +207,15 @@ int64_t decimal128_to_int(const decimal128_t *d) {
206207
}
207208

208209
/* Check if fits in int64 */
209-
if (h != 0 || l > INT64_MAX) {
210+
if (h != 0 || (!d->negative && l > INT64_MAX) ||
211+
(d->negative && l > (uint64_t)INT64_MAX + 1ULL)) {
210212
return d->negative ? INT64_MIN : INT64_MAX;
211213
}
212214

215+
if (d->negative && l == (uint64_t)INT64_MAX + 1ULL) {
216+
return INT64_MIN;
217+
}
218+
213219
return d->negative ? -(int64_t)l : (int64_t)l;
214220
}
215221

@@ -241,6 +247,7 @@ char *decimal128_to_string(const decimal128_t *d) {
241247
}
242248
/* Build 0.000... */
243249
char *result = malloc(d->scale + 3);
250+
if (!result) return NULL;
244251
result[0] = '0';
245252
result[1] = '.';
246253
for (int i = 0; i < d->scale; i++) {
@@ -262,6 +269,7 @@ char *decimal128_to_string(const decimal128_t *d) {
262269
if (d->scale == 0) {
263270
size_t result_len = digit_count + (d->negative ? 1 : 0) + 1;
264271
char *result = malloc(result_len);
272+
if (!result) return NULL;
265273
if (d->negative) {
266274
result[0] = '-';
267275
strcpy(result + 1, digit_str);
@@ -277,6 +285,7 @@ char *decimal128_to_string(const decimal128_t *d) {
277285
/* 0.00...XXX */
278286
size_t result_len = 2 + (-int_digits) + digit_count + (d->negative ? 1 : 0) + 1;
279287
char *result = malloc(result_len);
288+
if (!result) return NULL;
280289
char *p = result;
281290
if (d->negative) *p++ = '-';
282291
*p++ = '0';
@@ -291,6 +300,7 @@ char *decimal128_to_string(const decimal128_t *d) {
291300
/* Normal case: XXX.YYY */
292301
size_t result_len = digit_count + 1 + (d->negative ? 1 : 0) + 1;
293302
char *result = malloc(result_len);
303+
if (!result) return NULL;
294304
char *p = result;
295305
if (d->negative) *p++ = '-';
296306
memcpy(p, digit_str, int_digits);

c/glyph-codec/src/glyph.c

Lines changed: 127 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -29,41 +29,64 @@ typedef struct {
2929
char *data;
3030
size_t len;
3131
size_t cap;
32+
bool oom;
3233
} strbuf_t;
3334

3435
static void strbuf_init(strbuf_t *buf) {
3536
buf->data = malloc(256);
3637
buf->len = 0;
3738
buf->cap = 256;
38-
if (buf->data) buf->data[0] = '\0';
39+
buf->oom = (buf->data == NULL);
40+
if (buf->data) {
41+
buf->data[0] = '\0';
42+
} else {
43+
buf->cap = 0;
44+
}
3945
}
4046

41-
static void strbuf_grow(strbuf_t *buf, size_t need) {
42-
if (buf->len + need >= buf->cap) {
43-
size_t new_cap = buf->cap * 2;
44-
while (buf->len + need >= new_cap) new_cap *= 2;
45-
char *new_data = realloc(buf->data, new_cap);
46-
if (new_data) {
47-
buf->data = new_data;
48-
buf->cap = new_cap;
47+
static bool strbuf_grow(strbuf_t *buf, size_t need) {
48+
if (buf->oom) return false;
49+
if (buf->len + need < buf->cap) return true;
50+
51+
size_t new_cap = buf->cap ? buf->cap : 1;
52+
while (buf->len + need >= new_cap) {
53+
if (new_cap > SIZE_MAX / 2) {
54+
buf->oom = true;
55+
return false;
4956
}
57+
new_cap *= 2;
5058
}
59+
60+
char *new_data = realloc(buf->data, new_cap);
61+
if (!new_data) {
62+
buf->oom = true;
63+
return false;
64+
}
65+
buf->data = new_data;
66+
buf->cap = new_cap;
67+
return true;
5168
}
5269

5370
static void strbuf_append(strbuf_t *buf, const char *s) {
71+
if (!s) return;
5472
size_t len = strlen(s);
55-
strbuf_grow(buf, len + 1);
73+
if (!strbuf_grow(buf, len + 1)) return;
5674
memcpy(buf->data + buf->len, s, len + 1);
5775
buf->len += len;
5876
}
5977

6078
static void strbuf_append_char(strbuf_t *buf, char c) {
61-
strbuf_grow(buf, 2);
79+
if (!strbuf_grow(buf, 2)) return;
6280
buf->data[buf->len++] = c;
6381
buf->data[buf->len] = '\0';
6482
}
6583

6684
static char *strbuf_finish(strbuf_t *buf) {
85+
if (buf->oom) {
86+
free(buf->data);
87+
buf->data = NULL;
88+
return NULL;
89+
}
6790
return buf->data;
6891
}
6992

@@ -109,16 +132,29 @@ glyph_value_t *glyph_str(const char *val) {
109132
if (v) {
110133
v->type = GLYPH_STR;
111134
v->str_val = strdup_safe(val);
135+
if (val && !v->str_val) {
136+
free(v);
137+
return NULL;
138+
}
112139
}
113140
return v;
114141
}
115142

116143
glyph_value_t *glyph_bytes(const uint8_t *data, size_t len) {
144+
if (len > 0 && !data) return NULL;
145+
117146
glyph_value_t *v = calloc(1, sizeof(glyph_value_t));
118147
if (v) {
119148
v->type = GLYPH_BYTES;
120-
v->bytes_val.data = malloc(len);
121-
if (v->bytes_val.data) {
149+
if (len == 0) {
150+
v->bytes_val.data = NULL;
151+
v->bytes_val.len = 0;
152+
} else {
153+
v->bytes_val.data = malloc(len);
154+
if (!v->bytes_val.data) {
155+
free(v);
156+
return NULL;
157+
}
122158
memcpy(v->bytes_val.data, data, len);
123159
v->bytes_val.len = len;
124160
}
@@ -132,6 +168,12 @@ glyph_value_t *glyph_id(const char *prefix, const char *value) {
132168
v->type = GLYPH_ID;
133169
v->id_val.prefix = strdup_safe(prefix ? prefix : "");
134170
v->id_val.value = strdup_safe(value);
171+
if (!v->id_val.prefix || (value && !v->id_val.value)) {
172+
free(v->id_val.prefix);
173+
free(v->id_val.value);
174+
free(v);
175+
return NULL;
176+
}
135177
}
136178
return v;
137179
}
@@ -152,11 +194,13 @@ void glyph_list_append(glyph_value_t *list, glyph_value_t *item) {
152194
size_t new_count = list->list_val.count + 1;
153195
glyph_value_t **new_items = realloc(list->list_val.items,
154196
new_count * sizeof(glyph_value_t *));
155-
if (new_items) {
156-
new_items[list->list_val.count] = item;
157-
list->list_val.items = new_items;
158-
list->list_val.count = new_count;
197+
if (!new_items) {
198+
glyph_value_free(item);
199+
return;
159200
}
201+
new_items[list->list_val.count] = item;
202+
list->list_val.items = new_items;
203+
list->list_val.count = new_count;
160204
}
161205

162206
glyph_value_t *glyph_map_new(void) {
@@ -172,22 +216,35 @@ glyph_value_t *glyph_map_new(void) {
172216
void glyph_map_set(glyph_value_t *map, const char *key, glyph_value_t *value) {
173217
if (!map || map->type != GLYPH_MAP || !key || !value) return;
174218

219+
char *key_copy = strdup_safe(key);
220+
if (!key_copy) {
221+
glyph_value_free(value);
222+
return;
223+
}
224+
175225
size_t new_count = map->map_val.count + 1;
176226
glyph_map_entry_t *new_entries = realloc(map->map_val.entries,
177227
new_count * sizeof(glyph_map_entry_t));
178-
if (new_entries) {
179-
new_entries[map->map_val.count].key = strdup_safe(key);
180-
new_entries[map->map_val.count].value = value;
181-
map->map_val.entries = new_entries;
182-
map->map_val.count = new_count;
228+
if (!new_entries) {
229+
free(key_copy);
230+
glyph_value_free(value);
231+
return;
183232
}
233+
new_entries[map->map_val.count].key = key_copy;
234+
new_entries[map->map_val.count].value = value;
235+
map->map_val.entries = new_entries;
236+
map->map_val.count = new_count;
184237
}
185238

186239
glyph_value_t *glyph_struct_new(const char *type_name) {
187240
glyph_value_t *v = calloc(1, sizeof(glyph_value_t));
188241
if (v) {
189242
v->type = GLYPH_STRUCT;
190243
v->struct_val.type_name = strdup_safe(type_name);
244+
if (type_name && !v->struct_val.type_name) {
245+
free(v);
246+
return NULL;
247+
}
191248
v->struct_val.fields = NULL;
192249
v->struct_val.fields_count = 0;
193250
}
@@ -197,15 +254,24 @@ glyph_value_t *glyph_struct_new(const char *type_name) {
197254
void glyph_struct_set(glyph_value_t *s, const char *key, glyph_value_t *value) {
198255
if (!s || s->type != GLYPH_STRUCT || !key || !value) return;
199256

257+
char *key_copy = strdup_safe(key);
258+
if (!key_copy) {
259+
glyph_value_free(value);
260+
return;
261+
}
262+
200263
size_t new_count = s->struct_val.fields_count + 1;
201264
glyph_map_entry_t *new_fields = realloc(s->struct_val.fields,
202265
new_count * sizeof(glyph_map_entry_t));
203-
if (new_fields) {
204-
new_fields[s->struct_val.fields_count].key = strdup_safe(key);
205-
new_fields[s->struct_val.fields_count].value = value;
206-
s->struct_val.fields = new_fields;
207-
s->struct_val.fields_count = new_count;
266+
if (!new_fields) {
267+
free(key_copy);
268+
glyph_value_free(value);
269+
return;
208270
}
271+
new_fields[s->struct_val.fields_count].key = key_copy;
272+
new_fields[s->struct_val.fields_count].value = value;
273+
s->struct_val.fields = new_fields;
274+
s->struct_val.fields_count = new_count;
209275
}
210276

211277
glyph_value_t *glyph_sum(const char *tag, glyph_value_t *value) {
@@ -214,6 +280,11 @@ glyph_value_t *glyph_sum(const char *tag, glyph_value_t *value) {
214280
v->type = GLYPH_SUM;
215281
v->sum_val.tag = strdup_safe(tag);
216282
v->sum_val.value = value;
283+
if (tag && !v->sum_val.tag) {
284+
glyph_value_free(value);
285+
free(v);
286+
return NULL;
287+
}
217288
}
218289
return v;
219290
}
@@ -382,11 +453,17 @@ static void write_canon_value(strbuf_t *buf, const glyph_value_t *v,
382453

383454
/* Compare entries by canonical key for sorting */
384455
static int compare_entries(const void *a, const void *b) {
385-
const glyph_map_entry_t *ea = a;
386-
const glyph_map_entry_t *eb = b;
456+
const glyph_map_entry_t *ea = (const glyph_map_entry_t *)a;
457+
const glyph_map_entry_t *eb = (const glyph_map_entry_t *)b;
387458
return strcmp(ea->key, eb->key);
388459
}
389460

461+
static int compare_key_strings(const void *a, const void *b) {
462+
const char *const *ka = (const char *const *)a;
463+
const char *const *kb = (const char *const *)b;
464+
return strcmp(*ka, *kb);
465+
}
466+
390467
static void write_canon_map(strbuf_t *buf, const glyph_map_entry_t *entries,
391468
size_t count, const glyph_canon_opts_t *opts) {
392469
strbuf_append_char(buf, '{');
@@ -422,6 +499,7 @@ static bool check_homogeneous(glyph_value_t **items, size_t count,
422499
/* Collect all keys */
423500
size_t all_keys_cap = 64;
424501
char **all_keys = malloc(all_keys_cap * sizeof(char *));
502+
if (!all_keys) return false;
425503
size_t all_keys_count = 0;
426504

427505
for (size_t i = 0; i < count; i++) {
@@ -452,9 +530,21 @@ static bool check_homogeneous(glyph_value_t **items, size_t count,
452530
if (!found) {
453531
if (all_keys_count >= all_keys_cap) {
454532
all_keys_cap *= 2;
455-
all_keys = realloc(all_keys, all_keys_cap * sizeof(char *));
533+
char **new_all_keys = realloc(all_keys, all_keys_cap * sizeof(char *));
534+
if (!new_all_keys) {
535+
for (size_t m = 0; m < all_keys_count; m++) free(all_keys[m]);
536+
free(all_keys);
537+
return false;
538+
}
539+
all_keys = new_all_keys;
540+
}
541+
all_keys[all_keys_count] = strdup_safe(key);
542+
if (!all_keys[all_keys_count]) {
543+
for (size_t m = 0; m < all_keys_count; m++) free(all_keys[m]);
544+
free(all_keys);
545+
return false;
456546
}
457-
all_keys[all_keys_count++] = strdup_safe(key);
547+
all_keys_count++;
458548
}
459549
}
460550
}
@@ -503,8 +593,7 @@ static bool check_homogeneous(glyph_value_t **items, size_t count,
503593
}
504594

505595
/* Sort columns */
506-
qsort(all_keys, all_keys_count, sizeof(char *),
507-
(int (*)(const void *, const void *))strcmp);
596+
qsort(all_keys, all_keys_count, sizeof(char *), compare_key_strings);
508597

509598
*out_cols = all_keys;
510599
*out_col_count = all_keys_count;
@@ -717,7 +806,12 @@ char *glyph_canonicalize_loose_no_tabular(const glyph_value_t *v) {
717806
char *glyph_canonicalize_loose_with_opts(const glyph_value_t *v,
718807
const glyph_canon_opts_t *opts) {
719808
strbuf_t buf;
809+
glyph_canon_opts_t default_opts;
720810
strbuf_init(&buf);
811+
if (!opts) {
812+
default_opts = glyph_canon_opts_default();
813+
opts = &default_opts;
814+
}
721815
write_canon_value(&buf, v, opts);
722816
return strbuf_finish(&buf);
723817
}

0 commit comments

Comments
 (0)