Avoid automatic variables in functions using setjmp.

According to https://en.cppreference.com/w/c/program/setjmp automatic variables
modified in a function calling setjmp can have indeterminate values.  Instead,
refactor all functions calling setjmp so that the function calling setjmp
doesn’t have any local variables.

Part II: Mini table decoder.

PiperOrigin-RevId: 509644446
pull/13171/head
Protobuf Team Bot 2 years ago committed by Copybara-Service
parent 0ccf6fd717
commit a0fbbd6b2d
  1. 195
      upb/mini_table/decode.c

@ -744,37 +744,17 @@ static void upb_MtDecoder_ParseMessageSet(upb_MtDecoder* d, const char* data,
ret->required_count = 0; ret->required_count = 0;
} }
upb_MiniTable* upb_MiniTable_BuildWithBuf(const char* data, size_t len, static upb_MiniTable* upb_MtDecoder_DoBuildMiniTableWithBuf(
upb_MiniTablePlatform platform, upb_MtDecoder* decoder, const char* data, size_t len, void** buf,
upb_Arena* arena, void** buf, size_t* buf_size) {
size_t* buf_size, upb_MtDecoder_CheckOutOfMemory(decoder, decoder->table);
upb_Status* status) {
upb_MtDecoder decoder = { decoder->table->size = 0;
.platform = platform, decoder->table->field_count = 0;
.vec = decoder->table->ext = kUpb_ExtMode_NonExtendable;
{ decoder->table->dense_below = 0;
.data = *buf, decoder->table->table_mask = -1;
.capacity = *buf_size / sizeof(*decoder.vec.data), decoder->table->required_count = 0;
.size = 0,
},
.arena = arena,
.status = status,
.table = upb_Arena_Malloc(arena, sizeof(*decoder.table)),
};
if (UPB_SETJMP(decoder.err)) {
decoder.table = NULL;
goto done;
}
upb_MtDecoder_CheckOutOfMemory(&decoder, decoder.table);
decoder.table->size = 0;
decoder.table->field_count = 0;
decoder.table->ext = kUpb_ExtMode_NonExtendable;
decoder.table->dense_below = 0;
decoder.table->table_mask = -1;
decoder.table->required_count = 0;
// Strip off and verify the version tag. // Strip off and verify the version tag.
if (!len--) goto done; if (!len--) goto done;
@ -782,29 +762,64 @@ upb_MiniTable* upb_MiniTable_BuildWithBuf(const char* data, size_t len,
switch (vers) { switch (vers) {
case kUpb_EncodedVersion_MapV1: case kUpb_EncodedVersion_MapV1:
upb_MtDecoder_ParseMap(&decoder, data, len); upb_MtDecoder_ParseMap(decoder, data, len);
break; break;
case kUpb_EncodedVersion_MessageV1: case kUpb_EncodedVersion_MessageV1:
upb_MtDecoder_ParseMessage(&decoder, data, len); upb_MtDecoder_ParseMessage(decoder, data, len);
upb_MtDecoder_AssignHasbits(decoder.table); upb_MtDecoder_AssignHasbits(decoder->table);
upb_MtDecoder_SortLayoutItems(&decoder); upb_MtDecoder_SortLayoutItems(decoder);
upb_MtDecoder_AssignOffsets(&decoder); upb_MtDecoder_AssignOffsets(decoder);
break; break;
case kUpb_EncodedVersion_MessageSetV1: case kUpb_EncodedVersion_MessageSetV1:
upb_MtDecoder_ParseMessageSet(&decoder, data, len); upb_MtDecoder_ParseMessageSet(decoder, data, len);
break; break;
default: default:
upb_MtDecoder_ErrorFormat(&decoder, "Invalid message version: %c", vers); upb_MtDecoder_ErrorFormat(decoder, "Invalid message version: %c", vers);
UPB_UNREACHABLE(); UPB_UNREACHABLE();
} }
done: done:
*buf = decoder.vec.data; *buf = decoder->vec.data;
*buf_size = decoder.vec.capacity * sizeof(*decoder.vec.data); *buf_size = decoder->vec.capacity * sizeof(*decoder->vec.data);
return decoder.table; return decoder->table;
}
static upb_MiniTable* upb_MtDecoder_BuildMiniTableWithBuf(
upb_MtDecoder* const decoder, const char* const data, const size_t len,
void** const buf, size_t* const buf_size) {
if (UPB_SETJMP(decoder->err) != 0) {
*buf = decoder->vec.data;
*buf_size = decoder->vec.capacity * sizeof(*decoder->vec.data);
return NULL;
}
return upb_MtDecoder_DoBuildMiniTableWithBuf(decoder, data, len, buf,
buf_size);
}
upb_MiniTable* upb_MiniTable_BuildWithBuf(const char* data, size_t len,
upb_MiniTablePlatform platform,
upb_Arena* arena, void** buf,
size_t* buf_size,
upb_Status* status) {
upb_MtDecoder decoder = {
.platform = platform,
.vec =
{
.data = *buf,
.capacity = *buf_size / sizeof(*decoder.vec.data),
.size = 0,
},
.arena = arena,
.status = status,
.table = upb_Arena_Malloc(arena, sizeof(*decoder.table)),
};
return upb_MtDecoder_BuildMiniTableWithBuf(&decoder, data, len, buf,
buf_size);
} }
static size_t upb_MiniTableEnum_Size(size_t count) { static size_t upb_MiniTableEnum_Size(size_t count) {
@ -843,85 +858,83 @@ static void upb_MiniTableEnum_BuildValue(upb_MtDecoder* d, uint32_t val) {
} }
} }
upb_MiniTableEnum* upb_MiniTableEnum_Build(const char* data, size_t len, static upb_MiniTableEnum* upb_MtDecoder_DoBuildMiniTableEnum(
upb_Arena* arena, upb_MtDecoder* decoder, const char* data, size_t len) {
upb_Status* status) {
upb_MtDecoder decoder = {
.enum_table = upb_Arena_Malloc(arena, upb_MiniTableEnum_Size(2)),
.enum_value_count = 0,
.enum_data_count = 0,
.enum_data_capacity = 1,
.status = status,
.end = UPB_PTRADD(data, len),
.arena = arena,
};
if (UPB_SETJMP(decoder.err)) return NULL;
// If the string is non-empty then it must begin with a version tag. // If the string is non-empty then it must begin with a version tag.
if (len) { if (len) {
if (*data != kUpb_EncodedVersion_EnumV1) { if (*data != kUpb_EncodedVersion_EnumV1) {
upb_MtDecoder_ErrorFormat(&decoder, "Invalid enum version: %c", *data); upb_MtDecoder_ErrorFormat(decoder, "Invalid enum version: %c", *data);
UPB_UNREACHABLE(); UPB_UNREACHABLE();
} }
data++; data++;
len--; len--;
} }
upb_MtDecoder_CheckOutOfMemory(&decoder, decoder.enum_table); upb_MtDecoder_CheckOutOfMemory(decoder, decoder->enum_table);
// Guarantee at least 64 bits of mask without checking mask size. // Guarantee at least 64 bits of mask without checking mask size.
decoder.enum_table->mask_limit = 64; decoder->enum_table->mask_limit = 64;
decoder.enum_table = _upb_MiniTable_AddEnumDataMember(&decoder, 0); decoder->enum_table = _upb_MiniTable_AddEnumDataMember(decoder, 0);
decoder.enum_table = _upb_MiniTable_AddEnumDataMember(&decoder, 0); decoder->enum_table = _upb_MiniTable_AddEnumDataMember(decoder, 0);
decoder.enum_table->value_count = 0; decoder->enum_table->value_count = 0;
const char* ptr = data; const char* ptr = data;
uint32_t base = 0; uint32_t base = 0;
while (ptr < decoder.end) { while (ptr < decoder->end) {
char ch = *ptr++; char ch = *ptr++;
if (ch <= kUpb_EncodedValue_MaxEnumMask) { if (ch <= kUpb_EncodedValue_MaxEnumMask) {
uint32_t mask = _upb_FromBase92(ch); uint32_t mask = _upb_FromBase92(ch);
for (int i = 0; i < 5; i++, base++, mask >>= 1) { for (int i = 0; i < 5; i++, base++, mask >>= 1) {
if (mask & 1) upb_MiniTableEnum_BuildValue(&decoder, base); if (mask & 1) upb_MiniTableEnum_BuildValue(decoder, base);
} }
} else if (kUpb_EncodedValue_MinSkip <= ch && } else if (kUpb_EncodedValue_MinSkip <= ch &&
ch <= kUpb_EncodedValue_MaxSkip) { ch <= kUpb_EncodedValue_MaxSkip) {
uint32_t skip; uint32_t skip;
ptr = upb_MiniTable_DecodeBase92Varint(&decoder, ptr, ch, ptr = upb_MiniTable_DecodeBase92Varint(decoder, ptr, ch,
kUpb_EncodedValue_MinSkip, kUpb_EncodedValue_MinSkip,
kUpb_EncodedValue_MaxSkip, &skip); kUpb_EncodedValue_MaxSkip, &skip);
base += skip; base += skip;
} else { } else {
upb_MtDecoder_ErrorFormat(&decoder, "Unexpected character: %c", ch); upb_MtDecoder_ErrorFormat(decoder, "Unexpected character: %c", ch);
return NULL; return NULL;
} }
} }
return decoder.enum_table; return decoder->enum_table;
} }
const char* _upb_MiniTableExtension_Build(const char* data, size_t len, static upb_MiniTableEnum* upb_MtDecoder_BuildMiniTableEnum(
upb_MiniTableExtension* ext, upb_MtDecoder* const decoder, const char* const data, size_t const len) {
const upb_MiniTable* extendee, if (UPB_SETJMP(decoder->err) != 0) return NULL;
upb_MiniTableSub sub, return upb_MtDecoder_DoBuildMiniTableEnum(decoder, data, len);
upb_MiniTablePlatform platform, }
upb_MiniTableEnum* upb_MiniTableEnum_Build(const char* data, size_t len,
upb_Arena* arena,
upb_Status* status) { upb_Status* status) {
upb_MtDecoder decoder = { upb_MtDecoder decoder = {
.arena = NULL, .enum_table = upb_Arena_Malloc(arena, upb_MiniTableEnum_Size(2)),
.enum_value_count = 0,
.enum_data_count = 0,
.enum_data_capacity = 1,
.status = status, .status = status,
.table = NULL, .end = UPB_PTRADD(data, len),
.platform = platform, .arena = arena,
}; };
if (UPB_SETJMP(decoder.err)) return NULL; return upb_MtDecoder_BuildMiniTableEnum(&decoder, data, len);
}
static const char* upb_MtDecoder_DoBuildMiniTableExtension(
upb_MtDecoder* decoder, const char* data, size_t len,
upb_MiniTableExtension* ext, const upb_MiniTable* extendee,
upb_MiniTableSub sub) {
// If the string is non-empty then it must begin with a version tag. // If the string is non-empty then it must begin with a version tag.
if (len) { if (len) {
if (*data != kUpb_EncodedVersion_ExtensionV1) { if (*data != kUpb_EncodedVersion_ExtensionV1) {
upb_MtDecoder_ErrorFormat(&decoder, "Invalid ext version: %c", *data); upb_MtDecoder_ErrorFormat(decoder, "Invalid ext version: %c", *data);
UPB_UNREACHABLE(); UPB_UNREACHABLE();
} }
data++; data++;
@ -930,7 +943,7 @@ const char* _upb_MiniTableExtension_Build(const char* data, size_t len,
uint16_t count = 0; uint16_t count = 0;
const char* ret = const char* ret =
upb_MtDecoder_Parse(&decoder, data, len, ext, sizeof(*ext), &count, NULL); upb_MtDecoder_Parse(decoder, data, len, ext, sizeof(*ext), &count, NULL);
if (!ret || count != 1) return NULL; if (!ret || count != 1) return NULL;
upb_MiniTableField* f = &ext->field; upb_MiniTableField* f = &ext->field;
@ -953,6 +966,32 @@ const char* _upb_MiniTableExtension_Build(const char* data, size_t len,
return ret; return ret;
} }
static const char* upb_MtDecoder_BuildMiniTableExtension(
upb_MtDecoder* const decoder, const char* const data, const size_t len,
upb_MiniTableExtension* const ext, const upb_MiniTable* const extendee,
const upb_MiniTableSub sub) {
if (UPB_SETJMP(decoder->err) != 0) return NULL;
return upb_MtDecoder_DoBuildMiniTableExtension(decoder, data, len, ext,
extendee, sub);
}
const char* _upb_MiniTableExtension_Build(const char* data, size_t len,
upb_MiniTableExtension* ext,
const upb_MiniTable* extendee,
upb_MiniTableSub sub,
upb_MiniTablePlatform platform,
upb_Status* status) {
upb_MtDecoder decoder = {
.arena = NULL,
.status = status,
.table = NULL,
.platform = platform,
};
return upb_MtDecoder_BuildMiniTableExtension(&decoder, data, len, ext,
extendee, sub);
}
upb_MiniTable* _upb_MiniTable_Build(const char* data, size_t len, upb_MiniTable* _upb_MiniTable_Build(const char* data, size_t len,
upb_MiniTablePlatform platform, upb_MiniTablePlatform platform,
upb_Arena* arena, upb_Status* status) { upb_Arena* arena, upb_Status* status) {

Loading…
Cancel
Save