@@ -330,6 +330,10 @@ Result<std::unique_ptr<Message>> ReadMessage(std::shared_ptr<Buffer> metadata,
330330 }
331331
332332 ARROW_RETURN_NOT_OK (decoder.Consume (metadata));
333+ if (decoder.buffered_size () > 0 ) {
334+ return Status::Invalid (" Message metadata too long by " , decoder.buffered_size (),
335+ " bytes" );
336+ }
333337
334338 switch (decoder.state ()) {
335339 case MessageDecoder::State::INITIAL :
@@ -384,6 +388,10 @@ static Result<std::unique_ptr<Message>> ReadMessageInternal(
384388 /* allow_short_read=*/ false ));
385389
386390 ARROW_RETURN_NOT_OK (decoder.Consume (SliceBuffer (metadata, 0 , metadata_length)));
391+ if (decoder.buffered_size () > 0 ) {
392+ return Status::Invalid (" Message metadata too long by " , decoder.buffered_size (),
393+ " bytes" );
394+ }
387395
388396 switch (decoder.state ()) {
389397 case MessageDecoder::State::INITIAL :
@@ -469,9 +477,14 @@ Future<std::shared_ptr<Message>> ReadMessageAsync(int64_t offset, int32_t metada
469477 ->ReadAsync (context, offset, metadata_length + body_length,
470478 /* allow_short_read=*/ false )
471479 .Then ([=](std::shared_ptr<Buffer> metadata) -> Result<std::shared_ptr<Message>> {
480+ // TODO reconcile + factor out with blocking ReadMessage logic
472481 DCHECK_EQ (metadata->size (), metadata_length + body_length);
473482 ARROW_RETURN_NOT_OK (
474483 state->decoder ->Consume (SliceBuffer (metadata, 0 , metadata_length)));
484+ if (state->decoder ->buffered_size () > 0 ) {
485+ return Status::Invalid (" Message metadata too long by " ,
486+ state->decoder ->buffered_size (), " bytes" );
487+ }
475488 switch (state->decoder ->state ()) {
476489 case MessageDecoder::State::INITIAL :
477490 return std::move (state->result );
@@ -484,12 +497,15 @@ Future<std::shared_ptr<Message>> ReadMessageAsync(int64_t offset, int32_t metada
484497 " invalid. File offset: " , offset,
485498 " , metadata length: " , metadata_length);
486499 case MessageDecoder::State::BODY : {
487- auto body = SliceBuffer (metadata, metadata_length, body_length);
488- if (body->size () < state->decoder ->next_required_size ()) {
489- return Status::IOError (" Expected to be able to read " ,
490- state->decoder ->next_required_size (),
491- " bytes for message body, got " , body->size ());
500+ if (body_length != state->decoder ->next_required_size ()) {
501+ // The streaming decoder got out of sync with the actual advertised
502+ // metadata and body size, which signals an invalid IPC file.
503+ return Status::IOError (
504+ " Invalid IPC file: advertised body size is " , body_length,
505+ " , but message decoder expects to read " ,
506+ state->decoder ->next_required_size (), " bytes instead" );
492507 }
508+ auto body = SliceBuffer (metadata, metadata_length, body_length);
493509 RETURN_NOT_OK (state->decoder ->Consume (body));
494510 return std::move (state->result );
495511 }
@@ -755,6 +771,8 @@ class MessageDecoder::MessageDecoderImpl {
755771
756772 int64_t next_required_size () const { return next_required_size_ - buffered_size_; }
757773
774+ int64_t buffered_size () const { return buffered_size_; }
775+
758776 MessageDecoder::State state () const { return state_; }
759777
760778 private:
@@ -1020,6 +1038,8 @@ Status MessageDecoder::Consume(std::shared_ptr<Buffer> buffer) {
10201038
10211039int64_t MessageDecoder::next_required_size () const { return impl_->next_required_size (); }
10221040
1041+ int64_t MessageDecoder::buffered_size () const { return impl_->buffered_size (); }
1042+
10231043MessageDecoder::State MessageDecoder::state () const { return impl_->state (); }
10241044
10251045// ----------------------------------------------------------------------
0 commit comments