Fixed "NULL + 0" UB in JSON encoder and decoder.

pull/13171/head
Joshua Haberman 4 years ago
parent 97e2aeb7ee
commit 63ad3db980
  1. 2
      .bazelrc
  2. 1
      tests/BUILD
  3. 12
      tests/test_cpp.cc
  4. 3
      upb/json_decode.c
  5. 19
      upb/json_encode.c

@ -8,6 +8,8 @@ build:ubsan --copt=-fsanitize=undefined --linkopt=-fsanitize=undefined --action_
# Workaround for the fact that Bazel links with $CC, not $CXX
# https://github.com/bazelbuild/bazel/issues/11122#issuecomment-613746748
build:ubsan --copt=-fno-sanitize=function --copt=-fno-sanitize=vptr
# Workaround for https://bugs.llvm.org/show_bug.cgi?id=16404
build:ubsan --linkopt=--rtlib=compiler-rt --linkopt=-lunwind
build:Werror --copt=-Werror
build:Werror --per_file_copt=json/parser@-Wno-error

@ -97,6 +97,7 @@ cc_test(
"//:port",
"//:reflection",
"//:upb",
"//:json",
],
)

@ -12,9 +12,12 @@
#include <sstream>
#include "tests/test_cpp.upbdefs.h"
#include "tests/test_cpp.upb.h"
#include "tests/upb_test.h"
#include "upb/def.h"
#include "upb/def.hpp"
#include "upb/json_decode.h"
#include "upb/json_encode.h"
#include "upb/upb.h"
// Must be last.
@ -102,6 +105,15 @@ void TestInlinedArena() {
}
void TestDefault() {
upb::SymbolTable symtab;
upb::Arena arena;
upb::MessageDefPtr md(upb_test_TestMessage_getmsgdef(symtab.ptr()));
upb_test_TestMessage *msg = upb_test_TestMessage_new(arena.ptr());
size_t size = upb_json_encode(msg, md.ptr(), NULL, 0, NULL, 0, NULL);
ASSERT(size == 2); // "{}"
}
void TestJsonNull() {
upb::SymbolTable symtab;
upb::MessageDefPtr md(upb_test_TestMessage_getmsgdef(symtab.ptr()));
upb::FieldDefPtr i32_f = md.FindFieldByName("i32");

@ -1427,6 +1427,9 @@ bool upb_json_decode(const char *buf, size_t size, upb_msg *msg,
const upb_msgdef *m, const upb_symtab *any_pool,
int options, upb_arena *arena, upb_status *status) {
jsondec d;
if (size == 0) return true;
d.ptr = buf;
d.end = buf + size;
d.arena = arena;

@ -35,6 +35,11 @@ static void jsonenc_msgfields(jsonenc *e, const upb_msg *msg,
const upb_msgdef *m, bool first);
static void jsonenc_value(jsonenc *e, const upb_msg *msg, const upb_msgdef *m);
static char *jsonenc_ptradd(char *ptr, size_t size) {
// Generates the same code as "ptr + size" but avoids UB of NULL + 0.
return size ? ptr + size : ptr;
}
UPB_NORETURN static void jsonenc_err(jsonenc *e, const char *msg) {
upb_status_seterrmsg(e->status, msg);
longjmp(e->err, 1);
@ -63,8 +68,10 @@ static void jsonenc_putbytes(jsonenc *e, const void *data, size_t len) {
memcpy(e->ptr, data, len);
e->ptr += len;
} else {
if (have) memcpy(e->ptr, data, have);
e->ptr += have;
if (have) {
memcpy(e->ptr, data, have);
e->ptr += have;
}
e->overflow += (len - have);
}
}
@ -86,7 +93,7 @@ static void jsonenc_printf(jsonenc *e, const char *fmt, ...) {
if (UPB_LIKELY(have > n)) {
e->ptr += n;
} else {
e->ptr += have;
if (have) e->ptr += have;
e->overflow += (n - have);
}
}
@ -190,7 +197,7 @@ static void jsonenc_bytes(jsonenc *e, upb_strview str) {
static const char base64[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
const unsigned char *ptr = (unsigned char*)str.data;
const unsigned char *end = ptr + str.size;
const unsigned char *end = jsonenc_ptradd(ptr, str.size);
char buf[4];
jsonenc_putstr(e, "\"");
@ -226,7 +233,7 @@ static void jsonenc_bytes(jsonenc *e, upb_strview str) {
static void jsonenc_stringbody(jsonenc *e, upb_strview str) {
const char *ptr = str.data;
const char *end = ptr + str.size;
const char *end = jsonenc_ptradd(ptr, str.size);
while (ptr < end) {
switch (*ptr) {
@ -698,7 +705,7 @@ size_t upb_json_encode(const upb_msg *msg, const upb_msgdef *m,
e.buf = buf;
e.ptr = buf;
e.end = buf + size;
e.end = jsonenc_ptradd(buf, size);
e.overflow = 0;
e.options = options;
e.ext_pool = ext_pool;

Loading…
Cancel
Save