]> git.uio.no Git - u/mrichter/AliRoot.git/blobdiff - MUON/AliMUONTrackerDDLDecoder.h
Coverity fix (BAD_OVERRIDE)
[u/mrichter/AliRoot.git] / MUON / AliMUONTrackerDDLDecoder.h
index 3c430b45d9bdf55f231f54962b92465f2a08a33c..d23a26308ab989154851d1273eb34a1ccadf68bb 100644 (file)
@@ -25,7 +25,7 @@
 /// \brief  Implementation of a high performance DDL decoder for the muon tracking stations.
 ///
 /// This file implementes the AliMUONTrackerDDLDecoder class, which contains
-/// the core logic for decoding the payload in DDL streams comming from the muon
+/// the core logic for decoding the payload in DDL streams coming from the muon
 /// spectrometer's tracking chambers in a very efficient manner.
 ///
 /// This implementation is derived from work done by Christian Finck for the
@@ -37,6 +37,7 @@
 /// must be checked before any proposed modification is made to this file.
 ///
 
+#include <string.h>
 #include "AliMUONTrackerDDLDecoderEventHandler.h"
 
 /// \ingroup raw
 ///
 /// This class implements a high performance decoder for decoding DDL payload
 /// data coming from the muon spectrometers tracking chambers.
-/// It has been implemented using the event driven paradigm, which allows us
-/// to minimise the number of method calls made in the inner loops of the algorithm
-/// and minimise the memory footprint.
+/// It has been implemented using the event driven paradigm with templates,
+/// which allows us to minimise the number of method calls made in the inner
+/// loops of the algorithm and minimise the memory footprint. At least for
+/// optimised production compilations.
 /// The decoder class only contains the basic decoding and error checking logic.
 /// It calls methods such as OnNewBlock, OnNewBusPatch, OnData etc in
 /// the event handler during the decoding to return the decoded data.
 /// The event handler class is nothing more than a callback interface to deliver
 /// the next chunks of decoded data.
-/// To actually do something with the data one needs to implement a custom
+/// To actually do something with the data, one needs to implement a custom
 /// event handler (callback) class by inheriting from AliMUONTrackerDDLDecoderEventHandler
 /// and overriding the callback methods like so:
 /// \code
 ///  class MyCustomHandler : public AliMUONTrackerDDLDecoderEventHandler
 ///  {
 ///  public:
-///     void OnData(UInt_t data)
+///     void OnData(UInt_t data, bool parityError)
 ///     {
-///       // I can do something with 'data' here.
+///       // I can do something with 'data' here and check if there was
+///       // a parity error with 'parityError'.
 ///     }
 ///  };
 /// \endcode
 ///
-/// Once the custom handler is written then the decoder is in instantiated as
-/// shown below, to use your new custom handler. And to start decoding one needs
+/// Once the custom handler is written then the decoder is instantiated as
+/// shown below, to use your new custom handler. Also to start decoding one needs
 /// to call the Decode() method of the decoder.
 /// \code
 ///  AliMUONTrackerDDLDecoder<MyCustomHandler> myDecoder;
@@ -76,9 +79,9 @@
 /// \endcode
 ///
 /// Note that this class was written as a template on purpose. To maximise the
-/// compilers chance to make optimisations and inlining code must use a template.
-/// Depending on exactly what you do inside your handler the decoder will be
-/// significantly slower if run time polymorphism was used i.e. making the class
+/// compilers chance to make optimisations and inline the code we must use a template.
+/// Depending on exactly what you do inside your handler, the decoder could be
+/// significantly slower if run time polymorphism was used, i.e. making the class
 /// AliMUONTrackerDDLDecoderEventHandler abstract and using virtual methods.
 ///
 /// There has been a change to the data format that the real detector generates.
@@ -179,6 +182,24 @@ public:
        /// This method decodes the DDL payload contained in the buffer.
        bool Decode(const void* buffer, UInt_t bufferSize);
        
