From a97ef4d6d1fc21964b68c6655ed24aa92563a444 Mon Sep 17 00:00:00 2001
From: Karsten Suehring <karsten.suehring@hhi.fraunhofer.de>
Date: Wed, 18 Nov 2020 22:20:45 +0100
Subject: [PATCH] Fix potential race condition when frame field information SEI
 arrives before picture timing SEI

Picture Timing SEI is intentionally not used in parsing of frame field information SEI.

In the existing code retrieving the picture timing SEI from HRD could return a nullptr, when the SEI has
not arrived yet. The pointer is dereferenced without checking and passed into frame field info SEI parsing
function and used for a consistency check.

This refactoring moves the check after parsing of all SEI messages.
---
 source/Lib/DecoderLib/DecLib.cpp  | 17 +++++++++++++++++
 source/Lib/DecoderLib/DecLib.h    |  1 +
 source/Lib/DecoderLib/SEIread.cpp | 10 ++--------
 source/Lib/DecoderLib/SEIread.h   |  2 +-
 4 files changed, 21 insertions(+), 9 deletions(-)

diff --git a/source/Lib/DecoderLib/DecLib.cpp b/source/Lib/DecoderLib/DecLib.cpp
index fa5b2144d..c221aecc9 100644
--- a/source/Lib/DecoderLib/DecLib.cpp
+++ b/source/Lib/DecoderLib/DecLib.cpp
@@ -1976,6 +1976,23 @@ void DecLib::xParsePrefixSEImessages()
     delete m_prefixSEINALUs.front();
     m_prefixSEINALUs.pop_front();
   }
+  xCheckPrefixSEIMessages(m_SEIs);
+}
+
+void DecLib::xCheckPrefixSEIMessages( SEIMessages& prefixSEIs )
+{
+  SEIMessages picTimingSEIs  = getSeisByType(prefixSEIs, SEI::PICTURE_TIMING);
+  SEIMessages frameFieldSEIs = getSeisByType(prefixSEIs, SEI::FRAME_FIELD_INFO);
+
+  if (!picTimingSEIs.empty() && !frameFieldSEIs.empty())
+  {
+    SEIPictureTiming  *pt = (SEIPictureTiming*)  picTimingSEIs.front();
+    SEIFrameFieldInfo *ff = (SEIFrameFieldInfo*) frameFieldSEIs.front();
+    if( pt->m_ptDisplayElementalPeriodsMinus1 != ff->m_displayElementalPeriodsMinus1 )
+    {
+      msg( WARNING, "Warning: ffi_display_elemental_periods_minus1 is different in picture timing and frame field information SEI messages!");
+    }
+  }
 }
 
 void DecLib::xDecodePicHeader( InputNALUnit& nalu )
diff --git a/source/Lib/DecoderLib/DecLib.h b/source/Lib/DecoderLib/DecLib.h
index b1ad6bb88..bb15b81eb 100644
--- a/source/Lib/DecoderLib/DecLib.h
+++ b/source/Lib/DecoderLib/DecLib.h
@@ -320,6 +320,7 @@ protected:
   }
   void      xParsePrefixSEImessages();
   void      xParsePrefixSEIsForUnknownVCLNal();
+  void      xCheckPrefixSEIMessages( SEIMessages& prefixSEIs );
 
   void  xCheckNalUnitConstraintFlags( const ConstraintInfo *cInfo, uint32_t naluType );
   void     xCheckMixedNalUnit(Slice* pcSlice, SPS *sps, InputNALUnit &nalu);
