diff options
Diffstat (limited to 'pw_varint/stream.cc')
-rw-r--r-- | pw_varint/stream.cc | 30 |
1 files changed, 23 insertions, 7 deletions
diff --git a/pw_varint/stream.cc b/pw_varint/stream.cc index 00fe1fb37..83a80de08 100644 --- a/pw_varint/stream.cc +++ b/pw_varint/stream.cc @@ -16,8 +16,8 @@ #include <cstddef> #include <cstdint> -#include <span> +#include "pw_span/span.h" #include "pw_status/status_with_size.h" #include "pw_stream/stream.h" #include "pw_varint/varint.h" @@ -25,9 +25,9 @@ namespace pw { namespace varint { -StatusWithSize Read(stream::Reader& reader, int64_t* output) { +StatusWithSize Read(stream::Reader& reader, int64_t* output, size_t max_size) { uint64_t value = 0; - StatusWithSize count = Read(reader, &value); + StatusWithSize count = Read(reader, &value, max_size); if (!count.ok()) { return count; } @@ -36,18 +36,34 @@ StatusWithSize Read(stream::Reader& reader, int64_t* output) { return count; } -StatusWithSize Read(stream::Reader& reader, uint64_t* output) { +StatusWithSize Read(stream::Reader& reader, uint64_t* output, size_t max_size) { uint64_t value = 0; size_t count = 0; while (true) { if (count >= varint::kMaxVarint64SizeBytes) { - // Varint can't fit a uint64_t. - return StatusWithSize::OutOfRange(); + // Varint can't fit a uint64_t, this likely means we're reading binary + // data that is not actually a varint. + return StatusWithSize::DataLoss(); + } + + if (count >= max_size) { + // Varint didn't fit within the range given; return OutOfRange() if + // max_size was 0, but DataLoss if we were reading something we thought + // was going to be a varint. + return count > 0 ? StatusWithSize::DataLoss() + : StatusWithSize::OutOfRange(); } std::byte b; - if (auto result = reader.Read(std::span(&b, 1)); !result.ok()) { + if (auto result = reader.Read(span(&b, 1)); !result.ok()) { + if (count > 0 && result.status().IsOutOfRange()) { + // Status::OutOfRange on the first byte means we tried to read a varint + // when we reached the end of file. But after the first byte it means we + // failed to decode a varint we were in the middle of, and that's not + // a normal error condition. + return StatusWithSize(Status::DataLoss(), 0); + } return StatusWithSize(result.status(), 0); } |