+       /// First try fix data corruption and then decode the DDL payload.
+       bool Decode(void* buffer, UInt_t bufferSize);
+       
+       /// Returns the block marker key.
+       static UInt_t BlockDataKeyWord() { return fgkBlockDataKey; }
+       
+       /// Returns the DSP marker key.
+       static UInt_t DspDataKeyWord() { return fgkDSPDataKey; }
+       
+       /// Returns the bus patch marker key.
+       static UInt_t BusPatchDataKeyWord() { return fgkBusPatchDataKey; }
+       
+       /// Returns the expected padding word value.
+       static UInt_t PaddingWord() { return fgkPaddingWord; }
+       
+       /// Returns the expected end of DDL marker.
+       static UInt_t EndOfDDLWord() { return fgkEndOfDDL; }
+       
 private:
 
        bool fExitOnError; ///< Indicates if we should exit on the very first error.
@@ -301,6 +322,43 @@ bool AliMUONTrackerDDLDecoder<EventHandler>::Decode(const void* buffer, UInt_t b
 }
 
 
+template <class EventHandler>
+bool AliMUONTrackerDDLDecoder<EventHandler>::Decode(void* buffer, UInt_t bufferSize)
+{
+       /// This decoding method performs a special checks to see if the DDL
+       /// corruption is fixable and then fixes the buffer by modifying it directly.
+       /// The fixes only apply if the fTryRecover flag is enabled.
+       /// \note buffer might be modified.
+       
+       assert( buffer != NULL );
+       if (fTryRecover)
+       {
+               ///////////////////////////////////////////////////////
+               // Trick to recover B off data Runs : 119041, 119047, 119055, 119057
+               // A. Baldisseri May 2010
+               // Check if 16 32-bit words from a buspatch have been inserted
+               // incorrectly immediately at the beginning of the DDL payload.
+               UChar_t* bufferChar = reinterpret_cast<UChar_t*>(buffer);
+               UInt_t* bufferInt = reinterpret_cast<UInt_t*>(buffer);
+               if (bufferSize > 18*4 // is the buffer large enough to check the header.
+                   and bufferInt[0] != fgkBlockDataKey and bufferInt[16] == fgkBlockDataKey // was the header incorrectly moved.
+                   and bufferSize > bufferInt[17]*4 + sizeof(AliMUONBlockHeaderStruct) // is the buffer large enough for the second block header.
+                   and bufferInt[bufferInt[17]] == fgkBlockDataKey  // Check that the second header is in the correct location.
+                   and bufferInt[17] == bufferInt[18] + 8  // Make sure that both lengths are correct.
+                   and (bufferInt[17] + bufferInt[bufferInt[17]+1]+2)*4 == bufferSize // Check that both blocks will have the correct size if we make the fix.
+                  )
+               {
+                       UChar_t tmpbuf[16*4];
+                       memcpy(tmpbuf, bufferChar, 16*4);
+                       size_t sizeToMove = bufferInt[17]*4-16*4;
+                       memmove(bufferChar, bufferChar+16*4, sizeToMove);
+                       memcpy(bufferChar + sizeToMove, tmpbuf, 16*4);
+               }
+       }
+       return Decode(reinterpret_cast<const void*>(buffer), bufferSize);
+}
+
+
 template <class EventHandler>
 void AliMUONTrackerDDLDecoder<EventHandler>::DecodeBuffer(
                const UChar_t* start, const UChar_t* end
@@ -324,14 +382,14 @@ void AliMUONTrackerDDLDecoder<EventHandler>::DecodeBuffer(
        
        // The DDL payload normally has a 2 word trailer which contains the end of
        // DDL markers 0xD000000D. But this is not the case for older simulated
-       // data so if we are autodetecting the trailer then we need to carefully
+       // data so if we are auto-detecting the trailer then we need to carefully
        // check if these words are there or not.
        const UChar_t* endOfBlocks = end;
        const UInt_t* trailerWords = reinterpret_cast<const UInt_t*>(end) - 2;
        if (fAutoDetectTrailer)
        {
-               if (trailerWords >= bufferStart and *trailerWords == fgkEndOfDDL
-                   and *(trailerWords+1) == fgkEndOfDDL
+               if (trailerWords >= bufferStart and trailerWords < bufferEnd
+                   and *trailerWords == fgkEndOfDDL and *(trailerWords+1) == fgkEndOfDDL
                   )
                {
                        // Found the trailer so reposition the end of blocks marker.
@@ -341,8 +399,8 @@ void AliMUONTrackerDDLDecoder<EventHandler>::DecodeBuffer(
        }
        else if (fCheckForTrailer)
        {
-               if (trailerWords >= bufferStart and *trailerWords == fgkEndOfDDL
-                   and *(trailerWords+1) == fgkEndOfDDL
+               if (trailerWords >= bufferStart and trailerWords < bufferEnd
+                   and *trailerWords == fgkEndOfDDL and *(trailerWords+1) == fgkEndOfDDL
                   )
                {
                        // Found the trailer so reposition the end of blocks marker.
@@ -350,9 +408,9 @@ void AliMUONTrackerDDLDecoder<EventHandler>::DecodeBuffer(
                }
                else
                {
-                       if (trailerWords+1 >= bufferStart and *(trailerWords+1) == fgkEndOfDDL)
+                       if (trailerWords+1 >= bufferStart and trailerWords+1 < bufferEnd and *(trailerWords+1) == fgkEndOfDDL)
                                fHandler.OnError(EventHandler::kTooFewDDLTrailerWords, trailerWords+1);
-                       else if (trailerWords >= bufferStart and *(trailerWords) == fgkEndOfDDL)
+                       else if (trailerWords >= bufferStart and trailerWords < bufferEnd and *(trailerWords) == fgkEndOfDDL)
                                fHandler.OnError(EventHandler::kTooFewDDLTrailerWords, trailerWords);
                        else
                                fHandler.OnError(EventHandler::kNoDDLTrailerWords, end);
@@ -364,7 +422,7 @@ void AliMUONTrackerDDLDecoder<EventHandler>::DecodeBuffer(
                        if (fExitOnError) return;
                        
                        // Mark that there was a problem with the trailer so that
-                       // for subsequest errors we try to deal with this better.
+                       // for subsequent errors we try to deal with this better.
                        problemWithTrailer = true;
                        
                        // We can also try figure out how many trailer words there
@@ -374,10 +432,10 @@ void AliMUONTrackerDDLDecoder<EventHandler>::DecodeBuffer(
                        {
                                trailerWords = bufferEnd;
                                // There should only be a max of 2 trailer words.
-                               if (*(trailerWords-1) == fgkEndOfDDL)
-                                       trailerWords--;
-                               else if (*(trailerWords-1) == fgkEndOfDDL)
-                                       trailerWords--;
+                               if (trailerWords-2 >= bufferStart and trailerWords-2 < bufferEnd and *(trailerWords-2) == fgkEndOfDDL)
+                                       trailerWords -= 2;
+                               else if (trailerWords-1 >= bufferStart and trailerWords-1 < bufferEnd and *(trailerWords-1) == fgkEndOfDDL)
+                                       trailerWords -= 1;
                                endOfBlocks = reinterpret_cast<const UChar_t*>(trailerWords);
                        }
                }
@@ -394,8 +452,12 @@ void AliMUONTrackerDDLDecoder<EventHandler>::DecodeBuffer(
                const AliMUONBlockHeaderStruct* blockHeader
                        = reinterpret_cast<const AliMUONBlockHeaderStruct*>(blockStart);
                current += sizeof(AliMUONBlockHeaderStruct);
-               if (current > endOfBlocks)
+               if (current > endOfBlocks or current < start)
                {
+                       // If we overflowed the pointer and already had an error then
+                       // we are clearly lost so just stop decoding before we segfault.
+                       if (current < start and fHadError) return;
+                       
                        // We first check if we actually hit the end of DDL markers
                        // If we did then either we did not/could not recover from
                        // a corrupt trailer or we did not detect a correct trailer
@@ -412,7 +474,7 @@ void AliMUONTrackerDDLDecoder<EventHandler>::DecodeBuffer(
                                if (fAutoDetectTrailer)
                                {
                                        // If we got here then there is at least one correct trailer
-                                       // word, but since we did not detect a currect trailer then
+                                       // word, but since we did not detect a correct trailer then
                                        // there must be only one. Announce the error and exit.
                                        fHandler.OnError(EventHandler::kTooFewDDLTrailerWords, trailerWords);
                                        fHadError = true;
@@ -448,7 +510,9 @@ void AliMUONTrackerDDLDecoder<EventHandler>::DecodeBuffer(
                // If any of the above fail then we know there is a problem with
                // the block header. It must be corrupted somehow.
                if (blockHeader->fDataKey != fgkBlockDataKey
-                   or dataEnd > endOfBlocks or blockEnd > endOfBlocks or dataEnd != blockEnd)
+                   or dataEnd > endOfBlocks or dataEnd < start
+                   or blockEnd > endOfBlocks or blockEnd < start
+                   or dataEnd != blockEnd)
                {
                        // So let us see what exactly is wrong and report this.
                        if (blockCount == fMaxBlocks)
@@ -462,9 +526,9 @@ void AliMUONTrackerDDLDecoder<EventHandler>::DecodeBuffer(
                        }
                        if (blockHeader->fDataKey != fgkBlockDataKey)
                                fHandler.OnError(EventHandler::kBadBlockKey, &blockHeader->fDataKey);
-                       if (blockEnd > endOfBlocks)
+                       if (blockEnd > endOfBlocks or blockEnd < start)
                                fHandler.OnError(EventHandler::kBadBlockLength, &blockHeader->fLength);
-                       if (dataEnd > endOfBlocks)
+                       if (dataEnd > endOfBlocks or dataEnd < start)
                                fHandler.OnError(EventHandler::kBadBlockTotalLength, &blockHeader->fTotalLength);
                        if (dataEnd != blockEnd)
                                fHandler.OnError(EventHandler::kBlockLengthMismatch, blockHeader);
@@ -550,8 +614,12 @@ bool AliMUONTrackerDDLDecoder<EventHandler>::DecodeBlockData(
                const AliMUONDSPHeaderStruct* dspHeader
                        = reinterpret_cast<const AliMUONDSPHeaderStruct*>(dspStart);
                current += sizeof(AliMUONDSPHeaderStruct);
-               if (current > end)
+               if (current > end or current < start)
                {
+                       // If we overflowed the pointer and already had an error then
+                       // we are clearly lost so just stop decoding before we segfault.
+                       if (current < start and fHadError) return false;
+                       
                        // So we only got part of a DSP header at the very end of
                        // the block structure buffer. Nothing to do but report the
                        // error and exit. Set fHadError in case of further decoding.
@@ -575,14 +643,16 @@ bool AliMUONTrackerDDLDecoder<EventHandler>::DecodeBlockData(
                // If any of the above fail then we know there is a problem with
                // the DSP header. It must be corrupted somehow.
                if (dspHeader->fDataKey != fgkDSPDataKey
-                   or dataEnd > end or dspEnd > end or dataEnd != dspEnd)
+                   or dataEnd > end or dataEnd < start
+                   or dspEnd > end or dspEnd < start
+                   or dataEnd != dspEnd)
                {
                        // So let us see what exactly is wrong and report this.
                        if (dspHeader->fDataKey != fgkDSPDataKey)
                                fHandler.OnError(EventHandler::kBadDSPKey, &dspHeader->fDataKey);
-                       if (dspEnd > end)
+                       if (dspEnd > end or dspEnd < start)
                                fHandler.OnError(EventHandler::kBadDSPLength, &dspHeader->fLength);
-                       if (dataEnd > end)
+                       if (dataEnd > end or dataEnd < start)
                                fHandler.OnError(EventHandler::kBadDSPTotalLength, &dspHeader->fTotalLength);
                        if (dataEnd != dspEnd)
                                fHandler.OnError(EventHandler::kDSPLengthMismatch, dspHeader);
@@ -622,15 +692,29 @@ bool AliMUONTrackerDDLDecoder<EventHandler>::DecodeBlockData(
                fHandler.OnNewDSP(dspHeader, dataStart);
                
                // Check the error word in the header.
-               if (dspHeader->fErrorWord == (0x000000B1 | blockHeader->fDSPId)
-                   or dspHeader->fErrorWord == (0x00000091 | blockHeader->fDSPId)
-                  )
+               if (dspHeader->fErrorWord != 0x0)
                {
-                       // An event with a glitch in the readout has been detected.
-                       // It means that somewhere a 1 byte word has been randomly
-                       // inserted and all the readout sequence is shifted until
-                       // the next event.
-                       fHandler.OnError(EventHandler::kGlitchFound, &dspHeader->fErrorWord);
+                       if (dspHeader->fErrorWord == (0x000000B1 | blockHeader->fDSPId)
+                           or dspHeader->fErrorWord == (0x00000091 | blockHeader->fDSPId)
+                          )
+                       {
+                               // An event with a glitch in the readout has been detected.
+                               // It means that somewhere a 1 byte word has been randomly
+                               // inserted and all the readout sequence is shifted until
+                               // the next event.
+                               fHandler.OnError(EventHandler::kGlitchFound, &dspHeader->fErrorWord);
+                       }
+                       else if ((dspHeader->fErrorWord & 0x0000FFF0) == 0x220)
+                       {
+                               // Detected a TOKEN_LOST error which can affect the dead time in the DAQ.
+                               fHandler.OnError(EventHandler::kTokenLost, &dspHeader->fErrorWord);
+                       }
+                       else
+                       {
+                               // The DSP error code is non-zero but has an unknown code.
+                               fHandler.OnError(EventHandler::kUnknownDspError, &dspHeader->fErrorWord);
+                       }
+                       
                        fHadError = true;
                        if (fExitOnError)
                        {
@@ -639,11 +723,15 @@ bool AliMUONTrackerDDLDecoder<EventHandler>::DecodeBlockData(
                        }
                        
                        // Try recover by finding the very next DSP and continue
-                       // decoding from there. Note: to achieve all we have to do
-                       // is continue to the next iteration, because the logic
+                       // decoding from there. Note: to achieve this all we have to
+                       // do is continue to the next iteration, because the logic
                        // will land up calling the FindKey method within the
                        // TryRecoverStruct method above.
-                       if (fTryRecover) continue;
+                       if (fTryRecover)
+                       {
+                               fHandler.OnEndOfDSP(dspHeader, dataStart);
+                               continue;
+                       }
                }
                
                // Check if we are padding. If we are, then the bus patch data is
@@ -714,8 +802,12 @@ bool AliMUONTrackerDDLDecoder<EventHandler>::DecodeDSPData(
                const AliMUONBusPatchHeaderStruct* busPatchHeader
                        = reinterpret_cast<const AliMUONBusPatchHeaderStruct*>(busPatchStart);
                current += sizeof(AliMUONBusPatchHeaderStruct);
-               if (current > end)
+               if (current > end or current < start)
                {
+                       // If we overflowed the pointer and already had an error then
+                       // we are clearly lost so just stop decoding before we segfault.
+                       if (current < start and fHadError) return false;
+                       
                        // So we only got part of a bus patch header at the very
                        // end of the DSP structure buffer. Nothing to do but
                        // report the error and exit. Set fHadError in case of
@@ -742,14 +834,16 @@ bool AliMUONTrackerDDLDecoder<EventHandler>::DecodeDSPData(
                // If any of the above fail then we know there is a problem with
                // the bus patch header. It must be corrupted somehow.
                if (busPatchHeader->fDataKey != fgkBusPatchDataKey
-                   or dataEnd > end or busPatchEnd > end or dataEnd != busPatchEnd)
+                   or dataEnd > end or dataEnd < start
+                   or busPatchEnd > end or busPatchEnd < start
+                   or dataEnd != busPatchEnd)
                {
                        // So let us see what exactly is wrong and report this.
                        if (busPatchHeader->fDataKey != fgkBusPatchDataKey)
                                fHandler.OnError(EventHandler::kBadBusPatchKey, &busPatchHeader->fDataKey);
-                       if (busPatchEnd > end)
+                       if (busPatchEnd > end or busPatchEnd < start)
                                fHandler.OnError(EventHandler::kBadBusPatchLength, &busPatchHeader->fLength);
-                       if (dataEnd > end)
+                       if (dataEnd > end or dataEnd < start)
                                fHandler.OnError(EventHandler::kBadBusPatchTotalLength, &busPatchHeader->fTotalLength);
                        if (dataEnd != busPatchEnd)
                                fHandler.OnError(EventHandler::kBusPatchLengthMismatch, busPatchHeader);
@@ -953,7 +1047,7 @@ AliMUONTrackerDDLDecoder<EventHandler>::TryRecoverStruct(
        const UInt_t* headerKey = reinterpret_cast<const UInt_t*>(structStart);
        bool headerKeyOk = (expectedKey == *headerKey);
        
-       bool lengthsMatch = (totalLength == length + headerSize);
+       bool lengthsMatch = (totalLength*4 == length*4 + headerSize);
        
        bool lengthIsCorrect = false;
        bool totalLengthIsCorrect = false;
@@ -972,7 +1066,7 @@ AliMUONTrackerDDLDecoder<EventHandler>::TryRecoverStruct(
                {
                        // Must check that we can read another 4 bytes before
                        // checking the key at dataEnd.
-                       if (dataEnd + sizeof(UInt_t) <= bufferEnd)
+                       if (dataEnd + sizeof(UInt_t) <= bufferEnd and dataEnd + sizeof(UInt_t) > structStart)
                        {
                                if (*keyAtDataEnd == fgkBlockDataKey)
                                        lengthIsCorrect = true;
@@ -988,7 +1082,7 @@ AliMUONTrackerDDLDecoder<EventHandler>::TryRecoverStruct(
                {
                        // Must check that we can read another 4 bytes before
                        // checking the key at structEnd.
-                       if (structEnd + sizeof(UInt_t) <= bufferEnd)
+                       if (structEnd + sizeof(UInt_t) <= bufferEnd and structEnd + sizeof(UInt_t) > structStart)
                        {
                                if (*keyAtStructEnd == fgkBlockDataKey)
                                        totalLengthIsCorrect = true;
@@ -1007,7 +1101,7 @@ AliMUONTrackerDDLDecoder<EventHandler>::TryRecoverStruct(
                {
                        // Must check that we can read another 4 bytes before
                        // checking the key at dataEnd.
-                       if (dataEnd + sizeof(UInt_t) <= bufferEnd)
+                       if (dataEnd + sizeof(UInt_t) <= bufferEnd and dataEnd + sizeof(UInt_t) > structStart)
                        {
                                if (*keyAtDataEnd == fgkBlockDataKey
                                    or *keyAtDataEnd == fgkDSPDataKey)
@@ -1024,7 +1118,7 @@ AliMUONTrackerDDLDecoder<EventHandler>::TryRecoverStruct(
                {
                        // Must check that we can read another 4 bytes before
                        // checking the key at structEnd.
-                       if (structEnd + sizeof(UInt_t) <= bufferEnd)
+                       if (structEnd + sizeof(UInt_t) <= bufferEnd and structEnd + sizeof(UInt_t) > structStart)
                        {
                                if (*keyAtStructEnd == fgkBlockDataKey
                                    or *keyAtStructEnd == fgkDSPDataKey)
@@ -1043,7 +1137,7 @@ AliMUONTrackerDDLDecoder<EventHandler>::TryRecoverStruct(
                {
                        // Must check that we can read another 4 bytes before
                        // checking the key at dataEnd.
-                       if (dataEnd + sizeof(UInt_t) <= bufferEnd)
+                       if (dataEnd + sizeof(UInt_t) <= bufferEnd and dataEnd + sizeof(UInt_t) > structStart)
                        {
                                if (*keyAtDataEnd == fgkDSPDataKey
                                    or *keyAtDataEnd == fgkBusPatchDataKey)
@@ -1060,7 +1154,7 @@ AliMUONTrackerDDLDecoder<EventHandler>::TryRecoverStruct(
                {
                        // Must check that we can read another 4 bytes before
                        // checking the key at structEnd.
-                       if (structEnd + sizeof(UInt_t) <= bufferEnd)
+                       if (structEnd + sizeof(UInt_t) <= bufferEnd and structEnd + sizeof(UInt_t) > structStart)
                        {
                                if (*keyAtStructEnd == fgkDSPDataKey
                                    or *keyAtStructEnd == fgkBusPatchDataKey)
@@ -1115,7 +1209,8 @@ const UChar_t* AliMUONTrackerDDLDecoder<EventHandler>::FindKey(
        /// should point to 'start + bufferSize', i.e. just past the last byte of the
        /// buffer. If the key was found then the pointer to that location is returned
        /// otherwise NULL is returned.
+       
+       if (end + sizeof(UInt_t) < start) return NULL;  // check for pointer overflow.
        const UChar_t* current = start;
        while (current + sizeof(UInt_t) <= end)
        {