diff options
Diffstat (limited to 'pw_protobuf/public/pw_protobuf')
-rw-r--r-- | pw_protobuf/public/pw_protobuf/encoder.h | 17 | ||||
-rw-r--r-- | pw_protobuf/public/pw_protobuf/stream_decoder.h | 14 |
2 files changed, 24 insertions, 7 deletions
diff --git a/pw_protobuf/public/pw_protobuf/encoder.h b/pw_protobuf/public/pw_protobuf/encoder.h index dccc6869a..bd6a95b33 100644 --- a/pw_protobuf/public/pw_protobuf/encoder.h +++ b/pw_protobuf/public/pw_protobuf/encoder.h @@ -32,6 +32,7 @@ #include "pw_status/try.h" #include "pw_stream/memory_stream.h" #include "pw_stream/stream.h" +#include "pw_toolchain/internal/sibling_cast.h" #include "pw_varint/varint.h" namespace pw::protobuf { @@ -658,13 +659,21 @@ class StreamEncoder { constexpr StreamEncoder(StreamEncoder& parent, ByteSpan scratch_buffer, bool write_when_empty = true) - : status_(scratch_buffer.empty() ? Status::ResourceExhausted() - : OkStatus()), + : status_(OkStatus()), write_when_empty_(write_when_empty), parent_(&parent), nested_field_number_(0), memory_writer_(scratch_buffer), - writer_(memory_writer_) {} + writer_(memory_writer_) { + // If this encoder was spawned from a failed encoder, it should also start + // in a failed state. + if (&parent != this) { + status_.Update(parent.status_); + } + if (scratch_buffer.empty()) { + status_.Update(Status::ResourceExhausted()); + } + } bool nested_encoder_open() const { return nested_field_number_ != 0; } @@ -902,7 +911,7 @@ inline ToStreamEncoder& StreamEncoderCast(FromStreamEncoder& encoder) { static_assert(std::is_base_of<StreamEncoder, ToStreamEncoder>::value, "Cannot cast to a type that is not a derived class of " "pw::protobuf::StreamEncoder"); - return static_cast<ToStreamEncoder&>(static_cast<StreamEncoder&>(encoder)); + return pw::internal::SiblingCast<ToStreamEncoder&, StreamEncoder>(encoder); } } // namespace pw::protobuf diff --git a/pw_protobuf/public/pw_protobuf/stream_decoder.h b/pw_protobuf/public/pw_protobuf/stream_decoder.h index 0a7b4e506..c57210733 100644 --- a/pw_protobuf/public/pw_protobuf/stream_decoder.h +++ b/pw_protobuf/public/pw_protobuf/stream_decoder.h @@ -607,15 +607,23 @@ class StreamDecoder { std::is_same_v<T, int64_t>, "Protobuf varints must be of type bool, uint32_t, int32_t, uint64_t, " "or int64_t"); + using DecodedValue = + std::conditional_t<std::is_signed<T>::value, int64_t, uint64_t>; + static_assert(sizeof(DecodedValue) >= sizeof(T)); - T result; + DecodedValue result; if (Status status = ReadVarintField(as_writable_bytes(span(&result, 1)), decode_type); !status.ok()) { return status; } - - return result; + if (result > static_cast<DecodedValue>(std::numeric_limits<T>::max()) || + result < static_cast<DecodedValue>(std::numeric_limits<T>::lowest())) { + // When a varint is too big to fit in an integer, the decoder returns + // FAILED_PRECONDITION, so this mirrors that behavior. + return Status::FailedPrecondition(); + } + return static_cast<T>(result); } Status ReadFixedField(span<std::byte> out); |