diff --git a/src/cbor.h b/src/cbor.h index 863678c4..b8599d16 100644 --- a/src/cbor.h +++ b/src/cbor.h @@ -107,7 +107,6 @@ typedef enum CborError { /* errors in all modes */ CborUnknownError, - CborErrorOutOfMemory, CborErrorUnknownLength, /* request for length in array, map, or string with indeterminate length */ CborErrorAdvancePastEOF, CborErrorIO, @@ -131,7 +130,9 @@ typedef enum CborError { /* internal implementation errors */ CborErrorDataTooLarge = 1024, CborErrorNestingTooDeep, - CborErrorInternalError = ~0U + CborErrorInternalError = ~0U, + + CborErrorOutOfMemory = ~0U / 2 + 1 } CborError; CBOR_API const char *cbor_error_string(CborError error); diff --git a/src/cborencoder.c b/src/cborencoder.c index ba1a388a..5d2fca97 100644 --- a/src/cborencoder.c +++ b/src/cborencoder.c @@ -46,6 +46,16 @@ static inline void put16(void *where, uint16_t v) memcpy(where, &v, sizeof(v)); } +// Note: Since this is currently only used in situations where OOM is the only +// valid error, we KNOW this to be true. Thus, this function now returns just 'true', +// but if in the future, any function starts returning a non-OOM error, this will need +// to be changed to the test. At the moment, this is done to prevent more branches +// being created in the tinycbor output +static inline bool isOomError(CborError err) +{ + return true; +} + static inline void put32(void *where, uint32_t v) { v = cbor_htonl(v); @@ -60,8 +70,17 @@ static inline void put64(void *where, uint64_t v) static inline CborError append_to_buffer(CborEncoder *encoder, const void *data, size_t len) { - if (encoder->ptr + len > encoder->end) + if (encoder->end - encoder->ptr - (ptrdiff_t)len < 0) { + + if(encoder->end != NULL) { + len -= encoder->end - encoder->ptr; + encoder->end = encoder->ptr = NULL; + } + + encoder->ptr += len; return CborErrorOutOfMemory; + } + memcpy(encoder->ptr, data, len); encoder->ptr += len; return CborNoError; @@ -69,8 +88,16 @@ static inline CborError append_to_buffer(CborEncoder *encoder, const void *data, static inline CborError append_byte_to_buffer(CborEncoder *encoder, uint8_t byte) { - if (encoder->ptr == encoder->end) + if (encoder->end <= encoder->ptr) { + + if(encoder->end != NULL) { + encoder->end = encoder->ptr = NULL; + } + + ++encoder->ptr; return CborErrorOutOfMemory; + } + *encoder->ptr++ = byte; return CborNoError; } @@ -152,7 +179,7 @@ CborError cbor_encode_tag(CborEncoder *encoder, CborTag tag) static CborError encode_string(CborEncoder *encoder, size_t length, uint8_t shiftedMajorType, const void *string) { CborError err = encode_number(encoder, length, shiftedMajorType); - if (err) + if (err && !isOomError(err)) return err; return append_to_buffer(encoder, string, length); } @@ -174,7 +201,7 @@ static CborError create_container(CborEncoder *encoder, size_t length, uint8_t s err = append_byte_to_buffer(encoder, shiftedMajorType + IndefiniteLength); else err = encode_number(encoder, length, shiftedMajorType); - if (err) + if (err && !isOomError(err)) return err; *container = *encoder; @@ -195,6 +222,7 @@ CborError cbor_encoder_create_map(CborEncoder *encoder, CborEncoder *mapEncoder, CborError cbor_encoder_close_container(CborEncoder *encoder, const CborEncoder *containerEncoder) { encoder->ptr = containerEncoder->ptr; + encoder->end = containerEncoder->end; if (containerEncoder->flags & CborIteratorFlag_UnknownLength) return append_byte_to_buffer(encoder, BreakByte); return CborNoError; diff --git a/tests/encoder/tst_encoder.cpp b/tests/encoder/tst_encoder.cpp index 2d1a7c0a..f236bc1f 100644 --- a/tests/encoder/tst_encoder.cpp +++ b/tests/encoder/tst_encoder.cpp @@ -88,6 +88,11 @@ QVariant make_ilmap(const std::initializer_list> &list return QVariant::fromValue(IndeterminateLengthMap(list)); } +static inline bool isOomError(CborError err) +{ + return err == CborErrorOutOfMemory; +} + CborError encodeVariant(CborEncoder *encoder, const QVariant &v) { int type = v.userType(); @@ -132,9 +137,9 @@ CborError encodeVariant(CborEncoder *encoder, const QVariant &v) return cbor_encode_half_float(encoder, v.constData()); if (type == qMetaTypeId()) { CborError err = cbor_encode_tag(encoder, v.value().tag); - if (err) + if (err && !isOomError(err)) return err; - return encodeVariant(encoder, v.value().tagged); + return static_cast(err | encodeVariant(encoder, v.value().tagged)); } if (type == QVariant::List || type == qMetaTypeId()) { CborEncoder sub; @@ -145,14 +150,14 @@ CborError encodeVariant(CborEncoder *encoder, const QVariant &v) list = v.value(); } CborError err = cbor_encoder_create_array(encoder, &sub, len); - if (err) + if (err && !isOomError(err)) return err; foreach (const QVariant &v2, list) { - err = encodeVariant(&sub, v2); - if (err) + err = static_cast(err | encodeVariant(&sub, v2)); + if (err && !isOomError(err)) return err; } - return cbor_encoder_close_container(encoder, &sub); + return static_cast(err | cbor_encoder_close_container(encoder, &sub)); } if (type == qMetaTypeId() || type == qMetaTypeId()) { CborEncoder sub; @@ -163,17 +168,17 @@ CborError encodeVariant(CborEncoder *encoder, const QVariant &v) map = v.value(); } CborError err = cbor_encoder_create_map(encoder, &sub, len); - if (err) + if (err && !isOomError(err)) return err; for (auto pair : map) { - err = encodeVariant(&sub, pair.first); - if (err) + err = static_cast(err | encodeVariant(&sub, pair.first)); + if (err && !isOomError(err)) return err; - err = encodeVariant(&sub, pair.second); - if (err) + err = static_cast(err | encodeVariant(&sub, pair.second)); + if (err && !isOomError(err)) return err; } - return cbor_encoder_close_container(encoder, &sub); + return (CborError)(err | cbor_encoder_close_container(encoder, &sub)); } } return CborErrorUnknownType; @@ -527,6 +532,7 @@ void tst_Encoder::shortBuffer() CborEncoder encoder; cbor_encoder_init(&encoder, reinterpret_cast(buffer.data()), len, 0); QCOMPARE(int(encodeVariant(&encoder, input)), int(CborErrorOutOfMemory)); + QCOMPARE(len + int(encoder.ptr - encoder.end), output.length()); } }