From db3d802c409cb5abec3b07175b219118056c5d4d Mon Sep 17 00:00:00 2001
From: Martyn Gigg <martyn.gigg@gmail.com>
Date: Sun, 19 Aug 2018 12:15:04 +0100
Subject: [PATCH] Use unique_ptr to manage array memory

Avoid memory leaks on various error paths.
---
 .../MantidDataHandling/LoadBankFromDiskTask.h |  17 +--
 .../DataHandling/src/LoadBankFromDiskTask.cpp | 132 +++++++++---------
 2 files changed, 71 insertions(+), 78 deletions(-)

diff --git a/Framework/DataHandling/inc/MantidDataHandling/LoadBankFromDiskTask.h b/Framework/DataHandling/inc/MantidDataHandling/LoadBankFromDiskTask.h
index 52464a7a609..18799248f1a 100644
--- a/Framework/DataHandling/inc/MantidDataHandling/LoadBankFromDiskTask.h
+++ b/Framework/DataHandling/inc/MantidDataHandling/LoadBankFromDiskTask.h
@@ -54,12 +54,13 @@ public:
 
 private:
   void loadPulseTimes(::NeXus::File &file);
-  void loadEventIndex(::NeXus::File &file, std::vector<uint64_t> &event_index);
+  std::unique_ptr<std::vector<uint64_t>> loadEventIndex(::NeXus::File &file);
   void prepareEventId(::NeXus::File &file, int64_t &start_event,
-                      int64_t &stop_event, std::vector<uint64_t> &event_index);
-  void loadEventId(::NeXus::File &file);
-  void loadTof(::NeXus::File &file);
-  void loadEventWeights(::NeXus::File &file);
+                      int64_t &stop_event,
+                      const std::vector<uint64_t> &event_index);
+  std::unique_ptr<uint32_t[]> loadEventId(::NeXus::File &file);
+  std::unique_ptr<float[]> loadTof(::NeXus::File &file);
+  std::unique_ptr<float[]> loadEventWeights(::NeXus::File &file);
   int64_t recalculateDataSize(const int64_t &size);
 
   /// Algorithm being run
@@ -82,18 +83,12 @@ private:
   std::vector<int64_t> m_loadStart;
   /// How much to load in the file
   std::vector<int64_t> m_loadSize;
-  /// Event pixel ID data
-  uint32_t *m_event_id;
   /// Minimum pixel ID in this data
   uint32_t m_min_id;
   /// Maximum pixel ID in this data
   uint32_t m_max_id;
-  /// TOF data
-  float *m_event_time_of_flight;
   /// Flag for simulated data
   bool m_have_weight;
-  /// Event weights
-  float *m_event_weight;
   /// Frame period numbers
   const std::vector<int> m_framePeriodNumbers;
 }; // END-DEF-CLASS LoadBankFromDiskTask
diff --git a/Framework/DataHandling/src/LoadBankFromDiskTask.cpp b/Framework/DataHandling/src/LoadBankFromDiskTask.cpp
index a0c365a99bc..53b31de75c5 100644
--- a/Framework/DataHandling/src/LoadBankFromDiskTask.cpp
+++ b/Framework/DataHandling/src/LoadBankFromDiskTask.cpp
@@ -27,9 +27,8 @@ LoadBankFromDiskTask::LoadBankFromDiskTask(
     const std::vector<int> &framePeriodNumbers)
     : m_loader(loader), entry_name(entry_name), entry_type(entry_type),
       prog(prog), scheduler(scheduler), m_loadError(false),
