Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 24 additions & 11 deletions src/sentry_json.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "sentry_value.h"

#define SENTRY_JSON_MAX_DEPTH 64
#define SENTRY_JSON_STRLEN ((size_t)-1)

struct sentry_jsonwriter_s {
sentry_writer_t *writer;
Expand Down Expand Up @@ -201,12 +202,15 @@ static unsigned char needs_escaping[256] = {
};

static void
write_json_str(sentry_jsonwriter_t *jw, const char *str)
write_json_str(sentry_jsonwriter_t *jw, const char *str, size_t str_len)
{
// using unsigned here because utf-8 is > 127 :-)
const unsigned char *ptr = (const unsigned char *)str;
const unsigned char *start = ptr;
for (; *ptr && !sentry__jsonwriter_has_failed(jw); ptr++) {
const unsigned char *end
= str_len == SENTRY_JSON_STRLEN ? NULL : ptr + str_len;
for (; (end ? ptr < end : *ptr) && !sentry__jsonwriter_has_failed(jw);
ptr++) {
Comment thread
cursor[bot] marked this conversation as resolved.
if (!needs_escaping[*ptr]) {
continue;
}
Expand Down Expand Up @@ -352,14 +356,21 @@ sentry__jsonwriter_write_double(sentry_jsonwriter_t *jw, double val)

void
sentry__jsonwriter_write_str(sentry_jsonwriter_t *jw, const char *val)
{
sentry__jsonwriter_write_str_n(jw, val, SENTRY_JSON_STRLEN);
}

void
sentry__jsonwriter_write_str_n(
sentry_jsonwriter_t *jw, const char *val, size_t val_len)
{
if (!val) {
sentry__jsonwriter_write_null(jw);
return;
}
if (can_write_item(jw)) {
write_char(jw, '"');
write_json_str(jw, val);
write_json_str(jw, val, val_len);
write_char(jw, '"');
}
}
Expand Down Expand Up @@ -390,7 +401,7 @@ sentry__jsonwriter_write_key(sentry_jsonwriter_t *jw, const char *val)
{
if (can_write_item(jw)) {
write_char(jw, '"');
write_json_str(jw, val);
write_json_str(jw, val, SENTRY_JSON_STRLEN);
write_char(jw, '"');
write_char(jw, ':');
jw->last_was_key = true;
Expand Down Expand Up @@ -459,7 +470,7 @@ read_escaped_unicode_char(const char *buf)
}

static bool
decode_string_inplace(char *buf)
decode_string_inplace(char *buf, size_t *len_out)
{
const char *input = buf;
char *output = buf;
Expand Down Expand Up @@ -508,9 +519,7 @@ decode_string_inplace(char *buf)
return false;
}

if (uchar) {
output += sentry__unichar_to_utf8((uint32_t)uchar, output);
}
output += sentry__unichar_to_utf8((uint32_t)uchar, output);
break;
}
default:
Expand All @@ -520,6 +529,9 @@ decode_string_inplace(char *buf)

#undef SIMPLE_ESCAPE

if (len_out) {
*len_out = (size_t)(output - buf);
}
*output = 0;
return true;
}
Expand Down Expand Up @@ -604,8 +616,9 @@ tokens_to_value(jsmntok_t *tokens, size_t token_count, const char *buf,
case JSMN_STRING: {
char *string = sentry__string_clone_n_unchecked(
buf + root->start, (size_t)(root->end - root->start));
if (decode_string_inplace(string)) {
rv = sentry__value_new_string_owned(string);
size_t string_len = 0;
if (decode_string_inplace(string, &string_len)) {
rv = sentry__value_new_string_owned_n(string, string_len);
} else {
sentry_free(string);
rv = sentry_value_new_null();
Expand All @@ -628,7 +641,7 @@ tokens_to_value(jsmntok_t *tokens, size_t token_count, const char *buf,

char *key = sentry__string_clone_n_unchecked(
buf + token->start, (size_t)(token->end - token->start));
if (decode_string_inplace(key)) {
if (decode_string_inplace(key, NULL)) {
Comment thread
jpnurmi marked this conversation as resolved.
sentry_value_set_by_key(rv, key, child);
} else {
sentry_value_decref(child);
Expand Down
6 changes: 6 additions & 0 deletions src/sentry_json.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,12 @@ void sentry__jsonwriter_write_double(sentry_jsonwriter_t *jw, double val);
*/
void sentry__jsonwriter_write_str(sentry_jsonwriter_t *jw, const char *val);

/**
* Write a string with an explicit byte length.
*/
void sentry__jsonwriter_write_str_n(
sentry_jsonwriter_t *jw, const char *val, size_t val_len);

/**
* Write a UUID as a JSON string.
* See `sentry_uuid_as_string`.
Expand Down
67 changes: 52 additions & 15 deletions src/sentry_value.c
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,11 @@ typedef struct {
long refcount;
} obj_t;

typedef struct {
char *s;
size_t len;
} blob_t;

static const char *
level_as_string(sentry_level_t level)
{
Expand Down Expand Up @@ -189,6 +194,13 @@ obj_free(obj_t *obj)
sentry_free(obj);
}

static void
blob_free(blob_t *blob)
{
sentry_free(blob->s);
sentry_free(blob);
}

static list_t *
list_clone(const list_t *list)
{
Expand Down Expand Up @@ -316,7 +328,7 @@ thing_free(thing_t *thing)
obj_free(thing->payload._ptr);
break;
case THING_TYPE_STRING:
sentry_free(thing->payload._ptr);
blob_free(thing->payload._ptr);
break;
}
sentry_free(thing);
Expand Down Expand Up @@ -511,7 +523,7 @@ sentry_value_new_string_n(const char *value, size_t value_len)
if (!s) {
return sentry_value_new_null();
}
return sentry__value_new_string_owned(s);
return sentry__value_new_string_owned_n(s, value_len);
}

sentry_value_t
Expand Down Expand Up @@ -1173,7 +1185,7 @@ sentry_value_get_length(sentry_value_t value)
if (thing) {
switch (thing_get_type(thing)) {
case THING_TYPE_STRING:
return strlen(thing->payload._ptr);
return ((const blob_t *)thing->payload._ptr)->len;
case THING_TYPE_LIST:
return ((const list_t *)thing->payload._ptr)->len;
case THING_TYPE_OBJECT:
Expand Down Expand Up @@ -1269,7 +1281,7 @@ sentry_value_as_string(sentry_value_t value)
{
const thing_t *thing = value_as_thing(value);
if (thing && thing_get_type(thing) == THING_TYPE_STRING) {
return (const char *)thing->payload._ptr;
return ((const blob_t *)thing->payload._ptr)->s;
}
return "";
}
Expand Down Expand Up @@ -1393,9 +1405,17 @@ sentry__jsonwriter_write_value(sentry_jsonwriter_t *jw, sentry_value_t value)
case SENTRY_VALUE_TYPE_DOUBLE:
sentry__jsonwriter_write_double(jw, sentry_value_as_double(value));
break;
case SENTRY_VALUE_TYPE_STRING:
sentry__jsonwriter_write_str(jw, sentry_value_as_string(value));
case SENTRY_VALUE_TYPE_STRING: {
const thing_t *thing = value_as_thing(value);
if (!thing) {
UNREACHABLE("thing of a string is NULL during serialization");
return;
}

const blob_t *b = thing->payload._ptr;
sentry__jsonwriter_write_str_n(jw, b->s, b->len);
break;
}
case SENTRY_VALUE_TYPE_LIST: {
const thing_t *thing = value_as_thing(value);
if (!thing) {
Expand Down Expand Up @@ -1473,7 +1493,9 @@ value_to_msgpack(mpack_writer_t *writer, sentry_value_t value)
mpack_write_double(writer, sentry_value_as_double(value));
break;
case SENTRY_VALUE_TYPE_STRING: {
mpack_write_cstr_or_nil(writer, sentry_value_as_string(value));
const blob_t *b = value_as_thing(value)->payload._ptr;

mpack_write_str(writer, b->s, (uint32_t)b->len);
break;
}
case SENTRY_VALUE_TYPE_LIST: {
Expand Down Expand Up @@ -1515,16 +1537,31 @@ sentry_value_to_msgpack(sentry_value_t value, size_t *size_out)

sentry_value_t
sentry__value_new_string_owned(char *s)
{
return s ? sentry__value_new_string_owned_n(s, strlen(s))
: sentry_value_new_null();
}

sentry_value_t
sentry__value_new_string_owned_n(char *s, size_t s_len)
{
if (!s) {
return sentry_value_new_null();
}
sentry_value_t rv
= new_thing_value(s, THING_TYPE_STRING | THING_TYPE_FROZEN);
if (sentry_value_is_null(rv)) {
blob_t *b = SENTRY_MAKE(blob_t);
if (b) {
b->s = s;
b->len = s_len;
sentry_value_t rv
= new_thing_value(b, THING_TYPE_STRING | THING_TYPE_FROZEN);
if (sentry_value_is_null(rv)) {
blob_free(b);
}
return rv;
} else {
sentry_free(s);
return sentry_value_new_null();
}
return rv;
}

#ifdef SENTRY_PLATFORM_WINDOWS
Expand Down Expand Up @@ -1564,7 +1601,7 @@ sentry__value_new_hexstring(const uint8_t *bytes, size_t len)
written += rv;
}
buf[written] = '\0';
return sentry__value_new_string_owned(buf);
return sentry__value_new_string_owned_n(buf, written);
}

sentry_value_t
Expand All @@ -1576,7 +1613,7 @@ sentry__value_new_span_uuid(const sentry_uuid_t *uuid)
}
sentry__span_uuid_as_string(uuid, buf);
buf[16] = '\0';
return sentry__value_new_string_owned(buf);
return sentry__value_new_string_owned_n(buf, 16);
}

sentry_value_t
Expand All @@ -1588,7 +1625,7 @@ sentry__value_new_internal_uuid(const sentry_uuid_t *uuid)
}
sentry__internal_uuid_as_string(uuid, buf);
buf[32] = '\0';
return sentry__value_new_string_owned(buf);
return sentry__value_new_string_owned_n(buf, 32);
}

sentry_value_t
Expand All @@ -1600,7 +1637,7 @@ sentry__value_new_uuid(const sentry_uuid_t *uuid)
}
sentry_uuid_as_string(uuid, buf);
buf[36] = '\0';
return sentry__value_new_string_owned(buf);
return sentry__value_new_string_owned_n(buf, 36);
}

sentry_value_t
Expand Down
5 changes: 5 additions & 0 deletions src/sentry_value.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@
*/
sentry_value_t sentry__value_new_string_owned(char *s);

/**
* Create a new Value from an owned string with explicit byte length.
*/
sentry_value_t sentry__value_new_string_owned_n(char *s, size_t s_len);

#ifdef SENTRY_PLATFORM_WINDOWS
/**
* Create a new Value from a Wide String.
Expand Down
27 changes: 27 additions & 0 deletions tests/unit/test_value.c
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,25 @@ SENTRY_TEST(value_string_n)
TEST_CHECK(sentry_value_get_type(val) == SENTRY_VALUE_TYPE_STRING);
TEST_CHECK(sentry_value_is_true(val) == true);
sentry_value_decref(val);

char string_with_nul[] = { 'h', 'e', '\0', 'l', 'o' };
val = sentry_value_new_string_n(string_with_nul, sizeof(string_with_nul));
TEST_CHECK(sentry_value_get_length(val) == sizeof(string_with_nul));
TEST_CHECK(memcmp(sentry_value_as_string(val), string_with_nul,
sizeof(string_with_nul))
== 0);
TEST_CHECK_JSON_VALUE(val, "\"he\\u0000lo\"");

char *json = sentry_value_to_json(val);
sentry_value_t deserialized = sentry__value_from_json(json, strlen(json));
TEST_CHECK(
sentry_value_get_length(deserialized) == sizeof(string_with_nul));
TEST_CHECK(memcmp(sentry_value_as_string(deserialized), string_with_nul,
sizeof(string_with_nul))
== 0);
sentry_free(json);
sentry_value_decref(deserialized);
sentry_value_decref(val);
}

SENTRY_TEST(value_unicode)
Expand Down Expand Up @@ -1123,6 +1142,14 @@ SENTRY_TEST(value_json_parsing)
"foo\xe2\x98\x83");
sentry_value_decref(rv);

char string_with_nul[] = { 'h', 'e', '\0', 'l', 'o' };
rv = sentry__value_from_json(STRING("\"he\\u0000lo\""));
TEST_CHECK(sentry_value_get_length(rv) == sizeof(string_with_nul));
TEST_CHECK(memcmp(sentry_value_as_string(rv), string_with_nul,
sizeof(string_with_nul))
== 0);
sentry_value_decref(rv);

rv = sentry__value_from_json(
STRING("[false, 42, \"foo\\u2603\", \"bar\", {\"foo\": 42}]"));
TEST_CHECK_JSON_VALUE(rv, "[false,42,\"foo☃\",\"bar\",{\"foo\":42}]");
Expand Down
Loading