Have std/cbor reject tags before an 0xFF stop code
diff --git a/release/c/wuffs-unsupported-snapshot.c b/release/c/wuffs-unsupported-snapshot.c
index 12b0edf..dd48c0d 100644
--- a/release/c/wuffs-unsupported-snapshot.c
+++ b/release/c/wuffs-unsupported-snapshot.c
@@ -5761,6 +5761,7 @@
uint64_t v_string_length;
uint32_t v_depth;
uint32_t v_token_length;
+ bool v_tagged;
uint8_t v_indefinite_string_major_type;
} s_decode_tokens[1];
} private_data;
@@ -16759,6 +16760,7 @@
uint8_t v_c = 0;
uint8_t v_c_major = 0;
uint8_t v_c_minor = 0;
+ bool v_tagged = false;
uint8_t v_indefinite_string_major_type = 0;
wuffs_base__token* iop_a_dst = NULL;
@@ -16790,6 +16792,7 @@
v_string_length = self->private_data.s_decode_tokens[0].v_string_length;
v_depth = self->private_data.s_decode_tokens[0].v_depth;
v_token_length = self->private_data.s_decode_tokens[0].v_token_length;
+ v_tagged = self->private_data.s_decode_tokens[0].v_tagged;
v_indefinite_string_major_type = self->private_data.s_decode_tokens[0].v_indefinite_string_major_type;
}
switch (coro_susp_point) {
@@ -17089,6 +17092,7 @@
self->private_data.f_stack[v_stack_byte] &= (4294967295 ^ (((uint32_t)(3)) << v_stack_bit));
self->private_data.f_container_num_remaining[v_depth] = v_string_length;
v_depth += 1;
+ v_tagged = false;
goto label__outer__continue;
} else if (v_c_major == 5) {
if (WUFFS_CBOR__TOKEN_LENGTHS[v_c_minor] == 0) {
@@ -17124,6 +17128,7 @@
self->private_data.f_stack[v_stack_byte] |= (((uint32_t)(3)) << v_stack_bit);
self->private_data.f_container_num_remaining[v_depth] = v_string_length;
v_depth += 1;
+ v_tagged = false;
goto label__outer__continue;
} else if (v_c_major == 6) {
if (v_c_minor >= 28) {
@@ -17144,6 +17149,7 @@
(~(v_string_length & 70368744177663) << WUFFS_BASE__TOKEN__VALUE_EXTENSION__SHIFT) |
(((uint64_t)(((uint32_t)(WUFFS_CBOR__TOKEN_LENGTHS[v_c_minor])))) << WUFFS_BASE__TOKEN__LENGTH__SHIFT));
}
+ v_tagged = true;
goto label__outer__continue;
} else if (v_c_major == 7) {
if (v_c_minor < 20) {
@@ -17172,7 +17178,7 @@
(((uint64_t)(((uint32_t)(WUFFS_CBOR__TOKEN_LENGTHS[v_c_minor])))) << WUFFS_BASE__TOKEN__LENGTH__SHIFT));
goto label__goto_parsed_a_leaf_value__break;
} else if (v_c_minor == 31) {
- if (v_depth <= 0) {
+ if (v_tagged || (v_depth <= 0)) {
goto label__goto_fail__break;
}
v_depth -= 1;
@@ -17219,6 +17225,7 @@
goto exit;
}
label__goto_parsed_a_leaf_value__break:;
+ v_tagged = false;
while (v_depth > 0) {
v_stack_byte = ((v_depth - 1) / 16);
v_stack_bit = (((v_depth - 1) & 15) * 2);
@@ -17280,6 +17287,7 @@
self->private_data.s_decode_tokens[0].v_string_length = v_string_length;
self->private_data.s_decode_tokens[0].v_depth = v_depth;
self->private_data.s_decode_tokens[0].v_token_length = v_token_length;
+ self->private_data.s_decode_tokens[0].v_tagged = v_tagged;
self->private_data.s_decode_tokens[0].v_indefinite_string_major_type = v_indefinite_string_major_type;
goto exit;
diff --git a/std/cbor/decode_cbor.wuffs b/std/cbor/decode_cbor.wuffs
index 7153384..f28d4c1 100644
--- a/std/cbor/decode_cbor.wuffs
+++ b/std/cbor/decode_cbor.wuffs
@@ -112,6 +112,7 @@
var c : base.u8
var c_major : base.u8[..= 0x07]
var c_minor : base.u8[..= 0x1F]
+ var tagged : base.bool
// indefinite_string_major_type is 2 or 3 when we are in an
// indefinite-length byte string or text string. It is 0 otherwise.
@@ -484,6 +485,7 @@
this.stack[stack_byte] &= 0xFFFF_FFFF ^ ((3 as base.u32) << stack_bit)
this.container_num_remaining[depth] = string_length
depth += 1
+ tagged = false
continue.outer
// -------- END Major type 4: an array of data items.
@@ -545,6 +547,7 @@
this.stack[stack_byte] |= (3 as base.u32) << stack_bit
this.container_num_remaining[depth] = string_length
depth += 1
+ tagged = false
continue.outer
// -------- END Major type 5: a map of pairs of data items.
@@ -573,6 +576,7 @@
continued: 0,
length: TOKEN_LENGTHS[c_minor] as base.u32)
}
+ tagged = true
continue.outer
// -------- END Major type 6: tags.
@@ -621,7 +625,7 @@
} else if c_minor == 0x1F {
// Indefinite-length strings were dealt with separately, above.
// Here, we expect to be in an indefinite-length container.
- if depth <= 0 {
+ if tagged or (depth <= 0) {
break.goto_fail
}
depth -= 1
@@ -683,6 +687,7 @@
// We've just parsed a leaf (non-container) value, or the (explicit or
// implicit) close of a container (array or object).
+ tagged = false
while depth > 0 {
// Toggle the key/value bit for object containers. This bit is
// ignored for array containers.
diff --git a/test/c/std/cbor.c b/test/c/std/cbor.c
index cc7076e..fdf6603 100644
--- a/test/c/std/cbor.c
+++ b/test/c/std/cbor.c
@@ -103,10 +103,16 @@
char* test_cases[] = {
// Truncated (integer; major type 0) value.
"\x18",
+ // Tag in array, immediately before an 0xFF stop code. Some discussion is
+ // at https://github.com/cbor/cbor.github.io/issues/65
+ "\x9F\xD0\xFF",
// Map with 1 element (an odd number).
"\xA1\x01",
// Map with 3 elements (an odd number).
"\xBF\x01\x02\x03\xFF",
+ // Tag in map, immediately before an 0xFF stop code. Some discussion is
+ // at https://github.com/cbor/cbor.github.io/issues/65
+ "\xBF\xD0\xFF",
// Unused opcode.
"\xFE",
};
@@ -147,6 +153,10 @@
char* test_cases[] = {
// Map with 2 elements (an even number).
"\xA1\x01\x02",
+ // Tag immediately before an empty array.
+ "\xD0\x9F\xFF",
+ // Tag immediately before an empty map.
+ "\xD0\xBF\xFF",
};
int tc;