From f50d9f5688e7b571ee9437546711049e0171988a Mon Sep 17 00:00:00 2001
From: Dinyar Rabady <dinyar.rabady@cern.ch>
Date: Mon, 28 Nov 2022 15:46:36 +0100
Subject: [PATCH] Add asserts to ensure we don't leave valid memory space

---
 src/processor.cc | 23 ++++++++++++++++-------
 src/processor.h  |  4 ++--
 2 files changed, 18 insertions(+), 9 deletions(-)

diff --git a/src/processor.cc b/src/processor.cc
index ac63156e..bd1ba6b7 100644
--- a/src/processor.cc
+++ b/src/processor.cc
@@ -6,6 +6,7 @@
 #include <cmath>
 #include <vector>
 #include <algorithm>
+#include <cassert>
 
 // Definition of the static member stats
 StreamProcessor::Statistics StreamProcessor::stats;
@@ -64,7 +65,7 @@ bool StreamProcessor::CheckFrameMultBlock(size_t inputSize){
 
 bool StreamProcessor::GetTrailer(Slice& input, char*& rd_ptr) {
 	rd_ptr += 32; // +32 to account for orbit header
-	while ( rd_ptr != input.end()){
+	while ( rd_ptr + sizeof(orbit_trailer) - 1 <= input.end() ) {
 		orbit_trailer* ot = reinterpret_cast<orbit_trailer*>(rd_ptr);
 		if (ot->beefdead[0]==constants::beefdead){ // found orbit trailer
 			return true;
@@ -87,7 +88,7 @@ inline std::pair<uint32_t, bool> StreamProcessor::ProcessOrbitHeader(char* rd_pt
 }
 
 // Goes through orbit worth of data and fills the output memory with the calo data corresponding to the non-empty bunchcrossings, as marked in bx_vect
-StreamProcessor::fillOrbitMetadata StreamProcessor::FillOrbitCalo(orbit_trailer* trailer, char* rd_ptr, char* wr_ptr){
+StreamProcessor::fillOrbitMetadata StreamProcessor::FillOrbitCalo(orbit_trailer* trailer, char* rd_ptr, char* wr_ptr, char* rd_end_ptr, char* wr_end_ptr){
   std::pair<uint32_t, bool> orbit_header = std::pair<uint32_t, bool> {ProcessOrbitHeader(rd_ptr)};//.second is the warning test enable bit
   rd_ptr += 32; // +32 to account for orbit header
   uint32_t orbit = uint32_t{orbit_header.first} - 1; // Starting with orbit number one lower than what is in the header because the "link orbit" contains a few BXs of the previous orbit
@@ -117,9 +118,11 @@ StreamProcessor::fillOrbitMetadata StreamProcessor::FillOrbitCalo(orbit_trailer*
     if((trailer->bx_map[word] & (1 << bit)) == 0) {
       continue; // If the bit is zero that BX was empty and we continue.
     }
+    assert(rd_ptr + sizeof(blockCalo) - 1 <= rd_end_ptr);
     ++filled_bxs;
     blockCalo *bl = reinterpret_cast<blockCalo*>(rd_ptr);
     if (bl->calo0[0]==constants::beefdead){break;} // orbit trailer has been reached, end of orbit data
+    assert(wr_ptr + (3 + 8*7)*4 - 1 <= wr_end_ptr);
     uint32_t header = uint32_t{orbit_header.second}; //header can be added to later
     memcpy(wr_ptr,(char*)&header,4); wr_ptr+=4;
     memcpy(wr_ptr,(char*)&bx,4); wr_ptr+=4;
@@ -152,6 +155,7 @@ uint32_t StreamProcessor::FillBril(char* rd_ptr, char* wr_ptr, char* end_ptr){
 	//BrilHistoQueue<std::array<uint32_t, constants::NBXPerOrbit + constants::NFramesInHistoHeader>> BrilQueue;	
 
 	while ( (rd_ptr != end_ptr) && (histo_i < NHistosPerPacket)){
+    assert(rd_ptr + sizeof(brilFrame) - 1 <= end_ptr);
 
 		brilFrame *fr = reinterpret_cast<brilFrame*>(rd_ptr);
 		if (fr->word == constants::bril_header){
@@ -185,7 +189,7 @@ uint32_t StreamProcessor::FillBril(char* rd_ptr, char* wr_ptr, char* end_ptr){
 
 
 // Goes through orbit worth of data and fills the output memory with the muons corresponding to the non-empty bunchcrossings, as marked in bx_vect
-StreamProcessor::fillOrbitMetadata StreamProcessor::FillOrbitMuon(orbit_trailer* trailer, char* rd_ptr, char* wr_ptr){
+StreamProcessor::fillOrbitMetadata StreamProcessor::FillOrbitMuon(orbit_trailer* trailer, char* rd_ptr, char* wr_ptr, char* rd_end_ptr, char* wr_end_ptr){
     std::pair<uint32_t, bool> orbit_header = std::pair<uint32_t, bool>{ProcessOrbitHeader(rd_ptr)};//.second is the warning test enable bit
     rd_ptr += 32; // +32 to account for orbit header
     uint32_t orbit = uint32_t{orbit_header.first} - 1; // Starting with orbit number one lower than what is in the header because the "link orbit" contains a few BXs of the previous orbit
@@ -215,9 +219,11 @@ StreamProcessor::fillOrbitMetadata StreamProcessor::FillOrbitMuon(orbit_trailer*
       if((trailer->bx_map[word] & (1 << bit)) == 0) {
         continue; // If the bit is zero that BX was empty and we continue.
       }
+      assert(rd_ptr + sizeof(blockMuon) - 1 <= rd_end_ptr);
       ++filled_bxs;
       blockMuon *bl = reinterpret_cast<blockMuon*>(rd_ptr);
       if (bl->orbit[0]==constants::beefdead){ break; } // orbit trailer has been reached, end of orbit data
+      assert(wr_ptr + (3 + 2*8*3)*4 - 1 <= wr_end_ptr); // Assuming the maximum size a decoded muon block can use.
       int mAcount = 0;
       int mBcount = 0;
       bool AblocksOn[8];
@@ -292,7 +298,8 @@ void StreamProcessor::process(Slice& input, Slice& out)
 	
 	char* rd_ptr = input.begin();
 	char* wr_ptr = out.begin();
-	char* end_ptr = input.end();
+	char* rd_end_ptr = input.end();
+	char* wr_end_ptr = out.begin() + out.avail();
 	uint32_t counts = 0;
 	bool endofpacket = false;
 	uint32_t orbit_per_packet_count = 0;
@@ -305,7 +312,7 @@ void StreamProcessor::process(Slice& input, Slice& out)
 		return;
 	}
 	if (processorType == ProcessorType::BRIL){
-		counts = FillBril(rd_ptr, wr_ptr, end_ptr);
+		counts = FillBril(rd_ptr, wr_ptr, rd_end_ptr);
 		out.set_end(out.begin() + counts);
 		out.set_counts(counts);
 		return;
@@ -323,12 +330,12 @@ void StreamProcessor::process(Slice& input, Slice& out)
 		}
 		orbit_trailer* trailer = reinterpret_cast<orbit_trailer*>(trailer_ptr);
 		if (processorType == ProcessorType::GMT) {
-			meta  = FillOrbitMuon(trailer, rd_ptr, wr_ptr);
+			meta  = FillOrbitMuon(trailer, rd_ptr, wr_ptr, rd_end_ptr, wr_end_ptr);
 			orbitCount = meta.counts;
 			++orbit_per_packet_count;
 			wr_ptr+= meta.counts*12 + 12*meta.filled_bxs; // 12 bytes for each muon/count then 12 bytes for each bx header
 		} else if (processorType == ProcessorType::CALO){
-			meta = FillOrbitCalo(trailer, rd_ptr, wr_ptr);				
+			meta = FillOrbitCalo(trailer, rd_ptr, wr_ptr, rd_end_ptr, wr_end_ptr);
 			orbitCount = meta.counts;
 			++orbit_per_packet_count;
 			// size of calo packet is 4bytes*(8links*7dataWords + 3headerWords)=236 bytes
@@ -339,6 +346,8 @@ void StreamProcessor::process(Slice& input, Slice& out)
     		throw std::invalid_argument("ERROR: PROCESSOR_TYPE NOT RECOGNISED");
 		}
 		rd_ptr+= 32 + meta.filled_bxs*sizeof(blockMuon) + constants::orbit_trailer_size; // 32 for orbit header, + nBXs + orbit trailer
+    assert(wr_ptr <= wr_end_ptr);
+    assert(rd_ptr <= rd_end_ptr);
 		counts += orbitCount;
 		if (firstOrbit){
 			out.set_firstOrbitN(meta.orbit);
diff --git a/src/processor.h b/src/processor.h
index c2a42e7a..b17f5ff7 100644
--- a/src/processor.h
+++ b/src/processor.h
@@ -33,8 +33,8 @@ private:
   bool CheckFrameMultBlock(size_t inputSize);  
   bool GetTrailer(Slice& input, char*& rd_ptr);
   inline std::pair<uint32_t, bool> ProcessOrbitHeader(char* rd_ptr);
-  fillOrbitMetadata FillOrbitMuon(orbit_trailer* trailer, char* rd_ptr, char* wr_ptr);
-  fillOrbitMetadata FillOrbitCalo(orbit_trailer* trailer, char* rd_ptr, char* wr_ptr);
+  fillOrbitMetadata FillOrbitMuon(orbit_trailer* trailer, char* rd_ptr, char* wr_ptr, char* rd_end_ptr, char* wr_end_ptr);
+  fillOrbitMetadata FillOrbitCalo(orbit_trailer* trailer, char* rd_ptr, char* wr_ptr, char* rd_end_ptr, char* wr_end_ptr);
   uint32_t FillBril(char* rd_ptr, char* wr_ptr, char* end_ptr);
   size_t max_size;
   uint64_t nbPackets;
-- 
GitLab