summaryrefslogtreecommitdiff
path: root/grpc/third_party/upb/tests/pb/test_decoder.cc
diff options
context:
space:
mode:
Diffstat (limited to 'grpc/third_party/upb/tests/pb/test_decoder.cc')
-rw-r--r--grpc/third_party/upb/tests/pb/test_decoder.cc1194
1 files changed, 0 insertions, 1194 deletions
diff --git a/grpc/third_party/upb/tests/pb/test_decoder.cc b/grpc/third_party/upb/tests/pb/test_decoder.cc
deleted file mode 100644
index 110dd2f9..00000000
--- a/grpc/third_party/upb/tests/pb/test_decoder.cc
+++ /dev/null
@@ -1,1194 +0,0 @@
-/*
- *
- * An exhaustive set of tests for parsing both valid and invalid protobuf
- * input, with buffer breaks in arbitrary places.
- *
- * Tests to add:
- * - string/bytes
- * - unknown field handler called appropriately
- * - unknown fields can be inserted in random places
- * - fuzzing of valid input
- * - resource limits (max stack depth, max string len)
- * - testing of groups
- * - more throrough testing of sequences
- * - test skipping of submessages
- * - test suspending the decoder
- * - buffers that are close enough to the end of the address space that
- * pointers overflow (this might be difficult).
- * - a few "kitchen sink" examples (one proto that uses all types, lots
- * of submsg/sequences, etc.
- * - test different handlers at every level and whether handlers fire at
- * the correct field path.
- * - test skips that extend past the end of current buffer (where decoder
- * returns value greater than the size param).
- */
-
-#ifndef __STDC_FORMAT_MACROS
-#define __STDC_FORMAT_MACROS // For PRIuS, etc.
-#endif
-
-#include <inttypes.h>
-#include <stdarg.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sstream>
-
-#include "tests/test_util.h"
-#include "tests/upb_test.h"
-#include "tests/pb/test_decoder.upbdefs.h"
-
-#ifdef AMALGAMATED
-#include "upb.h"
-#else // AMALGAMATED
-#include "upb/handlers.h"
-#include "upb/pb/decoder.h"
-#include "upb/upb.h"
-#endif // !AMALGAMATED
-
-#include "upb/port_def.inc"
-
-#undef PRINT_FAILURE
-#define PRINT_FAILURE(expr) \
- fprintf(stderr, "Assertion failed: %s:%d\n", __FILE__, __LINE__); \
- fprintf(stderr, "expr: %s\n", #expr); \
-
-#define MAX_NESTING 64
-
-#define LINE(x) x "\n"
-
-uint32_t filter_hash = 0;
-double completed;
-double total;
-double *count;
-
-enum TestMode {
- COUNT_ONLY = 1,
- NO_HANDLERS = 2,
- ALL_HANDLERS = 3
-} test_mode;
-
-// Copied from decoder.c, since this is not a public interface.
-typedef struct {
- uint8_t native_wire_type;
- bool is_numeric;
-} upb_decoder_typeinfo;
-
-static const upb_decoder_typeinfo upb_decoder_types[] = {
- {UPB_WIRE_TYPE_END_GROUP, false}, // ENDGROUP
- {UPB_WIRE_TYPE_64BIT, true}, // DOUBLE
- {UPB_WIRE_TYPE_32BIT, true}, // FLOAT
- {UPB_WIRE_TYPE_VARINT, true}, // INT64
- {UPB_WIRE_TYPE_VARINT, true}, // UINT64
- {UPB_WIRE_TYPE_VARINT, true}, // INT32
- {UPB_WIRE_TYPE_64BIT, true}, // FIXED64
- {UPB_WIRE_TYPE_32BIT, true}, // FIXED32
- {UPB_WIRE_TYPE_VARINT, true}, // BOOL
- {UPB_WIRE_TYPE_DELIMITED, false}, // STRING
- {UPB_WIRE_TYPE_START_GROUP, false}, // GROUP
- {UPB_WIRE_TYPE_DELIMITED, false}, // MESSAGE
- {UPB_WIRE_TYPE_DELIMITED, false}, // BYTES
- {UPB_WIRE_TYPE_VARINT, true}, // UINT32
- {UPB_WIRE_TYPE_VARINT, true}, // ENUM
- {UPB_WIRE_TYPE_32BIT, true}, // SFIXED32
- {UPB_WIRE_TYPE_64BIT, true}, // SFIXED64
- {UPB_WIRE_TYPE_VARINT, true}, // SINT32
- {UPB_WIRE_TYPE_VARINT, true}, // SINT64
-};
-
-#ifndef USE_GOOGLE
-using std::string;
-#endif
-
-void vappendf(string* str, const char *format, va_list args) {
- va_list copy;
- va_copy(copy, args);
-
- int count = vsnprintf(NULL, 0, format, args);
- if (count >= 0)
- {
- UPB_ASSERT(count < 32768);
- char *buffer = new char[count + 1];
- UPB_ASSERT(buffer);
- count = vsnprintf(buffer, count + 1, format, copy);
- UPB_ASSERT(count >= 0);
- str->append(buffer, count);
- delete [] buffer;
- }
- va_end(copy);
-}
-
-void appendf(string* str, const char *fmt, ...) {
- va_list args;
- va_start(args, fmt);
- vappendf(str, fmt, args);
- va_end(args);
-}
-
-void PrintBinary(const string& str) {
- for (size_t i = 0; i < str.size(); i++) {
- if (isprint(str[i])) {
- fprintf(stderr, "%c", str[i]);
- } else {
- fprintf(stderr, "\\x%02x", (int)(uint8_t)str[i]);
- }
- }
-}
-
-#define UPB_PB_VARINT_MAX_LEN 10
-
-static size_t upb_vencode64(uint64_t val, char *buf) {
- size_t i;
- if (val == 0) { buf[0] = 0; return 1; }
- i = 0;
- while (val) {
- uint8_t byte = val & 0x7fU;
- val >>= 7;
- if (val) byte |= 0x80U;
- buf[i++] = byte;
- }
- return i;
-}
-
-static uint32_t upb_zzenc_32(int32_t n) {
- return ((uint32_t)n << 1) ^ (n >> 31);
-}
-
-static uint64_t upb_zzenc_64(int64_t n) {
- return ((uint64_t)n << 1) ^ (n >> 63);
-}
-
-/* Routines for building arbitrary protos *************************************/
-
-const string empty;
-
-string cat(const string& a, const string& b,
- const string& c = empty,
- const string& d = empty,
- const string& e = empty,
- const string& f = empty,
- const string& g = empty,
- const string& h = empty,
- const string& i = empty,
- const string& j = empty,
- const string& k = empty,
- const string& l = empty) {
- string ret;
- ret.reserve(a.size() + b.size() + c.size() + d.size() + e.size() + f.size() +
- g.size() + h.size() + i.size() + j.size() + k.size() + l.size());
- ret.append(a);
- ret.append(b);
- ret.append(c);
- ret.append(d);
- ret.append(e);
- ret.append(f);
- ret.append(g);
- ret.append(h);
- ret.append(i);
- ret.append(j);
- ret.append(k);
- ret.append(l);
- return ret;
-}
-
-template <typename T>
-string num2string(T num) {
- std::ostringstream ss;
- ss << num;
- return ss.str();
-}
-
-string varint(uint64_t x) {
- char buf[UPB_PB_VARINT_MAX_LEN];
- size_t len = upb_vencode64(x, buf);
- return string(buf, len);
-}
-
-// TODO: proper byte-swapping for big-endian machines.
-string fixed32(void *data) { return string(static_cast<char*>(data), 4); }
-string fixed64(void *data) { return string(static_cast<char*>(data), 8); }
-
-string delim(const string& buf) { return cat(varint(buf.size()), buf); }
-string uint32(uint32_t u32) { return fixed32(&u32); }
-string uint64(uint64_t u64) { return fixed64(&u64); }
-string flt(float f) { return fixed32(&f); }
-string dbl(double d) { return fixed64(&d); }
-string zz32(int32_t x) { return varint(upb_zzenc_32(x)); }
-string zz64(int64_t x) { return varint(upb_zzenc_64(x)); }
-
-string tag(uint32_t fieldnum, char wire_type) {
- return varint((fieldnum << 3) | wire_type);
-}
-
-string submsg(uint32_t fn, const string& buf) {
- return cat( tag(fn, UPB_WIRE_TYPE_DELIMITED), delim(buf) );
-}
-
-string group(uint32_t fn, const string& buf) {
- return cat(tag(fn, UPB_WIRE_TYPE_START_GROUP), buf,
- tag(fn, UPB_WIRE_TYPE_END_GROUP));
-}
-
-// Like delim()/submsg(), but intentionally encodes an incorrect length.
-// These help test when a delimited boundary doesn't land in the right place.
-string badlen_delim(int err, const string& buf) {
- return cat(varint(buf.size() + err), buf);
-}
-
-string badlen_submsg(int err, uint32_t fn, const string& buf) {
- return cat( tag(fn, UPB_WIRE_TYPE_DELIMITED), badlen_delim(err, buf) );
-}
-
-
-/* A set of handlers that covers all .proto types *****************************/
-
-// The handlers simply append to a string indicating what handlers were called.
-// This string is similar to protobuf text format but fields are referred to by
-// number instead of name and sequences are explicitly delimited. We indent
-// using the closure depth to test that the stack of closures is properly
-// handled.
-
-int closures[MAX_NESTING];
-string output;
-
-void indentbuf(string *buf, int depth) {
- buf->append(2 * depth, ' ');
-}
-
-#define NUMERIC_VALUE_HANDLER(member, ctype, fmt) \
- bool value_##member(int* depth, const uint32_t* num, ctype val) { \
- indentbuf(&output, *depth); \
- appendf(&output, "%" PRIu32 ":%" fmt "\n", *num, val); \
- return true; \
- }
-
-NUMERIC_VALUE_HANDLER(uint32, uint32_t, PRIu32)
-NUMERIC_VALUE_HANDLER(uint64, uint64_t, PRIu64)
-NUMERIC_VALUE_HANDLER(int32, int32_t, PRId32)
-NUMERIC_VALUE_HANDLER(int64, int64_t, PRId64)
-NUMERIC_VALUE_HANDLER(float, float, "g")
-NUMERIC_VALUE_HANDLER(double, double, "g")
-
-bool value_bool(int* depth, const uint32_t* num, bool val) {
- indentbuf(&output, *depth);
- appendf(&output, "%" PRIu32 ":%s\n", *num, val ? "true" : "false");
- return true;
-}
-
-int* startstr(int* depth, const uint32_t* num, size_t size_hint) {
- indentbuf(&output, *depth);
- appendf(&output, "%" PRIu32 ":(%zu)\"", *num, size_hint);
- return depth + 1;
-}
-
-size_t value_string(int* depth, const uint32_t* num, const char* buf,
- size_t n, const upb_bufhandle* handle) {
- UPB_UNUSED(num);
- UPB_UNUSED(depth);
- output.append(buf, n);
- ASSERT(handle == &global_handle);
- return n;
-}
-
-bool endstr(int* depth, const uint32_t* num) {
- UPB_UNUSED(num);
- output.append("\n");
- indentbuf(&output, *depth);
- appendf(&output, "%" PRIu32 ":\"\n", *num);
- return true;
-}
-
-int* startsubmsg(int* depth, const uint32_t* num) {
- indentbuf(&output, *depth);
- appendf(&output, "%" PRIu32 ":{\n", *num);
- return depth + 1;
-}
-
-bool endsubmsg(int* depth, const uint32_t* num) {
- UPB_UNUSED(num);
- indentbuf(&output, *depth);
- output.append("}\n");
- return true;
-}
-
-int* startseq(int* depth, const uint32_t* num) {
- indentbuf(&output, *depth);
- appendf(&output, "%" PRIu32 ":[\n", *num);
- return depth + 1;
-}
-
-bool endseq(int* depth, const uint32_t* num) {
- UPB_UNUSED(num);
- indentbuf(&output, *depth);
- output.append("]\n");
- return true;
-}
-
-bool startmsg(int* depth) {
- indentbuf(&output, *depth);
- output.append("<\n");
- return true;
-}
-
-bool endmsg(int* depth, upb_status* status) {
- UPB_UNUSED(status);
- indentbuf(&output, *depth);
- output.append(">\n");
- return true;
-}
-
-void free_uint32(void *val) {
- uint32_t *u32 = static_cast<uint32_t*>(val);
- delete u32;
-}
-
-template<class T, bool F(int*, const uint32_t*, T)>
-void doreg(upb::HandlersPtr h, uint32_t num) {
- upb::FieldDefPtr f = h.message_def().FindFieldByNumber(num);
- ASSERT(f);
- ASSERT(h.SetValueHandler<T>(f, UpbBind(F, new uint32_t(num))));
- if (f.IsSequence()) {
- ASSERT(h.SetStartSequenceHandler(f, UpbBind(startseq, new uint32_t(num))));
- ASSERT(h.SetEndSequenceHandler(f, UpbBind(endseq, new uint32_t(num))));
- }
-}
-
-// The repeated field number to correspond to the given non-repeated field
-// number.
-uint32_t rep_fn(uint32_t fn) {
- return (UPB_MAX_FIELDNUMBER - 1000) + fn;
-}
-
-#define NOP_FIELD 40
-#define UNKNOWN_FIELD 666
-
-template <class T, bool F(int*, const uint32_t*, T)>
-void reg(upb::HandlersPtr h, upb_descriptortype_t type) {
- // We register both a repeated and a non-repeated field for every type.
- // For the non-repeated field we make the field number the same as the
- // type. For the repeated field we make it a function of the type.
- doreg<T, F>(h, type);
- doreg<T, F>(h, rep_fn(type));
-}
-
-void regseq(upb::HandlersPtr h, upb::FieldDefPtr f, uint32_t num) {
- ASSERT(h.SetStartSequenceHandler(f, UpbBind(startseq, new uint32_t(num))));
- ASSERT(h.SetEndSequenceHandler(f, UpbBind(endseq, new uint32_t(num))));
-}
-
-void reg_subm(upb::HandlersPtr h, uint32_t num) {
- upb::FieldDefPtr f = h.message_def().FindFieldByNumber(num);
- ASSERT(f);
- if (f.IsSequence()) regseq(h, f, num);
- ASSERT(
- h.SetStartSubMessageHandler(f, UpbBind(startsubmsg, new uint32_t(num))));
- ASSERT(h.SetEndSubMessageHandler(f, UpbBind(endsubmsg, new uint32_t(num))));
-}
-
-void reg_str(upb::HandlersPtr h, uint32_t num) {
- upb::FieldDefPtr f = h.message_def().FindFieldByNumber(num);
- ASSERT(f);
- if (f.IsSequence()) regseq(h, f, num);
- ASSERT(h.SetStartStringHandler(f, UpbBind(startstr, new uint32_t(num))));
- ASSERT(h.SetEndStringHandler(f, UpbBind(endstr, new uint32_t(num))));
- ASSERT(h.SetStringHandler(f, UpbBind(value_string, new uint32_t(num))));
-}
-
-struct HandlerRegisterData {
- TestMode mode;
-};
-
-void callback(const void *closure, upb::Handlers* h_ptr) {
- upb::HandlersPtr h(h_ptr);
- const HandlerRegisterData* data =
- static_cast<const HandlerRegisterData*>(closure);
- if (data->mode == ALL_HANDLERS) {
- h.SetStartMessageHandler(UpbMakeHandler(startmsg));
- h.SetEndMessageHandler(UpbMakeHandler(endmsg));
-
- // Register handlers for each type.
- reg<double, value_double>(h, UPB_DESCRIPTOR_TYPE_DOUBLE);
- reg<float, value_float> (h, UPB_DESCRIPTOR_TYPE_FLOAT);
- reg<int64_t, value_int64> (h, UPB_DESCRIPTOR_TYPE_INT64);
- reg<uint64_t, value_uint64>(h, UPB_DESCRIPTOR_TYPE_UINT64);
- reg<int32_t, value_int32> (h, UPB_DESCRIPTOR_TYPE_INT32);
- reg<uint64_t, value_uint64>(h, UPB_DESCRIPTOR_TYPE_FIXED64);
- reg<uint32_t, value_uint32>(h, UPB_DESCRIPTOR_TYPE_FIXED32);
- reg<bool, value_bool> (h, UPB_DESCRIPTOR_TYPE_BOOL);
- reg<uint32_t, value_uint32>(h, UPB_DESCRIPTOR_TYPE_UINT32);
- reg<int32_t, value_int32> (h, UPB_DESCRIPTOR_TYPE_ENUM);
- reg<int32_t, value_int32> (h, UPB_DESCRIPTOR_TYPE_SFIXED32);
- reg<int64_t, value_int64> (h, UPB_DESCRIPTOR_TYPE_SFIXED64);
- reg<int32_t, value_int32> (h, UPB_DESCRIPTOR_TYPE_SINT32);
- reg<int64_t, value_int64> (h, UPB_DESCRIPTOR_TYPE_SINT64);
-
- reg_str(h, UPB_DESCRIPTOR_TYPE_STRING);
- reg_str(h, UPB_DESCRIPTOR_TYPE_BYTES);
- reg_str(h, rep_fn(UPB_DESCRIPTOR_TYPE_STRING));
- reg_str(h, rep_fn(UPB_DESCRIPTOR_TYPE_BYTES));
-
- // Register submessage/group handlers that are self-recursive
- // to this type, eg: message M { optional M m = 1; }
- reg_subm(h, UPB_DESCRIPTOR_TYPE_MESSAGE);
- reg_subm(h, rep_fn(UPB_DESCRIPTOR_TYPE_MESSAGE));
-
- if (h.message_def().full_name() == std::string("DecoderTest")) {
- reg_subm(h, UPB_DESCRIPTOR_TYPE_GROUP);
- reg_subm(h, rep_fn(UPB_DESCRIPTOR_TYPE_GROUP));
- }
-
- // For NOP_FIELD we register no handlers, so we can pad a proto freely without
- // changing the output.
- }
-}
-
-/* Running of test cases ******************************************************/
-
-const upb::Handlers *global_handlers;
-upb::pb::DecoderMethodPtr global_method;
-
-upb::pb::DecoderPtr CreateDecoder(upb::Arena* arena,
- upb::pb::DecoderMethodPtr method,
- upb::Sink sink, upb::Status* status) {
- upb::pb::DecoderPtr ret =
- upb::pb::DecoderPtr::Create(arena, method, sink, status);
- ret.set_max_nesting(MAX_NESTING);
- return ret;
-}
-
-void CheckBytesParsed(upb::pb::DecoderPtr decoder, size_t ofs) {
- // We can't have parsed more data than the decoder callback is telling us it
- // parsed.
- ASSERT(decoder.BytesParsed() <= ofs);
-
- // The difference between what we've decoded and what the decoder has accepted
- // represents the internally buffered amount. This amount should not exceed
- // this value which comes from decoder.int.h.
- ASSERT(ofs <= (decoder.BytesParsed() + UPB_DECODER_MAX_RESIDUAL_BYTES));
-}
-
-static bool parse(VerboseParserEnvironment* env,
- upb::pb::DecoderPtr decoder, int bytes) {
- CheckBytesParsed(decoder, env->ofs());
- bool ret = env->ParseBuffer(bytes);
- if (ret) {
- CheckBytesParsed(decoder, env->ofs());
- }
-
- return ret;
-}
-
-void do_run_decoder(VerboseParserEnvironment* env, upb::pb::DecoderPtr decoder,
- const string& proto, const string* expected_output,
- size_t i, size_t j, bool may_skip) {
- env->Reset(proto.c_str(), proto.size(), may_skip, expected_output == NULL);
- decoder.Reset();
-
- if (test_mode != COUNT_ONLY) {
- output.clear();
-
- if (filter_hash) {
- fprintf(stderr, "RUNNING TEST CASE\n");
- fprintf(stderr, "Input (len=%u): ", (unsigned)proto.size());
- PrintBinary(proto);
- fprintf(stderr, "\n");
- if (expected_output) {
- if (test_mode == ALL_HANDLERS) {
- fprintf(stderr, "Expected output: %s\n", expected_output->c_str());
- } else if (test_mode == NO_HANDLERS) {
- fprintf(stderr,
- "No handlers are registered, BUT if they were "
- "the expected output would be: %s\n",
- expected_output->c_str());
- }
- } else {
- fprintf(stderr, "Expected to FAIL\n");
- }
- }
-
- bool ok = env->Start() &&
- parse(env, decoder, (int)i) &&
- parse(env, decoder, (int)(j - i)) &&
- parse(env, decoder, -1) &&
- env->End();
-
- ASSERT(env->CheckConsistency());
-
- if (test_mode == ALL_HANDLERS) {
- if (expected_output) {
- if (output != *expected_output) {
- fprintf(stderr, "Text mismatch: '%s' vs '%s'\n",
- output.c_str(), expected_output->c_str());
- }
- ASSERT(ok);
- ASSERT(output == *expected_output);
- } else {
- if (ok) {
- fprintf(stderr, "Didn't expect ok result, but got output: '%s'\n",
- output.c_str());
- }
- ASSERT(!ok);
- }
- }
- }
- (*count)++;
-}
-
-void run_decoder(const string& proto, const string* expected_output) {
- VerboseParserEnvironment env(filter_hash != 0);
- upb::Sink sink(global_handlers, &closures[0]);
- upb::pb::DecoderPtr decoder = CreateDecoder(env.arena(), global_method, sink, env.status());
- env.ResetBytesSink(decoder.input());
- for (size_t i = 0; i < proto.size(); i++) {
- for (size_t j = i; j < UPB_MIN(proto.size(), i + 5); j++) {
- do_run_decoder(&env, decoder, proto, expected_output, i, j, true);
- if (env.SkippedWithNull()) {
- do_run_decoder(&env, decoder, proto, expected_output, i, j, false);
- }
- }
- }
-}
-
-const static string thirty_byte_nop = cat(
- tag(NOP_FIELD, UPB_WIRE_TYPE_DELIMITED), delim(string(30, 'X')) );
-
-// Indents and wraps text as if it were a submessage with this field number
-string wrap_text(int32_t fn, const string& text) {
- string wrapped_text = text;
- size_t pos = 0;
- string replace_with = "\n ";
- while ((pos = wrapped_text.find("\n", pos)) != string::npos &&
- pos != wrapped_text.size() - 1) {
- wrapped_text.replace(pos, 1, replace_with);
- pos += replace_with.size();
- }
- wrapped_text = cat(
- LINE("<"),
- num2string(fn), LINE(":{")
- " ", wrapped_text,
- LINE(" }")
- LINE(">"));
- return wrapped_text;
-}
-
-void assert_successful_parse(const string& proto,
- const char *expected_fmt, ...) {
- string expected_text;
- va_list args;
- va_start(args, expected_fmt);
- vappendf(&expected_text, expected_fmt, args);
- va_end(args);
- // To test both middle-of-buffer and end-of-buffer code paths,
- // repeat once with no-op padding data at the end of buffer.
- run_decoder(proto, &expected_text);
- run_decoder(cat( proto, thirty_byte_nop ), &expected_text);
-
- // Test that this also works when wrapped in a submessage or group.
- // Indent the expected text one level and wrap it.
- string wrapped_text1 = wrap_text(UPB_DESCRIPTOR_TYPE_MESSAGE, expected_text);
- string wrapped_text2 = wrap_text(UPB_DESCRIPTOR_TYPE_GROUP, expected_text);
-
- run_decoder(submsg(UPB_DESCRIPTOR_TYPE_MESSAGE, proto), &wrapped_text1);
- run_decoder(group(UPB_DESCRIPTOR_TYPE_GROUP, proto), &wrapped_text2);
-}
-
-void assert_does_not_parse_at_eof(const string& proto) {
- run_decoder(proto, NULL);
-
- // Also test that we fail to parse at end-of-submessage, not just
- // end-of-message. But skip this if we have no handlers, because in that
- // case we won't descend into the submessage.
- if (test_mode != NO_HANDLERS) {
- run_decoder(submsg(UPB_DESCRIPTOR_TYPE_MESSAGE, proto), NULL);
- run_decoder(cat(submsg(UPB_DESCRIPTOR_TYPE_MESSAGE, proto),
- thirty_byte_nop), NULL);
- }
-}
-
-void assert_does_not_parse(const string& proto) {
- // Test that the error is caught both at end-of-buffer and middle-of-buffer.
- assert_does_not_parse_at_eof(proto);
- assert_does_not_parse_at_eof(cat( proto, thirty_byte_nop ));
-}
-
-
-/* The actual tests ***********************************************************/
-
-void test_premature_eof_for_type(upb_descriptortype_t type) {
- // Incomplete values for each wire type.
- static const string incompletes[6] = {
- string("\x80"), // UPB_WIRE_TYPE_VARINT
- string("abcdefg"), // UPB_WIRE_TYPE_64BIT
- string("\x80"), // UPB_WIRE_TYPE_DELIMITED (partial length)
- string(), // UPB_WIRE_TYPE_START_GROUP (no value required)
- string(), // UPB_WIRE_TYPE_END_GROUP (no value required)
- string("abc") // UPB_WIRE_TYPE_32BIT
- };
-
- uint32_t fieldnum = type;
- uint32_t rep_fieldnum = rep_fn(type);
- int wire_type = upb_decoder_types[type].native_wire_type;
- const string& incomplete = incompletes[wire_type];
-
- // EOF before a known non-repeated value.
- assert_does_not_parse_at_eof(tag(fieldnum, wire_type));
-
- // EOF before a known repeated value.
- assert_does_not_parse_at_eof(tag(rep_fieldnum, wire_type));
-
- // EOF before an unknown value.
- assert_does_not_parse_at_eof(tag(UNKNOWN_FIELD, wire_type));
-
- // EOF inside a known non-repeated value.
- assert_does_not_parse_at_eof(
- cat( tag(fieldnum, wire_type), incomplete ));
-
- // EOF inside a known repeated value.
- assert_does_not_parse_at_eof(
- cat( tag(rep_fieldnum, wire_type), incomplete ));
-
- // EOF inside an unknown value.
- assert_does_not_parse_at_eof(
- cat( tag(UNKNOWN_FIELD, wire_type), incomplete ));
-
- if (wire_type == UPB_WIRE_TYPE_DELIMITED) {
- // EOF in the middle of delimited data for known non-repeated value.
- assert_does_not_parse_at_eof(
- cat( tag(fieldnum, wire_type), varint(1) ));
-
- // EOF in the middle of delimited data for known repeated value.
- assert_does_not_parse_at_eof(
- cat( tag(rep_fieldnum, wire_type), varint(1) ));
-
- // EOF in the middle of delimited data for unknown value.
- assert_does_not_parse_at_eof(
- cat( tag(UNKNOWN_FIELD, wire_type), varint(1) ));
-
- if (type == UPB_DESCRIPTOR_TYPE_MESSAGE) {
- // Submessage ends in the middle of a value.
- string incomplete_submsg =
- cat ( tag(UPB_DESCRIPTOR_TYPE_INT32, UPB_WIRE_TYPE_VARINT),
- incompletes[UPB_WIRE_TYPE_VARINT] );
- assert_does_not_parse(
- cat( tag(fieldnum, UPB_WIRE_TYPE_DELIMITED),
- varint(incomplete_submsg.size()),
- incomplete_submsg ));
- }
- } else {
- // Packed region ends in the middle of a value.
- assert_does_not_parse(
- cat( tag(rep_fieldnum, UPB_WIRE_TYPE_DELIMITED),
- varint(incomplete.size()),
- incomplete ));
-
- // EOF in the middle of packed region.
- assert_does_not_parse_at_eof(
- cat( tag(rep_fieldnum, UPB_WIRE_TYPE_DELIMITED), varint(1) ));
- }
-}
-
-// "33" and "66" are just two random values that all numeric types can
-// represent.
-void test_valid_data_for_type(upb_descriptortype_t type,
- const string& enc33, const string& enc66) {
- uint32_t fieldnum = type;
- uint32_t rep_fieldnum = rep_fn(type);
- int wire_type = upb_decoder_types[type].native_wire_type;
-
- // Non-repeated
- assert_successful_parse(
- cat( tag(fieldnum, wire_type), enc33,
- tag(fieldnum, wire_type), enc66 ),
- LINE("<")
- LINE("%u:33")
- LINE("%u:66")
- LINE(">"), fieldnum, fieldnum);
-
- // Non-packed repeated.
- assert_successful_parse(
- cat( tag(rep_fieldnum, wire_type), enc33,
- tag(rep_fieldnum, wire_type), enc66 ),
- LINE("<")
- LINE("%u:[")
- LINE(" %u:33")
- LINE(" %u:66")
- LINE("]")
- LINE(">"), rep_fieldnum, rep_fieldnum, rep_fieldnum);
-
- // Packed repeated.
- assert_successful_parse(
- cat( tag(rep_fieldnum, UPB_WIRE_TYPE_DELIMITED),
- delim(cat( enc33, enc66 )) ),
- LINE("<")
- LINE("%u:[")
- LINE(" %u:33")
- LINE(" %u:66")
- LINE("]")
- LINE(">"), rep_fieldnum, rep_fieldnum, rep_fieldnum);
-}
-
-void test_valid_data_for_signed_type(upb_descriptortype_t type,
- const string& enc33, const string& enc66) {
- uint32_t fieldnum = type;
- uint32_t rep_fieldnum = rep_fn(type);
- int wire_type = upb_decoder_types[type].native_wire_type;
-
- // Non-repeated
- assert_successful_parse(
- cat( tag(fieldnum, wire_type), enc33,
- tag(fieldnum, wire_type), enc66 ),
- LINE("<")
- LINE("%u:33")
- LINE("%u:-66")
- LINE(">"), fieldnum, fieldnum);
-
- // Non-packed repeated.
- assert_successful_parse(
- cat( tag(rep_fieldnum, wire_type), enc33,
- tag(rep_fieldnum, wire_type), enc66 ),
- LINE("<")
- LINE("%u:[")
- LINE(" %u:33")
- LINE(" %u:-66")
- LINE("]")
- LINE(">"), rep_fieldnum, rep_fieldnum, rep_fieldnum);
-
- // Packed repeated.
- assert_successful_parse(
- cat( tag(rep_fieldnum, UPB_WIRE_TYPE_DELIMITED),
- delim(cat( enc33, enc66 )) ),
- LINE("<")
- LINE("%u:[")
- LINE(" %u:33")
- LINE(" %u:-66")
- LINE("]")
- LINE(">"), rep_fieldnum, rep_fieldnum, rep_fieldnum);
-}
-
-// Test that invalid protobufs are properly detected (without crashing) and
-// have an error reported. Field numbers match registered handlers above.
-void test_invalid() {
- test_premature_eof_for_type(UPB_DESCRIPTOR_TYPE_DOUBLE);
- test_premature_eof_for_type(UPB_DESCRIPTOR_TYPE_FLOAT);
- test_premature_eof_for_type(UPB_DESCRIPTOR_TYPE_INT64);
- test_premature_eof_for_type(UPB_DESCRIPTOR_TYPE_UINT64);
- test_premature_eof_for_type(UPB_DESCRIPTOR_TYPE_INT32);
- test_premature_eof_for_type(UPB_DESCRIPTOR_TYPE_FIXED64);
- test_premature_eof_for_type(UPB_DESCRIPTOR_TYPE_FIXED32);
- test_premature_eof_for_type(UPB_DESCRIPTOR_TYPE_BOOL);
- test_premature_eof_for_type(UPB_DESCRIPTOR_TYPE_STRING);
- test_premature_eof_for_type(UPB_DESCRIPTOR_TYPE_BYTES);
- test_premature_eof_for_type(UPB_DESCRIPTOR_TYPE_UINT32);
- test_premature_eof_for_type(UPB_DESCRIPTOR_TYPE_ENUM);
- test_premature_eof_for_type(UPB_DESCRIPTOR_TYPE_SFIXED32);
- test_premature_eof_for_type(UPB_DESCRIPTOR_TYPE_SFIXED64);
- test_premature_eof_for_type(UPB_DESCRIPTOR_TYPE_SINT32);
- test_premature_eof_for_type(UPB_DESCRIPTOR_TYPE_SINT64);
-
- // EOF inside a tag's varint.
- assert_does_not_parse_at_eof( string("\x80") );
-
- // EOF inside a known group.
- // TODO(haberman): add group to decoder test schema.
- //assert_does_not_parse_at_eof( tag(4, UPB_WIRE_TYPE_START_GROUP) );
-
- // EOF inside an unknown group.
- assert_does_not_parse_at_eof( tag(UNKNOWN_FIELD, UPB_WIRE_TYPE_START_GROUP) );
-
- // End group that we are not currently in.
- assert_does_not_parse( tag(4, UPB_WIRE_TYPE_END_GROUP) );
-
- // Field number is 0.
- assert_does_not_parse(
- cat( tag(0, UPB_WIRE_TYPE_DELIMITED), varint(0) ));
- // The previous test alone did not catch this particular pattern which could
- // corrupt the internal state.
- assert_does_not_parse(
- cat( tag(0, UPB_WIRE_TYPE_64BIT), uint64(0) ));
-
- // Field number is too large.
- assert_does_not_parse(
- cat( tag(UPB_MAX_FIELDNUMBER + 1, UPB_WIRE_TYPE_DELIMITED),
- varint(0) ));
-
- // Known group inside a submessage has ENDGROUP tag AFTER submessage end.
- assert_does_not_parse(
- cat ( submsg(UPB_DESCRIPTOR_TYPE_MESSAGE,
- tag(UPB_DESCRIPTOR_TYPE_GROUP, UPB_WIRE_TYPE_START_GROUP)),
- tag(UPB_DESCRIPTOR_TYPE_GROUP, UPB_WIRE_TYPE_END_GROUP)));
-
- // Unknown string extends past enclosing submessage.
- assert_does_not_parse(
- cat (badlen_submsg(-1, UPB_DESCRIPTOR_TYPE_MESSAGE,
- submsg(12345, string(" "))),
- submsg(UPB_DESCRIPTOR_TYPE_MESSAGE, string(" "))));
-
- // Unknown fixed-length field extends past enclosing submessage.
- assert_does_not_parse(
- cat (badlen_submsg(-1, UPB_DESCRIPTOR_TYPE_MESSAGE,
- cat( tag(12345, UPB_WIRE_TYPE_64BIT), uint64(0))),
- submsg(UPB_DESCRIPTOR_TYPE_MESSAGE, string(" "))));
-
- // Test exceeding the resource limit of stack depth.
- if (test_mode != NO_HANDLERS) {
- string buf;
- for (int i = 0; i <= MAX_NESTING; i++) {
- buf.assign(submsg(UPB_DESCRIPTOR_TYPE_MESSAGE, buf));
- }
- assert_does_not_parse(buf);
- }
-}
-
-void test_valid() {
- // Empty protobuf.
- assert_successful_parse(string(""), "<\n>\n");
-
- // Empty protobuf where we never call PutString between
- // StartString/EndString.
-
- upb::Status status;
- upb::Arena arena;
- upb::Sink sink(global_handlers, &closures[0]);
- upb::pb::DecoderPtr decoder =
- CreateDecoder(&arena, global_method, sink, &status);
- output.clear();
- bool ok = upb::PutBuffer(std::string(), decoder.input());
- ASSERT(ok);
- ASSERT(status.ok());
- if (test_mode == ALL_HANDLERS) {
- ASSERT(output == string("<\n>\n"));
- }
-
- test_valid_data_for_signed_type(UPB_DESCRIPTOR_TYPE_DOUBLE,
- dbl(33),
- dbl(-66));
- test_valid_data_for_signed_type(UPB_DESCRIPTOR_TYPE_FLOAT, flt(33), flt(-66));
- test_valid_data_for_signed_type(UPB_DESCRIPTOR_TYPE_INT64,
- varint(33),
- varint(-66));
- test_valid_data_for_signed_type(UPB_DESCRIPTOR_TYPE_INT32,
- varint(33),
- varint(-66));
- test_valid_data_for_signed_type(UPB_DESCRIPTOR_TYPE_ENUM,
- varint(33),
- varint(-66));
- test_valid_data_for_signed_type(UPB_DESCRIPTOR_TYPE_SFIXED32,
- uint32(33),
- uint32(-66));
- test_valid_data_for_signed_type(UPB_DESCRIPTOR_TYPE_SFIXED64,
- uint64(33),
- uint64(-66));
- test_valid_data_for_signed_type(UPB_DESCRIPTOR_TYPE_SINT32,
- zz32(33),
- zz32(-66));
- test_valid_data_for_signed_type(UPB_DESCRIPTOR_TYPE_SINT64,
- zz64(33),
- zz64(-66));
-
- test_valid_data_for_type(UPB_DESCRIPTOR_TYPE_UINT64, varint(33), varint(66));
- test_valid_data_for_type(UPB_DESCRIPTOR_TYPE_UINT32, varint(33), varint(66));
- test_valid_data_for_type(UPB_DESCRIPTOR_TYPE_FIXED64, uint64(33), uint64(66));
- test_valid_data_for_type(UPB_DESCRIPTOR_TYPE_FIXED32, uint32(33), uint32(66));
-
- // Unknown fields.
- int int32_type = UPB_DESCRIPTOR_TYPE_INT32;
- int msg_type = UPB_DESCRIPTOR_TYPE_MESSAGE;
- assert_successful_parse(
- cat( tag(12345, UPB_WIRE_TYPE_VARINT), varint(2345678) ),
- "<\n>\n");
- assert_successful_parse(
- cat( tag(12345, UPB_WIRE_TYPE_32BIT), uint32(2345678) ),
- "<\n>\n");
- assert_successful_parse(
- cat( tag(12345, UPB_WIRE_TYPE_64BIT), uint64(2345678) ),
- "<\n>\n");
- assert_successful_parse(
- submsg(12345, string(" ")),
- "<\n>\n");
-
- // Unknown field inside a known submessage.
- assert_successful_parse(
- submsg(UPB_DESCRIPTOR_TYPE_MESSAGE, submsg(12345, string(" "))),
- LINE("<")
- LINE("%u:{")
- LINE(" <")
- LINE(" >")
- LINE(" }")
- LINE(">"), UPB_DESCRIPTOR_TYPE_MESSAGE);
-
- assert_successful_parse(
- cat (submsg(UPB_DESCRIPTOR_TYPE_MESSAGE, submsg(12345, string(" "))),
- tag(UPB_DESCRIPTOR_TYPE_INT32, UPB_WIRE_TYPE_VARINT),
- varint(5)),
- LINE("<")
- LINE("%u:{")
- LINE(" <")
- LINE(" >")
- LINE(" }")
- LINE("%u:5")
- LINE(">"), UPB_DESCRIPTOR_TYPE_MESSAGE, UPB_DESCRIPTOR_TYPE_INT32);
-
- // This triggered a previous bug in the decoder.
- assert_successful_parse(
- cat( tag(UPB_DESCRIPTOR_TYPE_SFIXED32, UPB_WIRE_TYPE_VARINT),
- varint(0) ),
- "<\n>\n");
-
- assert_successful_parse(
- cat(
- submsg(UPB_DESCRIPTOR_TYPE_MESSAGE,
- submsg(UPB_DESCRIPTOR_TYPE_MESSAGE,
- cat( tag(int32_type, UPB_WIRE_TYPE_VARINT), varint(2345678),
- tag(12345, UPB_WIRE_TYPE_VARINT), varint(2345678) ))),
- tag(int32_type, UPB_WIRE_TYPE_VARINT), varint(22222)),
- LINE("<")
- LINE("%u:{")
- LINE(" <")
- LINE(" %u:{")
- LINE(" <")
- LINE(" %u:2345678")
- LINE(" >")
- LINE(" }")
- LINE(" >")
- LINE(" }")
- LINE("%u:22222")
- LINE(">"), msg_type, msg_type, int32_type, int32_type);
-
- assert_successful_parse(
- cat( tag(UPB_DESCRIPTOR_TYPE_INT32, UPB_WIRE_TYPE_VARINT), varint(1),
- tag(12345, UPB_WIRE_TYPE_VARINT), varint(2345678) ),
- LINE("<")
- LINE("%u:1")
- LINE(">"), UPB_DESCRIPTOR_TYPE_INT32);
-
- // String inside submsg.
- uint32_t msg_fn = UPB_DESCRIPTOR_TYPE_MESSAGE;
- assert_successful_parse(
- submsg(msg_fn,
- cat ( tag(UPB_DESCRIPTOR_TYPE_STRING, UPB_WIRE_TYPE_DELIMITED),
- delim(string("abcde"))
- )
- ),
- LINE("<")
- LINE("%u:{")
- LINE(" <")
- LINE(" %u:(5)\"abcde")
- LINE(" %u:\"")
- LINE(" >")
- LINE(" }")
- LINE(">"), msg_fn, UPB_DESCRIPTOR_TYPE_STRING,
- UPB_DESCRIPTOR_TYPE_STRING);
-
- // Test implicit startseq/endseq.
- uint32_t repfl_fn = rep_fn(UPB_DESCRIPTOR_TYPE_FLOAT);
- uint32_t repdb_fn = rep_fn(UPB_DESCRIPTOR_TYPE_DOUBLE);
- assert_successful_parse(
- cat( tag(repfl_fn, UPB_WIRE_TYPE_32BIT), flt(33),
- tag(repdb_fn, UPB_WIRE_TYPE_64BIT), dbl(66) ),
- LINE("<")
- LINE("%u:[")
- LINE(" %u:33")
- LINE("]")
- LINE("%u:[")
- LINE(" %u:66")
- LINE("]")
- LINE(">"), repfl_fn, repfl_fn, repdb_fn, repdb_fn);
-
- // Submessage tests.
- assert_successful_parse(
- submsg(msg_fn, submsg(msg_fn, submsg(msg_fn, string()))),
- LINE("<")
- LINE("%u:{")
- LINE(" <")
- LINE(" %u:{")
- LINE(" <")
- LINE(" %u:{")
- LINE(" <")
- LINE(" >")
- LINE(" }")
- LINE(" >")
- LINE(" }")
- LINE(" >")
- LINE(" }")
- LINE(">"), msg_fn, msg_fn, msg_fn);
-
- uint32_t repm_fn = rep_fn(UPB_DESCRIPTOR_TYPE_MESSAGE);
- assert_successful_parse(
- submsg(repm_fn, submsg(repm_fn, string())),
- LINE("<")
- LINE("%u:[")
- LINE(" %u:{")
- LINE(" <")
- LINE(" %u:[")
- LINE(" %u:{")
- LINE(" <")
- LINE(" >")
- LINE(" }")
- LINE(" ]")
- LINE(" >")
- LINE(" }")
- LINE("]")
- LINE(">"), repm_fn, repm_fn, repm_fn, repm_fn);
-
- // Test unknown group.
- uint32_t unknown_group_fn = 12321;
- assert_successful_parse(
- cat( tag(unknown_group_fn, UPB_WIRE_TYPE_START_GROUP),
- tag(unknown_group_fn, UPB_WIRE_TYPE_END_GROUP) ),
- LINE("<")
- LINE(">")
- );
-
- // Test some unknown fields inside an unknown group.
- const string unknown_group_with_data =
- cat(
- tag(unknown_group_fn, UPB_WIRE_TYPE_START_GROUP),
- tag(12345, UPB_WIRE_TYPE_VARINT), varint(2345678),
- tag(123456789, UPB_WIRE_TYPE_32BIT), uint32(2345678),
- tag(123477, UPB_WIRE_TYPE_64BIT), uint64(2345678),
- tag(123, UPB_WIRE_TYPE_DELIMITED), varint(0),
- tag(unknown_group_fn, UPB_WIRE_TYPE_END_GROUP)
- );
-
- // Nested unknown group with data.
- assert_successful_parse(
- cat(
- tag(unknown_group_fn, UPB_WIRE_TYPE_START_GROUP),
- unknown_group_with_data,
- tag(unknown_group_fn, UPB_WIRE_TYPE_END_GROUP),
- tag(UPB_DESCRIPTOR_TYPE_INT32, UPB_WIRE_TYPE_VARINT), varint(1)
- ),
- LINE("<")
- LINE("%u:1")
- LINE(">"),
- UPB_DESCRIPTOR_TYPE_INT32
- );
-
- assert_successful_parse(
- cat( tag(unknown_group_fn, UPB_WIRE_TYPE_START_GROUP),
- tag(unknown_group_fn + 1, UPB_WIRE_TYPE_START_GROUP),
- tag(unknown_group_fn + 1, UPB_WIRE_TYPE_END_GROUP),
- tag(unknown_group_fn, UPB_WIRE_TYPE_END_GROUP) ),
- LINE("<")
- LINE(">")
- );
-
- // Staying within the stack limit should work properly.
- string buf;
- string textbuf;
- int total = MAX_NESTING - 1;
- for (int i = 0; i < total; i++) {
- buf.assign(submsg(UPB_DESCRIPTOR_TYPE_MESSAGE, buf));
- indentbuf(&textbuf, i);
- textbuf.append("<\n");
- indentbuf(&textbuf, i);
- appendf(&textbuf, "%u:{\n", UPB_DESCRIPTOR_TYPE_MESSAGE);
- }
- indentbuf(&textbuf, total);
- textbuf.append("<\n");
- indentbuf(&textbuf, total);
- textbuf.append(">\n");
- for (int i = 0; i < total; i++) {
- indentbuf(&textbuf, total - i - 1);
- textbuf.append(" }\n");
- indentbuf(&textbuf, total - i - 1);
- textbuf.append(">\n");
- }
- // Have to use run_decoder directly, because we are at max nesting and can't
- // afford the extra nesting that assert_successful_parse() will do.
- run_decoder(buf, &textbuf);
-}
-
-void empty_callback(const void* /* closure */, upb::Handlers* /* h_ptr */) {}
-
-void test_emptyhandlers(upb::SymbolTable* symtab) {
- // Create an empty handlers to make sure that the decoder can handle empty
- // messages.
- HandlerRegisterData handlerdata;
- handlerdata.mode = test_mode;
-
- upb::HandlerCache handler_cache(empty_callback, &handlerdata);
- upb::pb::CodeCache pb_code_cache(&handler_cache);
-
- upb::MessageDefPtr md = upb::MessageDefPtr(Empty_getmsgdef(symtab->ptr()));
- global_handlers = handler_cache.Get(md);
- global_method = pb_code_cache.Get(md);
-
- // TODO: also test the case where a message has fields, but the fields are
- // submessage fields and have no handlers. This also results in a decoder
- // method with no field-handling code.
-
- // Ensure that the method can run with empty and non-empty input.
- string test_unknown_field_msg =
- cat(tag(1, UPB_WIRE_TYPE_VARINT), varint(42),
- tag(2, UPB_WIRE_TYPE_DELIMITED), delim("My test data"));
- const struct {
- const char* data;
- size_t length;
- } testdata[] = {
- { "", 0 },
- { test_unknown_field_msg.data(), test_unknown_field_msg.size() },
- { NULL, 0 },
- };
- for (int i = 0; testdata[i].data; i++) {
- VerboseParserEnvironment env(filter_hash != 0);
- upb::Sink sink(global_method.dest_handlers(), &closures[0]);
- upb::pb::DecoderPtr decoder =
- CreateDecoder(env.arena(), global_method, sink, env.status());
- env.ResetBytesSink(decoder.input());
- env.Reset(testdata[i].data, testdata[i].length, true, false);
- ASSERT(env.Start());
- ASSERT(env.ParseBuffer(-1));
- ASSERT(env.End());
- ASSERT(env.CheckConsistency());
- }
-}
-
-void run_tests() {
- HandlerRegisterData handlerdata;
- handlerdata.mode = test_mode;
-
- upb::SymbolTable symtab;
- upb::HandlerCache handler_cache(callback, &handlerdata);
- upb::pb::CodeCache pb_code_cache(&handler_cache);
-
- upb::MessageDefPtr md(DecoderTest_getmsgdef(symtab.ptr()));
- global_handlers = handler_cache.Get(md);
- global_method = pb_code_cache.Get(md);
- completed = 0;
-
- test_invalid();
- test_valid();
-
- test_emptyhandlers(&symtab);
-}
-
-extern "C" {
-
-int run_tests(int argc, char *argv[]) {
- if (argc > 1)
- filter_hash = (uint32_t)strtol(argv[1], NULL, 16);
- for (int i = 0; i < MAX_NESTING; i++) {
- closures[i] = i;
- }
-
- // Count tests.
- count = &total;
- total = 0;
- test_mode = COUNT_ONLY;
- run_tests();
- count = &completed;
-
- total *= 2; // NO_HANDLERS, ALL_HANDLERS.
-
- test_mode = NO_HANDLERS;
- run_tests();
-
- test_mode = ALL_HANDLERS;
- run_tests();
-
- printf("All tests passed, %d assertions.\n", num_assertions);
- return 0;
-}
-
-}