upb_Encode() now returns a status value

PiperOrigin-RevId: 454740100
pull/13171/head
Protobuf Team Bot 3 years ago committed by Copybara-Service
parent 65cd34dd00
commit 65bde4e75b
  1. 19
      python/descriptor.c
  2. 10
      python/message.c
  3. 18
      upb/bindings/lua/msg.c
  4. 6
      upb/conformance_upb.c
  5. 48
      upb/encode.c
  6. 22
      upb/encode.h
  7. 7
      upb/json_decode.c
  8. 11
      upb/mini_table_accessors.c
  9. 12
      upb/msg_test.cc
  10. 6
      upb/util/def_to_proto_test.cc
  11. 10
      upbc/protoc-gen-upb.cc

@ -123,14 +123,16 @@ static PyObject* PyUpb_DescriptorBase_GetOptions(PyUpb_DescriptorBase* self,
size_t size;
PyObject* py_arena = PyUpb_Arena_New();
upb_Arena* arena = PyUpb_Arena_Get(py_arena);
char* pb = upb_Encode(opts, layout, 0, arena, &size);
char* pb;
// TODO(b/235839510): Need to correctly handle failed return codes.
(void)upb_Encode(opts, layout, 0, arena, &pb, &size);
upb_Message* opts2 = upb_Message_New(m, arena);
assert(opts2);
bool ok = upb_Decode(pb, size, opts2, upb_MessageDef_MiniTable(m),
upb_DefPool_ExtensionRegistry(symtab), 0,
arena) == kUpb_DecodeStatus_Ok;
(void)ok;
assert(ok);
upb_DecodeStatus ds =
upb_Decode(pb, size, opts2, upb_MessageDef_MiniTable(m),
upb_DefPool_ExtensionRegistry(symtab), 0, arena);
(void)ds;
assert(ds == kUpb_DecodeStatus_Ok);
self->options = PyUpb_Message_Get(opts2, m, py_arena);
Py_DECREF(py_arena);
@ -150,8 +152,9 @@ static PyObject* PyUpb_DescriptorBase_GetSerializedProto(
upb_Message* proto = func(self->def, arena);
if (!proto) goto oom;
size_t size;
char* pb = upb_Encode(proto, layout, 0, arena, &size);
if (!pb) goto oom;
char* pb;
upb_EncodeStatus status = upb_Encode(proto, layout, 0, arena, &pb, &size);
if (status) goto oom; // TODO(b/235839510) non-oom errors are possible here
PyObject* str = PyBytes_FromStringAndSize(pb, size);
upb_Arena_Free(arena);
return str;

@ -1487,12 +1487,14 @@ PyObject* PyUpb_Message_SerializeInternal(PyObject* _self, PyObject* args,
size_t size = 0;
// Python does not currently have any effective limit on serialization depth.
int options = UPB_ENCODE_MAXDEPTH(UINT32_MAX);
if (check_required) options |= kUpb_Encode_CheckRequired;
if (deterministic) options |= kUpb_Encode_Deterministic;
char* pb = upb_Encode(self->ptr.msg, layout, options, arena, &size);
if (check_required) options |= kUpb_EncodeOption_CheckRequired;
if (deterministic) options |= kUpb_EncodeOption_Deterministic;
char* pb;
upb_EncodeStatus status =
upb_Encode(self->ptr.msg, layout, options, arena, &pb, &size);
PyObject* ret = NULL;
if (!pb) {
if (status != kUpb_EncodeStatus_Ok) {
PyUpb_ModuleState* state = PyUpb_ModuleState_Get();
PyObject* errors = PyUpb_Message_FindInitializationErrors(_self, NULL);
if (PyList_Size(errors) != 0) {

@ -983,19 +983,17 @@ static int lupb_Encode(lua_State* L) {
const upb_MessageDef* m = lupb_Message_Getmsgdef(L, 1);
const upb_MiniTable* layout = upb_MessageDef_MiniTable(m);
int options = lupb_getoptions(L, 2);
upb_Arena* arena;
upb_Arena* arena = lupb_Arena_pushnew(L);
char* buf;
size_t size;
char* result;
arena = lupb_Arena_pushnew(L);
result = upb_Encode(msg, (const void*)layout, options, arena, &size);
if (!result) {
upb_EncodeStatus status =
upb_Encode(msg, (const void*)layout, options, arena, &buf, &size);
if (status != kUpb_EncodeStatus_Ok) {
lua_pushstring(L, "Error encoding protobuf.");
return lua_error(L);
}
lua_pushlstring(L, result, size);
lua_pushlstring(L, buf, size);
return 1;
}
@ -1106,8 +1104,8 @@ void lupb_msg_registertypes(lua_State* L) {
lupb_setfieldi(L, "TXTENC_SKIPUNKNOWN", UPB_TXTENC_SKIPUNKNOWN);
lupb_setfieldi(L, "TXTENC_NOSORT", UPB_TXTENC_NOSORT);
lupb_setfieldi(L, "ENCODE_DETERMINISTIC", kUpb_Encode_Deterministic);
lupb_setfieldi(L, "ENCODE_SKIPUNKNOWN", kUpb_Encode_SkipUnknown);
lupb_setfieldi(L, "ENCODE_DETERMINISTIC", kUpb_EncodeOption_Deterministic);
lupb_setfieldi(L, "ENCODE_SKIPUNKNOWN", kUpb_EncodeOption_SkipUnknown);
lupb_setfieldi(L, "JSONENC_EMITDEFAULTS", upb_JsonEncode_EmitDefaults);
lupb_setfieldi(L, "JSONENC_PROTONAMES", upb_JsonEncode_UseProtoNames);

@ -102,8 +102,10 @@ bool parse_proto(upb_Message* msg, const upb_MessageDef* m, const ctx* c) {
void serialize_proto(const upb_Message* msg, const upb_MessageDef* m,
const ctx* c) {
size_t len;
char* data = upb_Encode(msg, upb_MessageDef_MiniTable(m), 0, c->arena, &len);
if (data) {
char* data;
upb_EncodeStatus status =
upb_Encode(msg, upb_MessageDef_MiniTable(m), 0, c->arena, &data, &len);
if (status == kUpb_EncodeStatus_Ok) {
conformance_ConformanceResponse_set_protobuf_payload(
c->response, upb_StringView_FromDataAndSize(data, len));
} else {

@ -76,7 +76,9 @@ static size_t upb_roundup_pow2(size_t bytes) {
return ret;
}
UPB_NORETURN static void encode_err(upb_encstate* e) { UPB_LONGJMP(e->err, 1); }
UPB_NORETURN static void encode_err(upb_encstate* e, upb_EncodeStatus s) {
UPB_LONGJMP(e->err, s);
}
UPB_NOINLINE
static void encode_growbuffer(upb_encstate* e, size_t bytes) {
@ -84,7 +86,7 @@ static void encode_growbuffer(upb_encstate* e, size_t bytes) {
size_t new_size = upb_roundup_pow2(bytes + (e->limit - e->ptr));
char* new_buf = upb_realloc(e->alloc, e->buf, old_size, new_size);
if (!new_buf) encode_err(e);
if (!new_buf) encode_err(e, kUpb_EncodeStatus_OutOfMemory);
/* We want previous data at the end, realloc() put it at the beginning. */
if (old_size > 0) {
@ -255,7 +257,7 @@ static void encode_scalar(upb_encstate* e, const void* _field_mem,
if (submsg == NULL) {
return;
}
if (--e->depth == 0) encode_err(e);
if (--e->depth == 0) encode_err(e, kUpb_EncodeStatus_MaxDepthExceeded);
encode_tag(e, f->number, kUpb_WireType_EndGroup);
encode_message(e, submsg, subm, &size);
wire_type = kUpb_WireType_StartGroup;
@ -269,7 +271,7 @@ static void encode_scalar(upb_encstate* e, const void* _field_mem,
if (submsg == NULL) {
return;
}
if (--e->depth == 0) encode_err(e);
if (--e->depth == 0) encode_err(e, kUpb_EncodeStatus_MaxDepthExceeded);
encode_message(e, submsg, subm, &size);
encode_varint(e, size);
wire_type = kUpb_WireType_Delimited;
@ -355,7 +357,7 @@ static void encode_array(upb_encstate* e, const upb_Message* msg,
const void* const* start = _upb_array_constptr(arr);
const void* const* ptr = start + arr->len;
const upb_MiniTable* subm = subs[f->submsg_index].submsg;
if (--e->depth == 0) encode_err(e);
if (--e->depth == 0) encode_err(e, kUpb_EncodeStatus_MaxDepthExceeded);
do {
size_t size;
ptr--;
@ -370,7 +372,7 @@ static void encode_array(upb_encstate* e, const upb_Message* msg,
const void* const* start = _upb_array_constptr(arr);
const void* const* ptr = start + arr->len;
const upb_MiniTable* subm = subs[f->submsg_index].submsg;
if (--e->depth == 0) encode_err(e);
if (--e->depth == 0) encode_err(e, kUpb_EncodeStatus_MaxDepthExceeded);
do {
size_t size;
ptr--;
@ -413,7 +415,7 @@ static void encode_map(upb_encstate* e, const upb_Message* msg,
if (map == NULL) return;
if (e->options & kUpb_Encode_Deterministic) {
if (e->options & kUpb_EncodeOption_Deterministic) {
_upb_sortedmap sorted;
_upb_mapsorter_pushmap(&e->sorter, layout->fields[0].descriptortype, map,
&sorted);
@ -520,16 +522,16 @@ static void encode_message(upb_encstate* e, const upb_Message* msg,
const upb_MiniTable* m, size_t* size) {
size_t pre_len = e->limit - e->ptr;
if ((e->options & kUpb_Encode_CheckRequired) && m->required_count) {
if ((e->options & kUpb_EncodeOption_CheckRequired) && m->required_count) {
uint64_t msg_head;
memcpy(&msg_head, msg, 8);
msg_head = _upb_BigEndian_Swap64(msg_head);
if (upb_MiniTable_requiredmask(m) & ~msg_head) {
encode_err(e);
encode_err(e, kUpb_EncodeStatus_MissingRequired);
}
}
if ((e->options & kUpb_Encode_SkipUnknown) == 0) {
if ((e->options & kUpb_EncodeOption_SkipUnknown) == 0) {
size_t unknown_size;
const char* unknown = upb_Message_GetUnknown(msg, &unknown_size);
@ -570,8 +572,9 @@ static void encode_message(upb_encstate* e, const upb_Message* msg,
*size = (e->limit - e->ptr) - pre_len;
}
char* upb_Encode(const void* msg, const upb_MiniTable* l, int options,
upb_Arena* arena, size_t* size) {
upb_EncodeStatus upb_Encode(const void* msg, const upb_MiniTable* l,
int options, upb_Arena* arena, char** buf,
size_t* size) {
upb_encstate e;
unsigned depth = (unsigned)options >> 16;
@ -582,23 +585,28 @@ char* upb_Encode(const void* msg, const upb_MiniTable* l, int options,
e.depth = depth ? depth : 64;
e.options = options;
_upb_mapsorter_init(&e.sorter);
char* ret = NULL;
if (UPB_SETJMP(e.err)) {
*size = 0;
ret = NULL;
} else {
upb_EncodeStatus status = UPB_SETJMP(e.err);
// Unfortunately we must continue to perform hackery here because there are
// code paths which blindly copy the returned pointer without bothering to
// check for errors until much later (b/235839510). So we still set *buf to
// NULL on error and we still set it to non-NULL on a successful empty result.
if (status == kUpb_EncodeStatus_Ok) {
encode_message(&e, msg, l, size);
*size = e.limit - e.ptr;
if (*size == 0) {
static char ch;
ret = &ch;
*buf = &ch;
} else {
UPB_ASSERT(e.ptr);
ret = e.ptr;
*buf = e.ptr;
}
} else {
*buf = NULL;
*size = 0;
}
_upb_mapsorter_destroy(&e.sorter);
return ret;
return status;
}

@ -26,7 +26,7 @@
*/
/*
* upb_Encode: parsing into a upb_Message using a upb_MiniTable.
* upb_Encode: parsing from a upb_Message using a upb_MiniTable.
*/
#ifndef UPB_ENCODE_H_
@ -48,19 +48,29 @@ enum {
*
* If your proto contains maps, the encoder will need to malloc()/free()
* memory during encode. */
kUpb_Encode_Deterministic = 1,
kUpb_EncodeOption_Deterministic = 1,
/* When set, unknown fields are not printed. */
kUpb_Encode_SkipUnknown = 2,
kUpb_EncodeOption_SkipUnknown = 2,
/* When set, the encode will fail if any required fields are missing. */
kUpb_Encode_CheckRequired = 4,
kUpb_EncodeOption_CheckRequired = 4,
};
#define UPB_ENCODE_MAXDEPTH(depth) ((depth) << 16)
char* upb_Encode(const void* msg, const upb_MiniTable* l, int options,
upb_Arena* arena, size_t* size);
typedef enum {
kUpb_EncodeStatus_Ok = 0,
kUpb_EncodeStatus_OutOfMemory = 1, // Arena alloc failed
kUpb_EncodeStatus_MaxDepthExceeded = 2, // Exceeded UPB_ENCODE_MAXDEPTH
// kUpb_EncodeOption_CheckRequired failed but the parse otherwise succeeded.
kUpb_EncodeStatus_MissingRequired = 3,
} upb_EncodeStatus;
upb_EncodeStatus upb_Encode(const void* msg, const upb_MiniTable* l,
int options, upb_Arena* arena, char** buf,
size_t* size);
#include "upb/port_undef.inc"

@ -1431,8 +1431,11 @@ static void jsondec_any(jsondec* d, upb_Message* msg, const upb_MessageDef* m) {
jsondec_objend(d);
encoded.str_val.data = upb_Encode(any_msg, upb_MessageDef_MiniTable(any_m), 0,
d->arena, &encoded.str_val.size);
upb_EncodeStatus status =
upb_Encode(any_msg, upb_MessageDef_MiniTable(any_m), 0, d->arena,
(char**)&encoded.str_val.data, &encoded.str_val.size);
// TODO(b/235839510): We should fail gracefully here on a bad return status.
UPB_ASSERT(status == kUpb_EncodeStatus_Ok);
upb_Message_Set(msg, value_f, encoded, d->arena);
}

@ -247,12 +247,13 @@ upb_GetExtensionAsBytes_Status upb_MiniTable_GetExtensionAsBytes(
const upb_Message_Extension* msg_ext = _upb_Message_Getext(msg, ext_table);
UPB_ASSERT(ext_table->field.descriptortype == kUpb_FieldType_Message);
if (msg_ext) {
*extension_data = upb_Encode(msg_ext->data.ptr, msg_ext->ext->sub.submsg,
encode_options, arena, len);
if (extension_data) {
return kUpb_GetExtensionAsBytes_Ok;
upb_EncodeStatus status =
upb_Encode(msg_ext->data.ptr, msg_ext->ext->sub.submsg, encode_options,
arena, (char**)extension_data, len);
if (status != kUpb_EncodeStatus_Ok) {
return kUpb_GetExtensionAsBytes_EncodeError;
}
return kUpb_GetExtensionAsBytes_EncodeError;
return kUpb_GetExtensionAsBytes_Ok;
}
int field_number = ext_table->field.number;
find_unknown_ret result = UnknownFieldSet_FindField(msg, field_number);

@ -407,13 +407,13 @@ TEST(MessageTest, EncodeRequiredFields) {
// Fails, we asked for required field checking but the required field is
// missing.
serialized = upb_test_TestRequiredFields_serialize_ex(
test_msg, kUpb_Encode_CheckRequired, arena.ptr(), &size);
test_msg, kUpb_EncodeOption_CheckRequired, arena.ptr(), &size);
ASSERT_TRUE(serialized == nullptr);
// Fails, some required fields are present but not others.
upb_test_TestRequiredFields_set_required_int32(test_msg, 1);
serialized = upb_test_TestRequiredFields_serialize_ex(
test_msg, kUpb_Encode_CheckRequired, arena.ptr(), &size);
test_msg, kUpb_EncodeOption_CheckRequired, arena.ptr(), &size);
ASSERT_TRUE(serialized == nullptr);
// Succeeds, all required fields are set.
@ -421,7 +421,7 @@ TEST(MessageTest, EncodeRequiredFields) {
upb_test_TestRequiredFields_set_required_int64(test_msg, 2);
upb_test_TestRequiredFields_set_required_message(test_msg, empty_msg);
serialized = upb_test_TestRequiredFields_serialize_ex(
test_msg, kUpb_Encode_CheckRequired, arena.ptr(), &size);
test_msg, kUpb_EncodeOption_CheckRequired, arena.ptr(), &size);
ASSERT_TRUE(serialized != nullptr);
}
@ -434,7 +434,7 @@ TEST(MessageTest, MaxRequiredFields) {
// missing.
size_t size;
char* serialized = upb_test_TestMaxRequiredFields_serialize_ex(
test_msg, kUpb_Encode_CheckRequired, arena.ptr(), &size);
test_msg, kUpb_EncodeOption_CheckRequired, arena.ptr(), &size);
ASSERT_TRUE(serialized == nullptr);
upb::SymbolTable symtab;
@ -449,7 +449,7 @@ TEST(MessageTest, MaxRequiredFields) {
// Fails, field 63 still isn't set.
serialized = upb_test_TestMaxRequiredFields_serialize_ex(
test_msg, kUpb_Encode_CheckRequired, arena.ptr(), &size);
test_msg, kUpb_EncodeOption_CheckRequired, arena.ptr(), &size);
ASSERT_TRUE(serialized == nullptr);
// Succeeds, all required fields are set.
@ -457,7 +457,7 @@ TEST(MessageTest, MaxRequiredFields) {
ASSERT_TRUE(f);
upb_Message_Set(test_msg, f.ptr(), val, arena.ptr());
serialized = upb_test_TestMaxRequiredFields_serialize_ex(
test_msg, kUpb_Encode_CheckRequired, arena.ptr(), &size);
test_msg, kUpb_EncodeOption_CheckRequired, arena.ptr(), &size);
ASSERT_TRUE(serialized != nullptr);
}

@ -65,9 +65,11 @@ std::unique_ptr<google::protobuf::Message> ToProto(
EXPECT_TRUE(desc != nullptr);
std::unique_ptr<google::protobuf::Message> google_msg(
factory->GetPrototype(desc)->New());
char* buf;
size_t size;
const char* buf =
upb_Encode(msg, upb_MessageDef_MiniTable(msgdef), 0, arena.ptr(), &size);
upb_EncodeStatus status = upb_Encode(msg, upb_MessageDef_MiniTable(msgdef), 0,
arena.ptr(), &buf, &size);
EXPECT_EQ(status, kUpb_EncodeStatus_Ok);
google_msg->ParseFromArray(buf, size);
return google_msg;
}

@ -801,6 +801,8 @@ void GenerateExtensionInHeader(const protobuf::FieldDescriptor* ext,
void GenerateMessageFunctionsInHeader(const protobuf::Descriptor* message,
Output& output) {
// TODO(b/235839510): The generated code here does not check the return values
// from upb_Encode(). How can we even fix this without breaking other things?
output(
R"cc(
UPB_INLINE $0* $0_new(upb_Arena* arena) {
@ -826,11 +828,15 @@ void GenerateMessageFunctionsInHeader(const protobuf::Descriptor* message,
return ret;
}
UPB_INLINE char* $0_serialize(const $0* msg, upb_Arena* arena, size_t* len) {
return upb_Encode(msg, &$1, 0, arena, len);
char* ptr;
(void)upb_Encode(msg, &$1, 0, arena, &ptr, len);
return ptr;
}
UPB_INLINE char* $0_serialize_ex(const $0* msg, int options,
upb_Arena* arena, size_t* len) {
return upb_Encode(msg, &$1, options, arena, len);
char* ptr;
(void)upb_Encode(msg, &$1, options, arena, &ptr, len);
return ptr;
}
)cc",
MessageName(message), MessageInit(message));

Loading…
Cancel
Save