-      m_oldNexusFileNames(oldNeXusFileNames), m_event_id(nullptr),
-      m_event_time_of_flight(nullptr), m_have_weight(false),
-      m_event_weight(nullptr), m_framePeriodNumbers(framePeriodNumbers) {
+      m_oldNexusFileNames(oldNeXusFileNames), m_have_weight(false),
+      m_framePeriodNumbers(framePeriodNumbers) {
   setMutex(ioMutex);
   m_cost = static_cast<double>(numEvents);
   m_min_id = std::numeric_limits<uint32_t>::max();
@@ -72,20 +71,19 @@ void LoadBankFromDiskTask::loadPulseTimes(::NeXus::File &file) {
 }
 
 /** Load the event_index field
-(a list of size of # of pulses giving the index in the event list for that
-pulse)
-
-* @param file :: File handle for the NeXus file
-* @param event_index :: ref to the vector
-*/
-void LoadBankFromDiskTask::loadEventIndex(::NeXus::File &file,
-                                          std::vector<uint64_t> &event_index) {
+ * (a list of size of # of pulses giving the index in the event list for that
+    pulse)
+ * @param file :: File handle for the NeXus file
+ */
+std::unique_ptr<std::vector<uint64_t>>
+LoadBankFromDiskTask::loadEventIndex(::NeXus::File &file) {
   // Get the event_index (a list of size of # of pulses giving the index in
   // the event list for that pulse)
   file.openData("event_index");
   // Must be uint64
+  auto event_index = Kernel::make_unique<std::vector<uint64_t>>();
   if (file.getInfo().type == ::NeXus::UINT64)
-    file.getData(event_index);
+    file.getData(*event_index);
   else {
     m_loader.alg->getLogger().warning()
         << "Entry " << entry_name
@@ -95,14 +93,15 @@ void LoadBankFromDiskTask::loadEventIndex(::NeXus::File &file,
   file.closeData();
 
   // Look for the sign that the bank is empty
-  if (event_index.size() == 1) {
-    if (event_index[0] == 0) {
+  if (event_index->size() == 1) {
+    if ((*event_index)[0] == 0) {
       // One entry, only zero. This means NO events in this bank.
       m_loadError = true;
       m_loader.alg->getLogger().debug()
           << "Bank " << entry_name << " is empty.\n";
     }
   }
+  return event_index;
 }
 
 /** Open the event_id field and validate the contents
@@ -113,10 +112,9 @@ void LoadBankFromDiskTask::loadEventIndex(::NeXus::File &file,
  * @param event_index ::  (a list of size of # of pulses giving the index in
  *the event list for that pulse)
  */
-void LoadBankFromDiskTask::prepareEventId(::NeXus::File &file,
-                                          int64_t &start_event,
-                                          int64_t &stop_event,
-                                          std::vector<uint64_t> &event_index) {
+void LoadBankFromDiskTask::prepareEventId(
+    ::NeXus::File &file, int64_t &start_event, int64_t &stop_event,
+    const std::vector<uint64_t> &event_index) {
   // Get the list of pixel ID's
   if (m_oldNexusFileNames)
     file.openData("event_pixel_id");
@@ -179,15 +177,18 @@ void LoadBankFromDiskTask::prepareEventId(::NeXus::File &file,
       << stop_event << "\n";
 }
 
-/** Load the event_id field, which has been open
+/** Load the event_id field, which has been opened
+ * @param file An NeXus::File object opened at the correct group
+ * @returns A new array containing the event Ids for this bank
  */
-void LoadBankFromDiskTask::loadEventId(::NeXus::File &file) {
+std::unique_ptr<uint32_t[]>
+LoadBankFromDiskTask::loadEventId(::NeXus::File &file) {
   // This is the data size
   ::NeXus::Info id_info = file.getInfo();
   int64_t dim0 = recalculateDataSize(id_info.dims[0]);
 
   // Now we allocate the required arrays
-  m_event_id = new uint32_t[m_loadSize[0]];
+  auto event_id = Kernel::make_unique<uint32_t[]>(m_loadSize[0]);
 
   // Check that the required space is there in the file.
   if (dim0 < m_loadSize[0] + m_loadStart[0]) {
@@ -204,7 +205,7 @@ void LoadBankFromDiskTask::loadEventId(::NeXus::File &file) {
   if (!m_loadError) {
     // Must be uint32
     if (id_info.type == ::NeXus::UINT32)
-      file.getSlab(m_event_id, m_loadStart, m_loadSize);
+      file.getSlab(event_id.get(), m_loadStart, m_loadSize);
     else {
       m_loader.alg->getLogger().warning()
           << "Entry " << entry_name
@@ -214,12 +215,12 @@ void LoadBankFromDiskTask::loadEventId(::NeXus::File &file) {
     file.closeData();
 
     // determine the range of pixel ids
-    for (auto i = 0; i < m_loadSize[0]; ++i) {
-      uint32_t temp = m_event_id[i];
-      if (temp < m_min_id)
-        m_min_id = temp;
-      if (temp > m_max_id)
-        m_max_id = temp;
+    for (int64_t i = 0; i < m_loadSize[0]; ++i) {
+      const auto id = event_id[i];
+      if (id < m_min_id)
+        m_min_id = id;
+      if (id > m_max_id)
+        m_max_id = id;
     }
 
     if (m_min_id > static_cast<uint32_t>(m_loader.eventid_max)) {
@@ -241,15 +242,16 @@ void LoadBankFromDiskTask::loadEventId(::NeXus::File &file) {
     if (m_max_id > static_cast<uint32_t>(m_loader.eventid_max))
       m_max_id = static_cast<uint32_t>(m_loader.eventid_max);
   }
+  return event_id;
 }
 
 /** Open and load the times-of-flight data
+ * @param file An NeXus::File object opened at the correct group
+ * @returns A new array containing the time of flights for this bank
  */
-void LoadBankFromDiskTask::loadTof(::NeXus::File &file) {
+std::unique_ptr<float[]> LoadBankFromDiskTask::loadTof(::NeXus::File &file) {
   // Allocate the array
-  auto temp = new float[m_loadSize[0]];
-  delete[] m_event_time_of_flight;
-  m_event_time_of_flight = temp;
+  auto event_time_of_flight = Kernel::make_unique<float[]>(m_loadSize[0]);
 
   // Get the list of event_time_of_flight's
   if (!m_oldNexusFileNames)
@@ -270,7 +272,7 @@ void LoadBankFromDiskTask::loadTof(::NeXus::File &file) {
 
   // Check that the type is what it is supposed to be
   if (tof_info.type == ::NeXus::FLOAT32)
-    file.getSlab(m_event_time_of_flight, m_loadStart, m_loadSize);
+    file.getSlab(event_time_of_flight.get(), m_loadStart, m_loadSize);
   else {
     m_loader.alg->getLogger().warning()
         << "Entry " << entry_name
@@ -290,26 +292,29 @@ void LoadBankFromDiskTask::loadTof(::NeXus::File &file) {
     }
     file.closeData();
   } // no error
+  return event_time_of_flight;
 }
 
-/** Load weight of weigthed events
+/** Load weight of weigthed events if they exist
+ * @param file An NeXus::File object opened at the correct group
+ * @returns A new array containing the weights or a nullptr if the weights
+ * are not present
  */
-void LoadBankFromDiskTask::loadEventWeights(::NeXus::File &file) {
+std::unique_ptr<float[]>
+LoadBankFromDiskTask::loadEventWeights(::NeXus::File &file) {
   try {
     // First, get info about the event_weight field in this bank
     file.openData("event_weight");
   } catch (::NeXus::Exception &) {
     // Field not found error is most likely.
     m_have_weight = false;
-    return;
+    return std::unique_ptr<float[]>();
   }
   // OK, we've got them
   m_have_weight = true;
 
   // Allocate the array
-  auto temp = new float[m_loadSize[0]];
-  delete[] m_event_weight;
-  m_event_weight = temp;
+  auto event_weight = Kernel::make_unique<float[]>(m_loadSize[0]);
 
   ::NeXus::Info weight_info = file.getInfo();
   int64_t weight_dim0 = recalculateDataSize(weight_info.dims[0]);
@@ -322,7 +327,7 @@ void LoadBankFromDiskTask::loadEventWeights(::NeXus::File &file) {
 
   // Check that the type is what it is supposed to be
   if (weight_info.type == ::NeXus::FLOAT32)
-    file.getSlab(m_event_weight, m_loadStart, m_loadSize);
+    file.getSlab(event_weight.get(), m_loadStart, m_loadSize);
   else {
     m_loader.alg->getLogger().warning()
         << "Entry " << entry_name
@@ -333,28 +338,26 @@ void LoadBankFromDiskTask::loadEventWeights(::NeXus::File &file) {
   if (!m_loadError) {
     file.closeData();
   }
+  return event_weight;
 }
 
 void LoadBankFromDiskTask::run() {
-  // The vectors we will be filling
-  auto event_index_ptr = new std::vector<uint64_t>();
-  std::vector<uint64_t> &event_index = *event_index_ptr;
-
   // These give the limits in each file as to which events we actually load
   // (when filtering by time).
   m_loadStart.resize(1, 0);
   m_loadSize.resize(1, 0);
 
-  // Data arrays
-  m_event_id = nullptr;
-  m_event_time_of_flight = nullptr;
-  m_event_weight = nullptr;
-
   m_loadError = false;
   m_have_weight = m_loader.m_haveWeights;
 
   prog->report(entry_name + ": load from disk");
 
+  // arrays to load into
+  std::unique_ptr<uint32_t[]> event_id;
+  std::unique_ptr<float[]> event_time_of_flight;
+  std::unique_ptr<float[]> event_weight;
+  std::unique_ptr<std::vector<uint64_t>> event_index_ptr;
+
   // Open the file
   ::NeXus::File file(m_loader.alg->m_filename);
   try {
@@ -364,7 +367,7 @@ void LoadBankFromDiskTask::run() {
     file.openGroup(entry_name, entry_type);
 
     // Load the event_index field.
-    this->loadEventIndex(file, event_index);
+    event_index_ptr = this->loadEventIndex(file);
 
     if (!m_loadError) {
       // Load and validate the pulse times
@@ -372,7 +375,7 @@ void LoadBankFromDiskTask::run() {
 
       // The event_index should be the same length as the pulse times from DAS
       // logs.
-      if (event_index.size() != thisBankPulseTimes->numPulses)
+      if (event_index_ptr->size() != thisBankPulseTimes->numPulses)
         m_loader.alg->getLogger().warning()
             << "Bank " << entry_name
             << " has a mismatch between the number of event_index entries "
@@ -381,7 +384,7 @@ void LoadBankFromDiskTask::run() {
       // Open and validate event_id field.
       int64_t start_event = 0;
       int64_t stop_event = 0;
-      this->prepareEventId(file, start_event, stop_event, event_index);
+      this->prepareEventId(file, start_event, stop_event, *event_index_ptr);
 
       // These are the arguments to getSlab()
       m_loadStart[0] = start_event;
@@ -389,7 +392,7 @@ void LoadBankFromDiskTask::run() {
 
       if ((m_loadSize[0] > 0) && (m_loadStart[0] >= 0)) {
         // Load pixel IDs
-        this->loadEventId(file);
+        event_id = this->loadEventId(file);
         if (m_loader.alg->getCancel()) {
           m_loader.alg->getLogger().error()
               << "Loading bank " << entry_name << " is cancelled.\n";
@@ -398,9 +401,9 @@ void LoadBankFromDiskTask::run() {
 
         // And TOF.
         if (!m_loadError) {
-          this->loadTof(file);
+          event_time_of_flight = this->loadTof(file);
           if (m_have_weight) {
-            this->loadEventWeights(file);
+            event_weight = this->loadEventWeights(file);
           }
         }
       } // Size is at least 1
@@ -434,13 +437,6 @@ void LoadBankFromDiskTask::run() {
 
   // Abort if anything failed
   if (m_loadError) {
-    delete[] m_event_id;
-    delete[] m_event_time_of_flight;
-    if (m_have_weight) {
-      delete[] m_event_weight;
-    }
-    delete event_index_ptr;
-
     return;
   }
 
@@ -485,11 +481,13 @@ void LoadBankFromDiskTask::run() {
   size_t numEvents = static_cast<size_t>(m_loadSize[0]);
   size_t startAt = static_cast<size_t>(m_loadStart[0]);
 
-  // convert things to shared_arrays
-  boost::shared_array<uint32_t> event_id_shrd(m_event_id);
-  boost::shared_array<float> event_time_of_flight_shrd(m_event_time_of_flight);
-  boost::shared_array<float> event_weight_shrd(m_event_weight);
-  boost::shared_ptr<std::vector<uint64_t>> event_index_shrd(event_index_ptr);
+  // convert things to shared_arrays to share between tasks
+  boost::shared_array<uint32_t> event_id_shrd(event_id.release());
+  boost::shared_array<float> event_time_of_flight_shrd(
+      event_time_of_flight.release());
+  boost::shared_array<float> event_weight_shrd(event_weight.release());
+  boost::shared_ptr<std::vector<uint64_t>> event_index_shrd(
+      event_index_ptr.release());
 
   ProcessBankData *newTask1 = new ProcessBankData(
       m_loader, entry_name, prog, event_id_shrd, event_time_of_flight_shrd,
-- 
GitLab