aboutsummaryrefslogtreecommitdiff
path: root/pw_protobuf/public/pw_protobuf
diff options
context:
space:
mode:
Diffstat (limited to 'pw_protobuf/public/pw_protobuf')
-rw-r--r--pw_protobuf/public/pw_protobuf/encoder.h17
-rw-r--r--pw_protobuf/public/pw_protobuf/stream_decoder.h14
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);