diff --git a/source/Lib/DecoderLib/SEIread.cpp b/source/Lib/DecoderLib/SEIread.cpp
index 31c07db50..d5c993102 100644
--- a/source/Lib/DecoderLib/SEIread.cpp
+++ b/source/Lib/DecoderLib/SEIread.cpp
@@ -177,7 +177,6 @@ void SEIReader::xReadSEImessage(SEIMessages& seis, const NalUnitType nalUnitType
 
   SEI *sei = NULL;
   const SEIBufferingPeriod *bp = NULL;
-  const SEIPictureTiming *pt = NULL;
 
   if(nalUnitType == NAL_UNIT_PREFIX_SEI)
   {
@@ -225,8 +224,7 @@ void SEIReader::xReadSEImessage(SEIMessages& seis, const NalUnitType nalUnitType
       break;
     case SEI::FRAME_FIELD_INFO:
       sei = new SEIFrameFieldInfo;
-      pt = hrd.getPictureTimingSEI();
-      xParseSEIFrameFieldinfo((SEIFrameFieldInfo&) *sei, *pt, payloadSize, pDecodedMessageOutputStream);
+      xParseSEIFrameFieldinfo((SEIFrameFieldInfo&) *sei, payloadSize, pDecodedMessageOutputStream);
       break;
     case SEI::DEPENDENT_RAP_INDICATION:
       sei = new SEIDependentRAPIndication;
@@ -990,7 +988,7 @@ void SEIReader::xParseSEIPictureTiming(SEIPictureTiming& sei, uint32_t payloadSi
   sei.m_ptDisplayElementalPeriodsMinus1 = symbol;
 }
 
-void SEIReader::xParseSEIFrameFieldinfo(SEIFrameFieldInfo& sei, const SEIPictureTiming& pt, uint32_t payloadSize, std::ostream *pDecodedMessageOutputStream)
+void SEIReader::xParseSEIFrameFieldinfo(SEIFrameFieldInfo& sei, uint32_t payloadSize, std::ostream *pDecodedMessageOutputStream)
 {
   output_sei_message_header(sei, pDecodedMessageOutputStream, payloadSize);
 
@@ -1024,10 +1022,6 @@ void SEIReader::xParseSEIFrameFieldinfo(SEIFrameFieldInfo& sei, const SEIPicture
     sei_read_uvlc( pDecodedMessageOutputStream, symbol,    "ffi_display_elemental_periods_minus1" );
 #endif
     sei.m_displayElementalPeriodsMinus1 = symbol;
-    if( pt.m_ptDisplayElementalPeriodsMinus1 != sei.m_displayElementalPeriodsMinus1 )
-    {
-      msg( WARNING, "Warning: ffi_display_elemental_periods_minus1 is different in picture timing and frame field information SEI messages!");
-    }
   }
   sei_read_code( pDecodedMessageOutputStream, 2, symbol,   "ffi_source_scan_type" );
   sei.m_sourceScanType = symbol;
diff --git a/source/Lib/DecoderLib/SEIread.h b/source/Lib/DecoderLib/SEIread.h
index 8627a85de..996f6e1f3 100644
--- a/source/Lib/DecoderLib/SEIread.h
+++ b/source/Lib/DecoderLib/SEIread.h
@@ -66,7 +66,7 @@ protected:
   void xParseSEIPictureTiming                 (SEIPictureTiming& sei,                 uint32_t payloadSize, const uint32_t temporalId, const SEIBufferingPeriod& bp, std::ostream *pDecodedMessageOutputStream);
   void xParseSEIScalableNesting               (SEIScalableNesting& sei, const NalUnitType nalUnitType, const uint32_t nuhLayerId, uint32_t payloadSize, const VPS* vps, const SPS* sps, HRD &hrd, std::ostream* decodedMessageOutputStream);
   void xCheckScalableNestingConstraints       (const SEIScalableNesting& sei, const NalUnitType nalUnitType, const VPS* vps);
-  void xParseSEIFrameFieldinfo                (SEIFrameFieldInfo& sei, const SEIPictureTiming& pt, uint32_t payloadSize, std::ostream *pDecodedMessageOutputStream);
+  void xParseSEIFrameFieldinfo                (SEIFrameFieldInfo& sei,                uint32_t payloadSize, std::ostream *pDecodedMessageOutputStream);
   void xParseSEIDependentRAPIndication        (SEIDependentRAPIndication& sei,        uint32_t payLoadSize,                     std::ostream *pDecodedMessageOutputStream);
   void xParseSEIFramePacking                  (SEIFramePacking& sei,                  uint32_t payloadSize,                     std::ostream *pDecodedMessageOutputStream);
   void xParseSEIParameterSetsInclusionIndication(SEIParameterSetsInclusionIndication& sei, uint32_t payloadSize,                std::ostream* pDecodedMessageOutputStream);
-- 
GitLab