From c4929ccc4c181940100b3c0a9b3cd5b57a9df26a Mon Sep 17 00:00:00 2001 From: Andreas Suter Date: Mon, 13 Jul 2026 08:05:38 +0200 Subject: [PATCH] guard all any_cast attribute reads in ReadNexusFileIdf1 against bad_any_cast Uncaught std::bad_any_cast calls terminated the program when an HDF4 attribute's stored type didn't match the expected type (e.g. vector instead of int, or a non-string units attribute). Wrap all eight attribute casts with try/catch so type mismatches produce a warning rather than a crash. Co-Authored-By: Claude Sonnet 4.6 --- src/include/PRunDataHandler.h | 159 +++++++++++++++++++++++++++++++--- 1 file changed, 149 insertions(+), 10 deletions(-) diff --git a/src/include/PRunDataHandler.h b/src/include/PRunDataHandler.h index b39db0c8..b283a4d7 100644 --- a/src/include/PRunDataHandler.h +++ b/src/include/PRunDataHandler.h @@ -530,16 +530,155 @@ Bool_t PRunDataHandler::ReadNexusFileIdf1(T& nxs_file) ival = nxs_file->template GetDataset("/run/number").GetData()[0]; runData.SetRunNumber(ival); - // get/set temperature - dval = PMUSR_UNDEFINED; - sstr = "n/a"; - if (nxs_file->HasDataset("/run/sample/temperature")) { - auto tmp_ds = nxs_file->template GetDataset("/run/sample/temperature"); - dval = tmp_ds.GetData()[0]; - if (tmp_ds.HasAttribute("units")) - sstr = std::any_cast(tmp_ds.GetAttribute("units")); - if (sstr == "Celcius") - dval += 273.16; + // get/set temperature + dval = PMUSR_UNDEFINED; + sstr = "n/a"; + if (nxs_file->HasDataset("/run/sample/temperature")) { + auto tmp_ds = nxs_file->template GetDataset("/run/sample/temperature"); + dval = tmp_ds.GetData()[0]; + if (tmp_ds.HasAttribute("units")) { + try { + sstr = std::any_cast(tmp_ds.GetAttribute("units")); + } catch (const std::bad_any_cast&) { + std::cerr << std::endl << "**WARNING** ReadNexusFileIdf1: temperature 'units' attribute has unexpected type." << std::endl; + } + } + if (sstr == "Celcius") + dval += 273.16; + } + runData.SetTemperature(0, dval, 0.0); + + // get/set field + dval = PMUSR_UNDEFINED; + sstr = "n/a"; + factor = 1.0; + if (nxs_file->HasDataset("/run/sample/magnetic_field")) { + auto mag_ds = nxs_file->template GetDataset("/run/sample/magnetic_field"); + dval = mag_ds.GetData()[0]; + if (mag_ds.HasAttribute("units")) { + try { + sstr = std::any_cast(mag_ds.GetAttribute("units")); + } catch (const std::bad_any_cast&) { + std::cerr << std::endl << "**WARNING** ReadNexusFileIdf1: magnetic_field 'units' attribute has unexpected type." << std::endl; + } + } + if (sstr == "Tesla") + factor = 1.0e4; + } + runData.SetField(dval*factor); + + // get/set implantation energy + runData.SetEnergy(PMUSR_UNDEFINED); + + // get/set moderator HV + runData.SetTransport(PMUSR_UNDEFINED); + + // get/set RA HV's (LEM specific) + for (UInt_t i=0; i<4; i++) + runData.SetRingAnode(i, PMUSR_UNDEFINED); + + // get/set setup + sstr = "n/a"; + if (nxs_file->HasDataset("/run/notes")) + sstr = nxs_file->template GetDataset("/run/notes").GetData()[0]; + runData.SetSetup(sstr); + + // get/set sample + sstr = "n/a"; + if (nxs_file->HasDataset("/run/sample/name")) + sstr = nxs_file->template GetDataset("/run/sample/name").GetData()[0]; + runData.SetSample(sstr); + + // get/set orientation + runData.SetOrientation("??"); + + // get/set time resolution (ns) + dval = PMUSR_UNDEFINED; + sstr = "n/a"; + factor = 1.0; + if (nxs_file->HasDataset("/run/histogram_data_1/resolution")) { + auto res_ds = nxs_file->template GetDataset("/run/histogram_data_1/resolution"); + dval = res_ds.GetData()[0]; + if (res_ds.HasAttribute("units")) { + try { + sstr = std::any_cast(res_ds.GetAttribute("units")); + } catch (const std::bad_any_cast&) { + std::cerr << std::endl << "**WARNING** ReadNexusFileIdf1: resolution 'units' attribute has unexpected type." << std::endl; + } + } + if ((sstr == "picoseconds") || (sstr == "pico.seconds")) + factor = 1.0e-3; // ps -> ns + } + runData.SetTimeResolution(dval*factor); + + // get/set start/stop time + sstr = "n/a"; + TString date{"n/a"}, time{"n/a"}; + if (nxs_file->HasDataset("/run/start_time")) + sstr = nxs_file->template GetDataset("/run/start_time").GetData()[0]; + str = sstr; + SplitTimeDate(str, time, date, ok); + if (ok) { + runData.SetStartTime(time); + runData.SetStartDate(date); + } + + sstr = "n/a"; + date = "n/a"; + time = "n/a"; + if (nxs_file->HasDataset("/run/stop_time")) + sstr = nxs_file->template GetDataset("/run/stop_time").GetData()[0]; + str = sstr; + SplitTimeDate(str, time, date, ok); + if (ok) { + runData.SetStopTime(time); + runData.SetStopDate(date); + } + + // get/set deadtime relevant parameters + if (nxs_file->HasDataset("/run/instrument/detector/deadtimes")) { + std::vector dt; + dt = nxs_file->template GetDataset("/run/instrument/detector/deadtimes").GetData(); + runData.SetDeadTimeParam(dt); + } + if (nxs_file->HasDataset("/run/instrument/beam/frames_good")) { + ival = nxs_file->template GetDataset("/run/instrument/beam/frames_good").GetData()[0]; + runData.SetNumberOfGoodFrames(ival); + } + + // data with its metadata + if (nxs_file->HasDataset("/run/histogram_data_1/counts")) { + int t0_bin{-1}, fgb{-1}, lgb{-1}, noOfHistos{-1}, histoLength{-1}; + auto count_ds = nxs_file->template GetDataset("/run/histogram_data_1/counts"); + auto count = count_ds.GetData(); + // get all necessary attributes + auto castIntAttr = [](const std::any& val, const std::string& name) -> int { + try { + return std::any_cast(val); + } catch (const std::bad_any_cast&) { + try { + // Attribute may be stored as vector when HDF4 attr_count > 1 + return std::any_cast>(val)[0]; + } catch (const std::bad_any_cast&) { + std::cerr << std::endl << "**WARNING** ReadNexusFileIdf1: counts attribute '" << name + << "' has unexpected type; defaulting to -1." << std::endl; + return -1; + } + } + }; + if (count_ds.HasAttribute("t0_bin")) + t0_bin = castIntAttr(count_ds.GetAttribute("t0_bin"), "t0_bin"); + if (count_ds.HasAttribute("first_good_bin")) + fgb = castIntAttr(count_ds.GetAttribute("first_good_bin"), "first_good_bin"); + if (count_ds.HasAttribute("last_good_bin")) + lgb = castIntAttr(count_ds.GetAttribute("last_good_bin"), "last_good_bin"); + if (count_ds.HasAttribute("number")) + noOfHistos = castIntAttr(count_ds.GetAttribute("number"), "number"); + if (count_ds.HasAttribute("length")) + histoLength = castIntAttr(count_ds.GetAttribute("length"), "length"); + if (static_cast(count.size()) != noOfHistos*histoLength) { + std::cerr << std::endl << "**ERROR** PNeXus data size error! count.size()=" << count.size() << ", #histos=" << noOfHistos << ", length=" << histoLength << "." << std::endl; + return false; } runData.SetTemperature(0, dval, 0.0);