CVE-2024-27628: Insufficient Information (NVD-CWE-noinfo)
value: Buffer Overflow vulnerability in DCMTK v.3.6.8 allows an attacker to execute arbitrary code via the EctEnhancedCT method component.
CWE description: There is insufficient information about the issue to classify it; details are unkown or unspecified.
Published: 2024-06-28T19:15Z
Repository: https://github.com/DCMTK/dcmtk
Language: C++
Files changed: dcmect/libsrc/enhanced_ct.cc, dcmect/tests/CMakeLists.txt, dcmect/tests/Makefile.dep, dcmect/tests/Makefile.in, dcmect/tests/t_overflow.cc, dcmect/tests/tests.cc
Commit date: 2024-02-21 11:06:32 +0100
Commit message: Fixed possible overflows when allocating memory.

Thanks to GitHub user "bananabr" (Daniel Berredo) for the report and
suggested patch.

Diff: diff --git a/dcmect/libsrc/enhanced_ct.cc b/dcmect/libsrc/enhanced_ct.cc
index 90b2d1d68..cffd610a8 100644
--- a/dcmect/libsrc/enhanced_ct.cc
+++ b/dcmect/libsrc/enhanced_ct.cc
@@ -25,10 +25,11 @@
 #include "dcmtk/dcmdata/dcfilefo.h"
 #include "dcmtk/dcmdata/dcpixel.h"
 #include "dcmtk/dcmect/types.h"
 #include "dcmtk/dcmfg/concatenationcreator.h"
 #include "dcmtk/dcmfg/concatenationloader.h"
+#include "dcmtk/dcmfg/fgtypes.h"
 #include "dcmtk/dcmiod/iodutil.h"
 #include "dcmtk/dcmiod/modimagepixel.h"
 
 struct EctEnhancedCT::SetImagePixelModuleVisitor
 {
@@ -101,12 +102,23 @@ struct EctEnhancedCT::WriteVisitor
         Uint16 rows = 0;
         Uint16 cols = 0;
         m_CT.getRows(rows);
         m_CT.getColumns(cols);
         const size_t numFrames      = m_CT.m_Frames.size();
+        if (numFrames > 2147483647)
+        {
+            DCMECT_ERROR("More than 2147483647 frames provided");
+            return FG_EC_PixelDataTooLarge;
+        }
+        const size_t numPixelsFrame = OFstatic_cast(size_t, rows) * OFstatic_cast(size_t, cols);
         const size_t numBytesFrame  = m_CT.m_Frames[0]->length;
-        const size_t numPixelsFrame = rows * cols;
+        if (numBytesFrame != numPixelsFrame * 2)
+        {
+            DCMECT_ERROR("Invalid number of bytes per frame: Expected " << numPixelsFrame * 2 << " but got "
+              << numBytesFrame << " frame pixel data");
+            return ECT_InvalidPixelInfo;
+        }
         // Creates the correct pixel data element, based on the image pixel module used.
         DcmPixelData* pixData = new DcmPixelData(DCM_PixelData);
         OFCondition result;
         if (pixData)
         {
diff --git a/dcmect/tests/CMakeLists.txt b/dcmect/tests/CMakeLists.txt
index 5d66b1145..032553414 100644
--- a/dcmect/tests/CMakeLists.txt
+++ b/dcmect/tests/CMakeLists.txt
@@ -1,9 +1,10 @@
 # declare executables
 DCMTK_ADD_EXECUTABLE(dcmect_tests
   tests.cc
   t_huge_concat.cc
+  t_overflow.cc
   t_roundtrip.cc
 )
 
 # make sure executables are linked to the corresponding libraries
 DCMTK_TARGET_LINK_MODULES(dcmect_tests dcmect dcmfg dcmdata oflog ofstd)
diff --git a/dcmect/tests/Makefile.dep b/dcmect/tests/Makefile.dep
index d1f92d2ce..ffa29f5b3 100644
--- a/dcmect/tests/Makefile.dep
+++ b/dcmect/tests/Makefile.dep
@@ -152,10 +152,161 @@ t_huge_concat.o: t_huge_concat.cc \
  ../../dcmfg/include/dcmtk/dcmfg/fgpixeltransform.h \
  ../../dcmfg/include/dcmtk/dcmfg/fgpixmsr.h \
  ../../dcmfg/include/dcmtk/dcmfg/fgplanor.h \
  ../../dcmfg/include/dcmtk/dcmfg/fgplanpo.h \
  ../../dcmfg/include/dcmtk/dcmfg/fgtemporalposition.h
+t_overflow.o: t_overflow.cc ../../config/include/dcmtk/config/osconfig.h \
+ ../include/dcmtk/dcmect/enhanced_ct.h ../include/dcmtk/dcmect/def.h \
+ ../../ofstd/include/dcmtk/ofstd/ofexport.h \
+ ../include/dcmtk/dcmect/types.h ../../oflog/include/dcmtk/oflog/oflog.h \
+ ../../oflog/include/dcmtk/oflog/logger.h \
+ ../../oflog/include/dcmtk/oflog/config.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdefine.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcast.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstdinc.h \
+ ../../oflog/include/dcmtk/oflog/config/defines.h \
+ ../../oflog/include/dcmtk/oflog/helpers/threadcf.h \
+ ../../oflog/include/dcmtk/oflog/loglevel.h \
+ ../../ofstd/include/dcmtk/ofstd/ofvector.h \
+ ../../ofstd/include/dcmtk/ofstd/oftypes.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstream.h \
+ ../../oflog/include/dcmtk/oflog/tstring.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstring.h \
+ ../../oflog/include/dcmtk/oflog/tchar.h \
+ ../../oflog/include/dcmtk/oflog/spi/apndatch.h \
+ ../../oflog/include/dcmtk/oflog/appender.h \
+ ../../ofstd/include/dcmtk/ofstd/ofmem.h \
+ ../../ofstd/include/dcmtk/ofstd/ofutil.h \
+ ../../ofstd/include/dcmtk/ofstd/oftraits.h \
+ ../../ofstd/include/dcmtk/ofstd/variadic/tuplefwd.h \
+ ../../oflog/include/dcmtk/oflog/layout.h \
+ ../../oflog/include/dcmtk/oflog/streams.h \
+ ../../oflog/include/dcmtk/oflog/helpers/pointer.h \
+ ../../oflog/include/dcmtk/oflog/thread/syncprim.h \
+ ../../oflog/include/dcmtk/oflog/spi/filter.h \
+ ../../oflog/include/dcmtk/oflog/helpers/lockfile.h \
+ ../../oflog/include/dcmtk/oflog/spi/logfact.h \
+ ../../oflog/include/dcmtk/oflog/logmacro.h \
+ ../../oflog/include/dcmtk/oflog/helpers/snprintf.h \
+ ../../oflog/include/dcmtk/oflog/tracelog.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcond.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdiag.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/push.def \
+ ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \
+ ../../ofstd/include/dcmtk/ofstd/diag/pop.def \
+ ../../dcmfg/include/dcmtk/dcmfg/fginterface.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fg.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgbase.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcitem.h \
+ ../../ofstd/include/dcmtk/ofstd/offile.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstd.h \
+ ../../ofstd/include/dcmtk/ofstd/oflist.h \
+ ../../ofstd/include/dcmtk/ofstd/oflimits.h \
+ ../../config/include/dcmtk/config/arith.h \
+ ../../ofstd/include/dcmtk/ofstd/oferror.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dctypes.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcdefine.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcobject.h \
+ ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
+ ../../ofstd/include/dcmtk/ofstd/ofthread.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcerror.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcxfer.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvr.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dctag.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dctagkey.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/ignrattr.def \
+ ../../dcmdata/include/dcmtk/dcmdata/dcstack.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dclist.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcpcache.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgtypes.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgdefine.h \
+ ../../ofstd/include/dcmtk/ofstd/ofmap.h \
+ ../../dcmiod/include/dcmtk/dcmiod/iodimage.h \
+ ../../dcmiod/include/dcmtk/dcmiod/iodcommn.h \
+ ../../dcmiod/include/dcmtk/dcmiod/iodrules.h \
+ ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
+ ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modcommoninstanceref.h \
+ ../../dcmiod/include/dcmtk/dcmiod/iodmacro.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcdeftag.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrlo.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcchrstr.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcbytstr.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcelem.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvris.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrus.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrlt.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrcs.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrpn.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modbase.h \
+ ../../dcmiod/include/dcmtk/dcmiod/iodreferences.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modequipment.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modfor.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modgeneralseries.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modgeneralstudy.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modpatient.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modpatientstudy.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modsopcommon.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modgeneralimage.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modimagepixelvariant.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modimagepixelbase.h \
+ ../../ofstd/include/dcmtk/ofstd/ofvriant.h \
+ ../../ofstd/include/dcmtk/ofstd/variadic/variant.h \
+ ../../ofstd/include/dcmtk/ofstd/variadic/helpers.h \
+ ../../ofstd/include/dcmtk/ofstd/ofalign.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/cnvrsn.def \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsprfw.def \
+ ../../ofstd/include/dcmtk/ofstd/diag/arrybnds.def \
+ ../../ofstd/include/dcmtk/ofstd/diag/unrefprm.def \
+ ../../dcmiod/include/dcmtk/dcmiod/modacquisitioncontext.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modenhequipment.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modimagepixel.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modmultiframedimension.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modmultiframefg.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modsynchronisation.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrdt.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdatime.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdate.h \
+ ../../ofstd/include/dcmtk/ofstd/oftime.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrds.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrfd.h \
+ ../../ofstd/include/dcmtk/ofstd/oftempf.h \
+ ../../ofstd/include/dcmtk/ofstd/oftest.h \
+ ../../ofstd/include/dcmtk/ofstd/ofconapp.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcmdln.h \
+ ../../ofstd/include/dcmtk/ofstd/ofexbl.h \
+ ../../ofstd/include/dcmtk/ofstd/ofconsol.h \
+ ../../ofstd/include/dcmtk/ofstd/ofexit.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcuid.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcdict.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dchashdi.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcfilefo.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcsequen.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcdatset.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgctacquisitiondetails.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgctacquisitiontype.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgctadditionalxraysource.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrfl.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrsh.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgctexposure.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgctgeometry.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgctimageframetype.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgctposition.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgctreconstruction.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgcttabledynamics.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgctxraydetails.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgfracon.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrul.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgframeanatomy.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgirradiationeventid.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrui.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgpixeltransform.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgpixmsr.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgplanor.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgplanpo.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgrealworldvaluemapping.h \
+ ../../dcmiod/include/dcmtk/dcmiod/iodcontentitemmacro.h
 t_roundtrip.o: t_roundtrip.cc \
  ../../config/include/dcmtk/config/osconfig.h \
  ../../ofstd/include/dcmtk/ofstd/ofmem.h \
  ../../ofstd/include/dcmtk/ofstd/ofutil.h \
  ../../ofstd/include/dcmtk/ofstd/oftraits.h \
diff --git a/dcmect/tests/Makefile.in b/dcmect/tests/Makefile.in
index da1f74f11..7dda4351f 100644
--- a/dcmect/tests/Makefile.in
+++ b/dcmect/tests/Makefile.in
@@ -22,14 +22,14 @@ dcmfgdir = $(top_srcdir)/../dcmfg
 LIBDIRS = -L$(top_srcdir)/libsrc -L$(ofstddir)/libsrc -L$(oflogdir)/libsrc \
 	-L$(dcmdatadir)/libsrc -L$(dcmioddir)/libsrc -L$(dcmfgdir)/libsrc \
 	-L$(oficonvdir)/libsrc
 LOCALLIBS = -ldcmect -ldcmfg -ldcmiod -ldcmdata -loflog -lofstd -loficonv \
 	$(ZLIBLIBS) $(CHARCONVLIBS) $(MATHLIBS)
-LOCALINCLUDES = -I$(top_srcdir)/include -I$(ofstddir)/include -I$(oflogdir)/include \
+LOCALINCLUDES = -I$(top_srcdir)/include -I$(configdir)/include -I$(ofstddir)/include -I$(oflogdir)/include \
 	-I$(dcmdatadir)/include -I$(dcmioddir)/include -I$(dcmfgdir)/include
 
-test_objs = tests.o t_huge_concat.o t_roundtrip.o
+test_objs = tests.o t_huge_concat.o t_overflow.cc t_roundtrip.o
 objs = $(test_objs)
 progs = tests
 
 
 all: $(progs)
diff --git a/dcmect/tests/t_overflow.cc b/dcmect/tests/t_overflow.cc
new file mode 100644
index 000000000..fcc0e1abb
--- /dev/null
+++ b/dcmect/tests/t_overflow.cc
@@ -0,0 +1,362 @@
+/*
+ *
+ *  Copyright (C) 2024, OFFIS e.V.
+ *  All rights reserved.  See COPYRIGHT file for details.
+ *
+ *  This software and supporting documentation were developed by
+ *
+ *    OFFIS e.V.
+ *    R&D Division Health
+ *    Escherweg 2
+ *    D-26121 Oldenburg, Germany
+ *
+ *
+ *  Module:  dcmect
+ *
+ *  Author:  Daniel Berredo / Michael Onken
+ *
+ *  Purpose: Tests that check for pixel data overflow conditions
+ *
+ */
+
+
+#include <dcmtk/config/osconfig.h> /* make sure OS specific configuration is included first */
+
+#include <dcmtk/dcmect/enhanced_ct.h>
+
+#include <dcmtk/ofstd/oftempf.h>
+#include <dcmtk/ofstd/oftest.h>
+
+#include <dcmtk/dcmdata/dcdict.h>
+#include <dcmtk/dcmdata/dcfilefo.h>
+
+#include <dcmtk/dcmfg/fgctacquisitiondetails.h>
+#include <dcmtk/dcmfg/fgctacquisitiontype.h>
+#include <dcmtk/dcmfg/fgctadditionalxraysource.h>
+#include <dcmtk/dcmfg/fgctexposure.h>
+#include <dcmtk/dcmfg/fgctgeometry.h>
+#include <dcmtk/dcmfg/fgctimageframetype.h>
+#include <dcmtk/dcmfg/fgctposition.h>
+#include <dcmtk/dcmfg/fgctreconstruction.h>
+#include <dcmtk/dcmfg/fgcttabledynamics.h>
+#include <dcmtk/dcmfg/fgctxraydetails.h>
+#include <dcmtk/dcmfg/fgfracon.h>
+#include <dcmtk/dcmfg/fgframeanatomy.h>
+#include <dcmtk/dcmfg/fgirradiationeventid.h>
+#include <dcmtk/dcmfg/fgpixeltransform.h>
+#include <dcmtk/dcmfg/fgpixmsr.h>
+#include <dcmtk/dcmfg/fgplanor.h>
+#include <dcmtk/dcmfg/fgplanpo.h>
+#include <dcmtk/dcmfg/fgrealworldvaluemapping.h>
+
+static const Uint16 NUM_ROWS = 1024;
+static const Uint16 NUM_COLS = 1;
+static const Uint16 NUM_FRAMES = 2;
+static const size_t NUM_PIXELS_PER_FRAME = 1;
+
+static OFString EXPECTED_DUMP;
+
+static EctEnhancedCT *create();
+static void configureIOD(EctEnhancedCT *ct);
+static void setGenericValues(EctEnhancedCT *ct);
+static void addSharedFGs(EctEnhancedCT *ct);
+static void addFrames(EctEnhancedCT *ct);
+static void addDimensions(EctEnhancedCT *ct);
+
+
+OFTEST(dcmect_overflow)
+{
+    /* make sure data dictionary is loaded */
+    if (!dcmDataDict.isDictionaryLoaded())
+    {
+        OFCHECK(dcmDataDict.isDictionaryLoaded());
+    }
+
+    // Creation
+    EctEnhancedCT *ct = create();
+    configureIOD(ct);
+    setGenericValues(ct);
+    addSharedFGs(ct);
+    addFrames(ct);
+    addDimensions(ct);
+
+    // Write to dataset and compare its dump with expected result
+    DcmFileFormat dcmff;
+
+    OFTempFile tf(O_RDWR, "", "t_overflow", ".dcm");
+    OFCondition result;
+    result = ct->saveFile("output.dcm", EXS_LittleEndianExplicit);
+    OFCHECK_MSG(result == ECT_InvalidPixelInfo, result.text());
+}
+
+static EctEnhancedCT *create()
+{
+    IODEnhGeneralEquipmentModule::EquipmentInfo eq("Open Connections", "OC CT", "4711", "0.1");
+    EctEnhancedCT *ct = NULL;
+    OFCondition result;
+    result = EctEnhancedCT::create(ct,
+                                   NUM_ROWS,
+                                   NUM_COLS,
+                                   OFFalse,
+                                   EctTypes::E_ImageType1_Original,
+                                   EctTypes::DT_ImageType3_Volume,
+                                   EctTypes::DT_ImageType4_Maximum,
+                                   "1" /* instance number */,
+                                   EctTypes::E_ContQuali_Research,
+                                   EctTypes::E_PixelPres_Monochrome,
+                                   EctTypes::E_VolProps_Volume,
+                                   EctTypes::DT_VolBasedCalcTechnique_VolumeRender,
+                                   eq,
+                                   "20190801120000" /* acquisition date */,
+                                   2.0 /* acquisition duration */);
+
+    OFCHECK(result.good());
+    OFCHECK(ct != OFnullptr);
+    return ct;
+}
+
+static void configureIOD(EctEnhancedCT *ct)
+{
+    if (!ct)
+        return;
+}
+
+static void setGenericValues(EctEnhancedCT *ct)
+{
+    if (!ct)
+        return;
+    OFCHECK(ct->getPatient().setPatientName("Bond^James").good());
+    OFCHECK(ct->getPatient().setPatientID("007").good());
+    OFCHECK(ct->getPatient().setPatientBirthDate("19771007").good());
+    OFCHECK(ct->getStudy().setStudyDate("20190801").good());
+    OFCHECK(ct->getStudy().setStudyTime("120000").good());
+    OFCHECK(ct->getStudy().setStudyID("1").good());
+    OFCHECK(ct->getPatientStudy().setPatientAge("040Y").good());
+    OFCHECK(ct->getSeries().setSeriesDescription("Test Description").good());
+    OFCHECK(ct->getSeries().setSeriesNumber("1").good());
+    OFCHECK(ct->getSeries().setPatientPosition("HFS").good());
+
+    // Those values are usually computed automatically. UIDS are generated and date/times are set to current values.
+    // But in order to compare the "old" dump with the freshly created image attributes, we set some values manually,
+    // so that they are not overwritten with new, automatically created values later.
+    OFCHECK(ct->getStudy().setStudyInstanceUID("1.2.276.0.7230010.3.1.2.8323329.14863.1565940357.864811").good());
+    OFCHECK(ct->getFrameOfReference().setFrameOfReferenceUID("2.25.30853397773651184949181049330553108086").good());
+    OFCHECK(ct->getSeries().setSeriesInstanceUID("1.2.276.0.7230010.3.1.3.8323329.14863.1565940357.864812").good());
+    OFCHECK(ct->getSOPCommon().setSOPInstanceUID("1.2.276.0.7230010.3.1.4.8323329.14863.1565940357.864813").good());
+
+    OFCHECK(ct->getIODMultiFrameFGModule().setContentTime("092557").good());
+    OFCHECK(ct->getIODMultiFrameFGModule().setContentDate("20190816").good());
+}
+
+static void addSharedFGs(EctEnhancedCT *ct)
+{
+    if (!ct)
+        return;
+
+    FGPixelMeasures meas;
+    OFCHECK(meas.setPixelSpacing("0.1\\0.1").good());
+    OFCHECK(meas.setSliceThickness("1.0").good());
+    OFCHECK(meas.setSpacingBetweenSlices("0.05").good());
+
+    FGPlanePosPatient planpo;
+    OFCHECK(planpo.setImagePositionPatient("0.0", "0.0", "0.0").good());
+
+    FGPlaneOrientationPatient planor;
+    OFCHECK(planor.setImageOrientationPatient("1.0", "0.0", "0.0", "0.0", "1.0", "0.0").good());
+
+    FGFrameAnatomy ana;
+    OFCHECK(ana.setLaterality(FGFrameAnatomy::LATERALITY_BOTH).good());
+    OFCHECK(ana.getAnatomy().getAnatomicRegion().set("12738006", "SCT", "Brain").good());
+
+    FGIrradiationEventIdentification irr;
+    OFCHECK(irr.setIrradiationEventUID("2.25.30853892236613436472911970638347155062").good());
+
+    FGCTImageFrameType itype;
+    OFCHECK(itype.setFrameType("ORIGINAL\\PRIMARY\\VOLUME\\MAXIMUM").good());
+    OFCHECK(itype.setPixelPresentation(FGCTImageFrameType::E_PixelPres_Monochrome).good());
+    OFCHECK(itype.setVolumetricProperties(FGCTImageFrameType::E_VolProp_Volume).good());
+    OFCHECK(itype.setVolumeBasedCalculationTechnique(FGCTImageFrameType::DT_VolBasedCalcTechnique_VolumeRender).good());
+
+    FGCTAcquisitionType atype;
+    OFCHECK(atype.setAcquisitionType(FGCTAcquisitionType::DT_AcquisitionType_ConstantAngle).good());
+    OFCHECK(atype.setTubeAngle(0.1).good());
+    OFCHECK(atype.setConstantVolumeFlag(FGCTAcquisitionType::E_ConstVol_Yes).good());
+    OFCHECK(atype.setFluoroscopyFlag(FGCTAcquisitionType::E_Fluoroscopy_No).good());
+
+    FGCTAcquisitionDetails adetails;
+    FGCTAcquisitionDetails::FGCTAcquisitionDetailsItem *item = new FGCTAcquisitionDetails::FGCTAcquisitionDetailsItem();
+    OFCHECK(item->setRotationDirection(FGCTAcquisitionDetails::E_RotationDirection_CW).good());
+    OFCHECK(item->setRevolutionTime(5).good());
+    OFCHECK(item->setSingleCollimationWidth(1).good());
+    OFCHECK(item->setTotalCollimationWidth(10).good());
+    OFCHECK(item->setTableHeight(50).good());
+    OFCHECK(item->setGantryDetectorTilt(5).good());
+    OFCHECK(item->setDataCollectionDiameter(20).good());
+    adetails.getCTAcquisitionDetailsItems().push_back(item);
+
+    FGCTTableDynamics dyn;
+    FGCTTableDynamics::FGCTTableDynamicsItem *dyn_item = new FGCTTableDynamics::FGCTTableDynamicsItem;
+    OFCHECK(dyn_item);
+    if (dyn_item)
+    {
+        OFCHECK(dyn_item->setTableSpeed(1.0).good());
+        OFCHECK(dyn_item->setTableFeedPerRotation(0.1).good());
+        OFCHECK(dyn_item->setSpiralPitchFactor(0.2).good());
+        dyn.getCTTableDynamicsItems().push_back(dyn_item);
+    }
+
+    FGCTPosition pos;
+    OFCHECK(pos.setTablePosition(100.0).good());
+    OFCHECK(pos.setReconstructionTargetCenterPatient(OFVector<Float64>(3, 1.0)).good());
+    OFCHECK(pos.setDataCollectionCenterPatient(OFVector<Float64>(3, 2.0)).good());
+
+    FGCTGeometry geo;
+    FGCTGeometry::FGCTGeometryItem *geo_item = new FGCTGeometry::FGCTGeometryItem;
+    if (geo_item)
+    {
+        OFCHECK(geo_item->setDistanceSourceToDataCollectionCenter(5.0).good());
+        OFCHECK(geo_item->setDistanceSourceToDetector(0.5).good());
+        geo.getCTGeometryItems().push_back(geo_item);
+    }
+
+    FGCTReconstruction rec;
+    OFCHECK(rec.setConvolutionKernel("DUMMY").good());
+    OFCHECK(rec.setConvolutionKernelGroup("DUMMYGROUP").good());
+    OFCHECK(rec.setImageFilter("FILTER").good());
+    OFCHECK(rec.setReconstructionAlgorithm("ALGO").good());
+    OFCHECK(rec.setReconstructionAngle(90.0).good());
+    OFCHECK(rec.setReconstructionDiameter(100.0).good());
+    // Not permitted if Reconstruction Diameter is provided instead
+    // OFCHECK(rec.setReconstructionFieldOfView(100.0, 100.0).good());
+    OFCHECK(rec.setReconstructionPixelSpacing(0.1, 0.1).good());
+
+    FGCTExposure exp;
+    FGCTExposure::FGCTExposureItem *exp_item = new FGCTExposure::FGCTExposureItem;
+    if (exp_item)
+    {
+        OFCHECK(exp_item->setCTDIVol(0.1).good());
+        CodeSequenceMacro *phantom_item = new CodeSequenceMacro("113682", "DCM", "ACR Accreditation Phantom - CT");
+        exp_item->getCTDIPhantomTypeCodeSequence().push_back(phantom_item);
+        OFCHECK(exp_item->setExposureInMas(0.3).good());
+        OFCHECK(exp_item->setExposureModulationType("WEIRD").good());
+        OFCHECK(exp_item->setExposureTimeInMs(0.4).good());
+        OFCHECK(exp_item->setImageAndFluoroscopyAreaDoseProduct(0.5).good());
+        OFCHECK(exp_item->setWaterEquivalentDiameter(0.6).good());
+        CodeSequenceMacro *water_code = new CodeSequenceMacro("113987", "DCM", "AAPM 220");
+        exp_item->getWaterEquivalentDiameterCalculationMethodCodeSequence().push_back(water_code);
+        OFCHECK(exp_item->setXRayTubeCurrentInMa(0.7).good());
+        exp.getCTExposureItems().push_back(exp_item);
+    }
+
+    FGCTXRayDetails det;
+    FGCTXRayDetails::FGCTXRayDetailsItem *det_item = new FGCTXRayDetails::FGCTXRayDetailsItem;
+    if (det_item)
+    {
+        OFCHECK(det_item->setCalciumScoringMassFactorDevice(OFVector<Float32>(3, 1)).good());
+        OFCHECK(det_item->setCalciumScoringMassFactorPatient(2).good());
+        OFCHECK(det_item->setEnergyWeightingFactor(3).good());
+        OFCHECK(det_item->setFilterMaterial("FILTER_MATERIAL").good());
+        OFCHECK(det_item->setFilterType("FILTER_TYPE").good());
+        OFCHECK(det_item->setFocalSpots(OFVector<Float64>(4, 4.4)).good());
+        OFCHECK(det_item->setKVP(5.0).good());
+        det.getCTXRayDetailsItems().push_back(det_item);
+    }
+
+    FGPixelValueTransformation trans;
+    trans.setFGType(FGPixelValueTransformation::E_PixelValTrans_CT);
+    trans.setRescaleIntercept("0");
+    trans.setRescaleSlope("1");
+    trans.setRescaleType("HU");
+
+    FGCTAdditionalXRaySource asrc;
+    FGCTAdditionalXRaySource::FGCTAdditionalXRaySourceItem *asrc_item = new FGCTAdditionalXRaySource::FGCTAdditionalXRaySourceItem;
+    if (asrc_item)
+    {
+        OFCHECK(asrc_item->setDataCollectionDiameter(1.0).good());
+        OFCHECK(asrc_item->setEnergyWeightingFactor(2.0).good());
+        OFCHECK(asrc_item->setExposureInmAs(3.0).good());
+        OFCHECK(asrc_item->setFilterMaterial("FILTER_MATERIAL").good());
+        OFCHECK(asrc_item->setFilterType("FILTER_TYPE").good());
+        OFCHECK(asrc_item->setFocalSpots(OFVector<Float64>(4, 4.4)).good());
+        OFCHECK(asrc_item->setKVP(5).good());
+        OFCHECK(asrc_item->setXRayTubeCurrentInmA(6).good());
+        asrc.getCTAdditionalXRaySourceItems().push_back(asrc_item);
+    }
+
+    OFCHECK(ct->addForAllFrames(meas).good());
+    OFCHECK(ct->addForAllFrames(planpo).good());
+    OFCHECK(ct->addForAllFrames(planor).good());
+    OFCHECK(ct->addForAllFrames(ana).good());
+    OFCHECK(ct->addForAllFrames(irr).good());
+    OFCHECK(ct->addForAllFrames(itype).good());
+    OFCHECK(ct->addForAllFrames(atype).good());
+    OFCHECK(ct->addForAllFrames(adetails).good());
+    OFCHECK(ct->addForAllFrames(dyn).good());
+    OFCHECK(ct->addForAllFrames(pos).good());
+    OFCHECK(ct->addForAllFrames(geo).good());
+    OFCHECK(ct->addForAllFrames(rec).good());
+    OFCHECK(ct->addForAllFrames(exp).good());
+    OFCHECK(ct->addForAllFrames(det).good());
+    OFCHECK(ct->addForAllFrames(trans).good());
+    OFCHECK(ct->addForAllFrames(asrc).good());
+}
+
+static void addFrames(EctEnhancedCT *ct)
+{
+    if (!ct)
+        return;
+
+    FGFrameContent *fg = new FGFrameContent();
+    fg->setStackID("1");
+    OFCHECK(fg);
+    if (fg)
+    {
+        EctEnhancedCT::FramesType frames = ct->getFrames();
+        for (Uint16 frameNo = 1; frameNo <= NUM_FRAMES; frameNo++)
+        {
+            OFCHECK(fg->setFrameAcquisitionNumber(frameNo).good());
+            OFCHECK(fg->setFrameReferenceDateTime("20190816092557").good());
+            OFCHECK(fg->setFrameAcquisitionDateTime("20190816092557").good());
+            OFCHECK(fg->setFrameAcquisitionDuration(0.001).good());
+            OFCHECK(fg->setInStackPositionNumber(frameNo).good());
+            OFCHECK(fg->setDimensionIndexValues(1, 0).good());
+            OFCHECK(fg->setDimensionIndexValues(frameNo, 1).good());
+            OFVector<FGBase *> groups;
+            groups.push_back(fg);
+
+            Uint16 *data = new Uint16[NUM_PIXELS_PER_FRAME];
+            for (size_t i = 0; i < NUM_PIXELS_PER_FRAME; ++i)
+            {
+                data[i] = 0x4141;
+            }
+            OFCHECK(
+                OFget<EctEnhancedCT::Frames<Uint16>>(&frames)->addFrame(data, NUM_PIXELS_PER_FRAME, groups).good());
+            delete[] data;
+        }
+    }
+    delete fg;
+}
+
+static void addDimensions(EctEnhancedCT *ct)
+{
+    if (!ct)
+        return;
+    IODMultiframeDimensionModule &dims = ct->getDimensions();
+    OFCHECK(dims.addDimensionIndex(
+                    DCM_StackID, "2.25.30855560781715986879861690673941231222", DCM_FrameContentSequence, "STACK_DIM")
+                .good());
+    OFCHECK(dims.addDimensionIndex(DCM_InStackPositionNumber,
+                                   "2.25.30855560781715986879861690673941231222",
+                                   DCM_FrameContentSequence,
+                                   "STACK_DIM")
+                .good());
+    OFunique_ptr<IODMultiframeDimensionModule::DimensionOrganizationItem> org(
+        new IODMultiframeDimensionModule::DimensionOrganizationItem);
+    if (org)
+    {
+        org->setDimensionOrganizationUID("2.25.30855560781715986879861690673941231222");
+        dims.getDimensionOrganizationSequence().push_back(org.release());
+    }
+}
+
+
diff --git a/dcmect/tests/tests.cc b/dcmect/tests/tests.cc
index 54a6ca021..8639dc1ac 100644
--- a/dcmect/tests/tests.cc
+++ b/dcmect/tests/tests.cc
@@ -1,8 +1,8 @@
 /*
  *
- *  Copyright (C) 2019, OFFIS e.V.
+ *  Copyright (C) 2019-2024, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
  *
  *    OFFIS e.V.
@@ -21,7 +21,8 @@
 
 #include "dcmtk/config/osconfig.h"
 #include "dcmtk/ofstd/oftest.h"
 
 OFTEST_REGISTER(dcmect_huge_concat);
+OFTEST_REGISTER(dcmect_overflow);
 OFTEST_REGISTER(dcmect_roundtrip);
 OFTEST_MAIN("dcmect")

Vulnerable code:         const size_t numPixelsFrame = rows * cols;
LOCALINCLUDES = -I$(top_srcdir)/include -I$(ofstddir)/include -I$(oflogdir)/include \
test_objs = tests.o t_huge_concat.o t_roundtrip.o
 *  Copyright (C) 2019, OFFIS e.V.
Fixed code: #include "dcmtk/dcmfg/fgtypes.h"
        if (numFrames > 2147483647)
        {
            DCMECT_ERROR("More than 2147483647 frames provided");
            return FG_EC_PixelDataTooLarge;
        }
        const size_t numPixelsFrame = OFstatic_cast(size_t, rows) * OFstatic_cast(size_t, cols);
        if (numBytesFrame != numPixelsFrame * 2)
        {
            DCMECT_ERROR("Invalid number of bytes per frame: Expected " << numPixelsFrame * 2 << " but got "
              << numBytesFrame << " frame pixel data");
            return ECT_InvalidPixelInfo;
        }
  t_overflow.cc
t_overflow.o: t_overflow.cc ../../config/include/dcmtk/config/osconfig.h \
 ../include/dcmtk/dcmect/enhanced_ct.h ../include/dcmtk/dcmect/def.h \
 ../../ofstd/include/dcmtk/ofstd/ofexport.h \
 ../include/dcmtk/dcmect/types.h ../../oflog/include/dcmtk/oflog/oflog.h \
 ../../oflog/include/dcmtk/oflog/logger.h \
 ../../oflog/include/dcmtk/oflog/config.h \
 ../../ofstd/include/dcmtk/ofstd/ofdefine.h \
 ../../ofstd/include/dcmtk/ofstd/ofcast.h \
 ../../ofstd/include/dcmtk/ofstd/ofstdinc.h \
 ../../oflog/include/dcmtk/oflog/config/defines.h \
 ../../oflog/include/dcmtk/oflog/helpers/threadcf.h \
 ../../oflog/include/dcmtk/oflog/loglevel.h \
 ../../ofstd/include/dcmtk/ofstd/ofvector.h \
 ../../ofstd/include/dcmtk/ofstd/oftypes.h \
 ../../ofstd/include/dcmtk/ofstd/ofstream.h \
 ../../oflog/include/dcmtk/oflog/tstring.h \
 ../../ofstd/include/dcmtk/ofstd/ofstring.h \
 ../../oflog/include/dcmtk/oflog/tchar.h \
 ../../oflog/include/dcmtk/oflog/spi/apndatch.h \
 ../../oflog/include/dcmtk/oflog/appender.h \
 ../../ofstd/include/dcmtk/ofstd/ofmem.h \
 ../../ofstd/include/dcmtk/ofstd/ofutil.h \
 ../../ofstd/include/dcmtk/ofstd/oftraits.h \
 ../../ofstd/include/dcmtk/ofstd/variadic/tuplefwd.h \
 ../../oflog/include/dcmtk/oflog/layout.h \
 ../../oflog/include/dcmtk/oflog/streams.h \
 ../../oflog/include/dcmtk/oflog/helpers/pointer.h \
 ../../oflog/include/dcmtk/oflog/thread/syncprim.h \
 ../../oflog/include/dcmtk/oflog/spi/filter.h \
 ../../oflog/include/dcmtk/oflog/helpers/lockfile.h \
 ../../oflog/include/dcmtk/oflog/spi/logfact.h \
 ../../oflog/include/dcmtk/oflog/logmacro.h \
 ../../oflog/include/dcmtk/oflog/helpers/snprintf.h \
 ../../oflog/include/dcmtk/oflog/tracelog.h \
 ../../ofstd/include/dcmtk/ofstd/ofcond.h \
 ../../ofstd/include/dcmtk/ofstd/ofdiag.h \
 ../../ofstd/include/dcmtk/ofstd/diag/push.def \
 ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \
 ../../ofstd/include/dcmtk/ofstd/diag/pop.def \
 ../../dcmfg/include/dcmtk/dcmfg/fginterface.h \
 ../../dcmfg/include/dcmtk/dcmfg/fg.h \
 ../../dcmfg/include/dcmtk/dcmfg/fgbase.h \
 ../../dcmdata/include/dcmtk/dcmdata/dcitem.h \
 ../../ofstd/include/dcmtk/ofstd/offile.h \
 ../../ofstd/include/dcmtk/ofstd/ofstd.h \
 ../../ofstd/include/dcmtk/ofstd/oflist.h \
 ../../ofstd/include/dcmtk/ofstd/oflimits.h \
 ../../config/include/dcmtk/config/arith.h \
 ../../ofstd/include/dcmtk/ofstd/oferror.h \
 ../../dcmdata/include/dcmtk/dcmdata/dctypes.h \
 ../../dcmdata/include/dcmtk/dcmdata/dcdefine.h \
 ../../dcmdata/include/dcmtk/dcmdata/dcobject.h \
 ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
 ../../ofstd/include/dcmtk/ofstd/ofthread.h \
 ../../dcmdata/include/dcmtk/dcmdata/dcerror.h \
 ../../dcmdata/include/dcmtk/dcmdata/dcxfer.h \
 ../../dcmdata/include/dcmtk/dcmdata/dcvr.h \
 ../../dcmdata/include/dcmtk/dcmdata/dctag.h \
 ../../dcmdata/include/dcmtk/dcmdata/dctagkey.h \
 ../../ofstd/include/dcmtk/ofstd/diag/ignrattr.def \
 ../../dcmdata/include/dcmtk/dcmdata/dcstack.h \
 ../../dcmdata/include/dcmtk/dcmdata/dclist.h \
 ../../dcmdata/include/dcmtk/dcmdata/dcpcache.h \
 ../../dcmfg/include/dcmtk/dcmfg/fgtypes.h \
 ../../dcmfg/include/dcmtk/dcmfg/fgdefine.h \
 ../../ofstd/include/dcmtk/ofstd/ofmap.h \
 ../../dcmiod/include/dcmtk/dcmiod/iodimage.h \
 ../../dcmiod/include/dcmtk/dcmiod/iodcommn.h \
 ../../dcmiod/include/dcmtk/dcmiod/iodrules.h \
 ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
 ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
 ../../dcmiod/include/dcmtk/dcmiod/modcommoninstanceref.h \
 ../../dcmiod/include/dcmtk/dcmiod/iodmacro.h \
 ../../dcmdata/include/dcmtk/dcmdata/dcdeftag.h \
 ../../dcmdata/include/dcmtk/dcmdata/dcvrlo.h \
 ../../dcmdata/include/dcmtk/dcmdata/dcchrstr.h \
 ../../dcmdata/include/dcmtk/dcmdata/dcbytstr.h \
 ../../dcmdata/include/dcmtk/dcmdata/dcelem.h \
 ../../dcmdata/include/dcmtk/dcmdata/dcvris.h \
 ../../dcmdata/include/dcmtk/dcmdata/dcvrus.h \
 ../../dcmdata/include/dcmtk/dcmdata/dcvrlt.h \
 ../../dcmdata/include/dcmtk/dcmdata/dcvrcs.h \
 ../../dcmdata/include/dcmtk/dcmdata/dcvrpn.h \
 ../../dcmiod/include/dcmtk/dcmiod/modbase.h \
 ../../dcmiod/include/dcmtk/dcmiod/iodreferences.h \
 ../../dcmiod/include/dcmtk/dcmiod/modequipment.h \
 ../../dcmiod/include/dcmtk/dcmiod/modfor.h \
 ../../dcmiod/include/dcmtk/dcmiod/modgeneralseries.h \
 ../../dcmiod/include/dcmtk/dcmiod/modgeneralstudy.h \
 ../../dcmiod/include/dcmtk/dcmiod/modpatient.h \
 ../../dcmiod/include/dcmtk/dcmiod/modpatientstudy.h \
 ../../dcmiod/include/dcmtk/dcmiod/modsopcommon.h \
 ../../dcmiod/include/dcmtk/dcmiod/modgeneralimage.h \
 ../../dcmiod/include/dcmtk/dcmiod/modimagepixelvariant.h \
 ../../dcmiod/include/dcmtk/dcmiod/modimagepixelbase.h \
 ../../ofstd/include/dcmtk/ofstd/ofvriant.h \
 ../../ofstd/include/dcmtk/ofstd/variadic/variant.h \
 ../../ofstd/include/dcmtk/ofstd/variadic/helpers.h \
 ../../ofstd/include/dcmtk/ofstd/ofalign.h \
 ../../ofstd/include/dcmtk/ofstd/diag/cnvrsn.def \
 ../../ofstd/include/dcmtk/ofstd/diag/vsprfw.def \
 ../../ofstd/include/dcmtk/ofstd/diag/arrybnds.def \
 ../../ofstd/include/dcmtk/ofstd/diag/unrefprm.def \
 ../../dcmiod/include/dcmtk/dcmiod/modacquisitioncontext.h \
 ../../dcmiod/include/dcmtk/dcmiod/modenhequipment.h \
 ../../dcmiod/include/dcmtk/dcmiod/modimagepixel.h \
 ../../dcmiod/include/dcmtk/dcmiod/modmultiframedimension.h \
 ../../dcmiod/include/dcmtk/dcmiod/modmultiframefg.h \
 ../../dcmiod/include/dcmtk/dcmiod/modsynchronisation.h \
 ../../dcmdata/include/dcmtk/dcmdata/dcvrdt.h \
 ../../ofstd/include/dcmtk/ofstd/ofdatime.h \
 ../../ofstd/include/dcmtk/ofstd/ofdate.h \
 ../../ofstd/include/dcmtk/ofstd/oftime.h \
 ../../dcmdata/include/dcmtk/dcmdata/dcvrds.h \
 ../../dcmdata/include/dcmtk/dcmdata/dcvrfd.h \
 ../../ofstd/include/dcmtk/ofstd/oftempf.h \
 ../../ofstd/include/dcmtk/ofstd/oftest.h \
 ../../ofstd/include/dcmtk/ofstd/ofconapp.h \
 ../../ofstd/include/dcmtk/ofstd/ofcmdln.h \
 ../../ofstd/include/dcmtk/ofstd/ofexbl.h \
 ../../ofstd/include/dcmtk/ofstd/ofconsol.h \
 ../../ofstd/include/dcmtk/ofstd/ofexit.h \
 ../../dcmdata/include/dcmtk/dcmdata/dcuid.h \
 ../../dcmdata/include/dcmtk/dcmdata/dcdict.h \
 ../../dcmdata/include/dcmtk/dcmdata/dchashdi.h \
 ../../dcmdata/include/dcmtk/dcmdata/dcfilefo.h \
 ../../dcmdata/include/dcmtk/dcmdata/dcsequen.h \
 ../../dcmdata/include/dcmtk/dcmdata/dcdatset.h \
 ../../dcmfg/include/dcmtk/dcmfg/fgctacquisitiondetails.h \
 ../../dcmfg/include/dcmtk/dcmfg/fgctacquisitiontype.h \
 ../../dcmfg/include/dcmtk/dcmfg/fgctadditionalxraysource.h \
 ../../dcmdata/include/dcmtk/dcmdata/dcvrfl.h \
 ../../dcmdata/include/dcmtk/dcmdata/dcvrsh.h \
 ../../dcmfg/include/dcmtk/dcmfg/fgctexposure.h \
 ../../dcmfg/include/dcmtk/dcmfg/fgctgeometry.h \
 ../../dcmfg/include/dcmtk/dcmfg/fgctimageframetype.h \
 ../../dcmfg/include/dcmtk/dcmfg/fgctposition.h \
 ../../dcmfg/include/dcmtk/dcmfg/fgctreconstruction.h \
 ../../dcmfg/include/dcmtk/dcmfg/fgcttabledynamics.h \
 ../../dcmfg/include/dcmtk/dcmfg/fgctxraydetails.h \
 ../../dcmfg/include/dcmtk/dcmfg/fgfracon.h \
 ../../dcmdata/include/dcmtk/dcmdata/dcvrul.h \
 ../../dcmfg/include/dcmtk/dcmfg/fgframeanatomy.h \
 ../../dcmfg/include/dcmtk/dcmfg/fgirradiationeventid.h \
 ../../dcmdata/include/dcmtk/dcmdata/dcvrui.h \
 ../../dcmfg/include/dcmtk/dcmfg/fgpixeltransform.h \
 ../../dcmfg/include/dcmtk/dcmfg/fgpixmsr.h \
 ../../dcmfg/include/dcmtk/dcmfg/fgplanor.h \
 ../../dcmfg/include/dcmtk/dcmfg/fgplanpo.h \
 ../../dcmfg/include/dcmtk/dcmfg/fgrealworldvaluemapping.h \
 ../../dcmiod/include/dcmtk/dcmiod/iodcontentitemmacro.h
LOCALINCLUDES = -I$(top_srcdir)/include -I$(configdir)/include -I$(ofstddir)/include -I$(oflogdir)/include \
test_objs = tests.o t_huge_concat.o t_overflow.cc t_roundtrip.o
/*
 *
 *  Copyright (C) 2024, OFFIS e.V.
 *  All rights reserved.  See COPYRIGHT file for details.
 *
 *  This software and supporting documentation were developed by
 *
 *    OFFIS e.V.
 *    R&D Division Health
 *    Escherweg 2
 *    D-26121 Oldenburg, Germany
 *
 *
 *  Module:  dcmect
 *
 *  Author:  Daniel Berredo / Michael Onken
 *
 *  Purpose: Tests that check for pixel data overflow conditions
 *
 */


#include <dcmtk/config/osconfig.h> /* make sure OS specific configuration is included first */

#include <dcmtk/dcmect/enhanced_ct.h>

#include <dcmtk/ofstd/oftempf.h>
#include <dcmtk/ofstd/oftest.h>

#include <dcmtk/dcmdata/dcdict.h>
#include <dcmtk/dcmdata/dcfilefo.h>

#include <dcmtk/dcmfg/fgctacquisitiondetails.h>
#include <dcmtk/dcmfg/fgctacquisitiontype.h>
#include <dcmtk/dcmfg/fgctadditionalxraysource.h>
#include <dcmtk/dcmfg/fgctexposure.h>
#include <dcmtk/dcmfg/fgctgeometry.h>
#include <dcmtk/dcmfg/fgctimageframetype.h>
#include <dcmtk/dcmfg/fgctposition.h>
#include <dcmtk/dcmfg/fgctreconstruction.h>
#include <dcmtk/dcmfg/fgcttabledynamics.h>
#include <dcmtk/dcmfg/fgctxraydetails.h>
#include <dcmtk/dcmfg/fgfracon.h>
#include <dcmtk/dcmfg/fgframeanatomy.h>
#include <dcmtk/dcmfg/fgirradiationeventid.h>
#include <dcmtk/dcmfg/fgpixeltransform.h>
#include <dcmtk/dcmfg/fgpixmsr.h>
#include <dcmtk/dcmfg/fgplanor.h>
#include <dcmtk/dcmfg/fgplanpo.h>
#include <dcmtk/dcmfg/fgrealworldvaluemapping.h>

static const Uint16 NUM_ROWS = 1024;
static const Uint16 NUM_COLS = 1;
static const Uint16 NUM_FRAMES = 2;
static const size_t NUM_PIXELS_PER_FRAME = 1;

static OFString EXPECTED_DUMP;

static EctEnhancedCT *create();
static void configureIOD(EctEnhancedCT *ct);
static void setGenericValues(EctEnhancedCT *ct);
static void addSharedFGs(EctEnhancedCT *ct);
static void addFrames(EctEnhancedCT *ct);
static void addDimensions(EctEnhancedCT *ct);


OFTEST(dcmect_overflow)
{
    /* make sure data dictionary is loaded */
    if (!dcmDataDict.isDictionaryLoaded())
    {
        OFCHECK(dcmDataDict.isDictionaryLoaded());
    }

    // Creation
    EctEnhancedCT *ct = create();
    configureIOD(ct);
    setGenericValues(ct);
    addSharedFGs(ct);
    addFrames(ct);
    addDimensions(ct);

    // Write to dataset and compare its dump with expected result
    DcmFileFormat dcmff;

    OFTempFile tf(O_RDWR, "", "t_overflow", ".dcm");
    OFCondition result;
    result = ct->saveFile("output.dcm", EXS_LittleEndianExplicit);
    OFCHECK_MSG(result == ECT_InvalidPixelInfo, result.text());
}

static EctEnhancedCT *create()
{
    IODEnhGeneralEquipmentModule::EquipmentInfo eq("Open Connections", "OC CT", "4711", "0.1");
    EctEnhancedCT *ct = NULL;
    OFCondition result;
    result = EctEnhancedCT::create(ct,
                                   NUM_ROWS,
                                   NUM_COLS,
                                   OFFalse,
                                   EctTypes::E_ImageType1_Original,
                                   EctTypes::DT_ImageType3_Volume,
                                   EctTypes::DT_ImageType4_Maximum,
                                   "1" /* instance number */,
                                   EctTypes::E_ContQuali_Research,
                                   EctTypes::E_PixelPres_Monochrome,
                                   EctTypes::E_VolProps_Volume,
                                   EctTypes::DT_VolBasedCalcTechnique_VolumeRender,
                                   eq,
                                   "20190801120000" /* acquisition date */,
                                   2.0 /* acquisition duration */);

    OFCHECK(result.good());
    OFCHECK(ct != OFnullptr);
    return ct;
}

static void configureIOD(EctEnhancedCT *ct)
{
    if (!ct)
        return;
}

static void setGenericValues(EctEnhancedCT *ct)
{
    if (!ct)
        return;
    OFCHECK(ct->getPatient().setPatientName("Bond^James").good());
    OFCHECK(ct->getPatient().setPatientID("007").good());
    OFCHECK(ct->getPatient().setPatientBirthDate("19771007").good());
    OFCHECK(ct->getStudy().setStudyDate("20190801").good());
    OFCHECK(ct->getStudy().setStudyTime("120000").good());
    OFCHECK(ct->getStudy().setStudyID("1").good());
    OFCHECK(ct->getPatientStudy().setPatientAge("040Y").good());
    OFCHECK(ct->getSeries().setSeriesDescription("Test Description").good());
    OFCHECK(ct->getSeries().setSeriesNumber("1").good());
    OFCHECK(ct->getSeries().setPatientPosition("HFS").good());

    // Those values are usually computed automatically. UIDS are generated and date/times are set to current values.
    // But in order to compare the "old" dump with the freshly created image attributes, we set some values manually,
    // so that they are not overwritten with new, automatically created values later.
    OFCHECK(ct->getStudy().setStudyInstanceUID("1.2.276.0.7230010.3.1.2.8323329.14863.1565940357.864811").good());
    OFCHECK(ct->getFrameOfReference().setFrameOfReferenceUID("2.25.30853397773651184949181049330553108086").good());
    OFCHECK(ct->getSeries().setSeriesInstanceUID("1.2.276.0.7230010.3.1.3.8323329.14863.1565940357.864812").good());
    OFCHECK(ct->getSOPCommon().setSOPInstanceUID("1.2.276.0.7230010.3.1.4.8323329.14863.1565940357.864813").good());

    OFCHECK(ct->getIODMultiFrameFGModule().setContentTime("092557").good());
    OFCHECK(ct->getIODMultiFrameFGModule().setContentDate("20190816").good());
}

static void addSharedFGs(EctEnhancedCT *ct)
{
    if (!ct)
        return;

    FGPixelMeasures meas;
    OFCHECK(meas.setPixelSpacing("0.1\\0.1").good());
    OFCHECK(meas.setSliceThickness("1.0").good());
    OFCHECK(meas.setSpacingBetweenSlices("0.05").good());

    FGPlanePosPatient planpo;
    OFCHECK(planpo.setImagePositionPatient("0.0", "0.0", "0.0").good());

    FGPlaneOrientationPatient planor;
    OFCHECK(planor.setImageOrientationPatient("1.0", "0.0", "0.0", "0.0", "1.0", "0.0").good());

    FGFrameAnatomy ana;
    OFCHECK(ana.setLaterality(FGFrameAnatomy::LATERALITY_BOTH).good());
    OFCHECK(ana.getAnatomy().getAnatomicRegion().set("12738006", "SCT", "Brain").good());

    FGIrradiationEventIdentification irr;
    OFCHECK(irr.setIrradiationEventUID("2.25.30853892236613436472911970638347155062").good());

    FGCTImageFrameType itype;
    OFCHECK(itype.setFrameType("ORIGINAL\\PRIMARY\\VOLUME\\MAXIMUM").good());
    OFCHECK(itype.setPixelPresentation(FGCTImageFrameType::E_PixelPres_Monochrome).good());
    OFCHECK(itype.setVolumetricProperties(FGCTImageFrameType::E_VolProp_Volume).good());
    OFCHECK(itype.setVolumeBasedCalculationTechnique(FGCTImageFrameType::DT_VolBasedCalcTechnique_VolumeRender).good());

    FGCTAcquisitionType atype;
    OFCHECK(atype.setAcquisitionType(FGCTAcquisitionType::DT_AcquisitionType_ConstantAngle).good());
    OFCHECK(atype.setTubeAngle(0.1).good());
    OFCHECK(atype.setConstantVolumeFlag(FGCTAcquisitionType::E_ConstVol_Yes).good());
    OFCHECK(atype.setFluoroscopyFlag(FGCTAcquisitionType::E_Fluoroscopy_No).good());

    FGCTAcquisitionDetails adetails;
    FGCTAcquisitionDetails::FGCTAcquisitionDetailsItem *item = new FGCTAcquisitionDetails::FGCTAcquisitionDetailsItem();
    OFCHECK(item->setRotationDirection(FGCTAcquisitionDetails::E_RotationDirection_CW).good());
    OFCHECK(item->setRevolutionTime(5).good());
    OFCHECK(item->setSingleCollimationWidth(1).good());
    OFCHECK(item->setTotalCollimationWidth(10).good());
    OFCHECK(item->setTableHeight(50).good());
    OFCHECK(item->setGantryDetectorTilt(5).good());
    OFCHECK(item->setDataCollectionDiameter(20).good());
    adetails.getCTAcquisitionDetailsItems().push_back(item);

    FGCTTableDynamics dyn;
    FGCTTableDynamics::FGCTTableDynamicsItem *dyn_item = new FGCTTableDynamics::FGCTTableDynamicsItem;
    OFCHECK(dyn_item);
    if (dyn_item)
    {
        OFCHECK(dyn_item->setTableSpeed(1.0).good());
        OFCHECK(dyn_item->setTableFeedPerRotation(0.1).good());
        OFCHECK(dyn_item->setSpiralPitchFactor(0.2).good());
        dyn.getCTTableDynamicsItems().push_back(dyn_item);
    }

    FGCTPosition pos;
    OFCHECK(pos.setTablePosition(100.0).good());
    OFCHECK(pos.setReconstructionTargetCenterPatient(OFVector<Float64>(3, 1.0)).good());
    OFCHECK(pos.setDataCollectionCenterPatient(OFVector<Float64>(3, 2.0)).good());

    FGCTGeometry geo;
    FGCTGeometry::FGCTGeometryItem *geo_item = new FGCTGeometry::FGCTGeometryItem;
    if (geo_item)
    {
        OFCHECK(geo_item->setDistanceSourceToDataCollectionCenter(5.0).good());
        OFCHECK(geo_item->setDistanceSourceToDetector(0.5).good());
        geo.getCTGeometryItems().push_back(geo_item);
    }

    FGCTReconstruction rec;
    OFCHECK(rec.setConvolutionKernel("DUMMY").good());
    OFCHECK(rec.setConvolutionKernelGroup("DUMMYGROUP").good());
    OFCHECK(rec.setImageFilter("FILTER").good());
    OFCHECK(rec.setReconstructionAlgorithm("ALGO").good());
    OFCHECK(rec.setReconstructionAngle(90.0).good());
    OFCHECK(rec.setReconstructionDiameter(100.0).good());
    // Not permitted if Reconstruction Diameter is provided instead
    // OFCHECK(rec.setReconstructionFieldOfView(100.0, 100.0).good());
    OFCHECK(rec.setReconstructionPixelSpacing(0.1, 0.1).good());

    FGCTExposure exp;
    FGCTExposure::FGCTExposureItem *exp_item = new FGCTExposure::FGCTExposureItem;
    if (exp_item)
    {
        OFCHECK(exp_item->setCTDIVol(0.1).good());
        CodeSequenceMacro *phantom_item = new CodeSequenceMacro("113682", "DCM", "ACR Accreditation Phantom - CT");
        exp_item->getCTDIPhantomTypeCodeSequence().push_back(phantom_item);
        OFCHECK(exp_item->setExposureInMas(0.3).good());
        OFCHECK(exp_item->setExposureModulationType("WEIRD").good());
        OFCHECK(exp_item->setExposureTimeInMs(0.4).good());
        OFCHECK(exp_item->setImageAndFluoroscopyAreaDoseProduct(0.5).good());
        OFCHECK(exp_item->setWaterEquivalentDiameter(0.6).good());
        CodeSequenceMacro *water_code = new CodeSequenceMacro("113987", "DCM", "AAPM 220");
        exp_item->getWaterEquivalentDiameterCalculationMethodCodeSequence().push_back(water_code);
        OFCHECK(exp_item->setXRayTubeCurrentInMa(0.7).good());
        exp.getCTExposureItems().push_back(exp_item);
    }

    FGCTXRayDetails det;
    FGCTXRayDetails::FGCTXRayDetailsItem *det_item = new FGCTXRayDetails::FGCTXRayDetailsItem;
    if (det_item)
    {
        OFCHECK(det_item->setCalciumScoringMassFactorDevice(OFVector<Float32>(3, 1)).good());
        OFCHECK(det_item->setCalciumScoringMassFactorPatient(2).good());
        OFCHECK(det_item->setEnergyWeightingFactor(3).good());
        OFCHECK(det_item->setFilterMaterial("FILTER_MATERIAL").good());
        OFCHECK(det_item->setFilterType("FILTER_TYPE").good());
        OFCHECK(det_item->setFocalSpots(OFVector<Float64>(4, 4.4)).good());
        OFCHECK(det_item->setKVP(5.0).good());
        det.getCTXRayDetailsItems().push_back(det_item);
    }

    FGPixelValueTransformation trans;
    trans.setFGType(FGPixelValueTransformation::E_PixelValTrans_CT);
    trans.setRescaleIntercept("0");
    trans.setRescaleSlope("1");
    trans.setRescaleType("HU");

    FGCTAdditionalXRaySource asrc;
    FGCTAdditionalXRaySource::FGCTAdditionalXRaySourceItem *asrc_item = new FGCTAdditionalXRaySource::FGCTAdditionalXRaySourceItem;
    if (asrc_item)
    {
        OFCHECK(asrc_item->setDataCollectionDiameter(1.0).good());
        OFCHECK(asrc_item->setEnergyWeightingFactor(2.0).good());
        OFCHECK(asrc_item->setExposureInmAs(3.0).good());
        OFCHECK(asrc_item->setFilterMaterial("FILTER_MATERIAL").good());
        OFCHECK(asrc_item->setFilterType("FILTER_TYPE").good());
        OFCHECK(asrc_item->setFocalSpots(OFVector<Float64>(4, 4.4)).good());
        OFCHECK(asrc_item->setKVP(5).good());
        OFCHECK(asrc_item->setXRayTubeCurrentInmA(6).good());
        asrc.getCTAdditionalXRaySourceItems().push_back(asrc_item);
    }

    OFCHECK(ct->addForAllFrames(meas).good());
    OFCHECK(ct->addForAllFrames(planpo).good());
    OFCHECK(ct->addForAllFrames(planor).good());
    OFCHECK(ct->addForAllFrames(ana).good());
    OFCHECK(ct->addForAllFrames(irr).good());
    OFCHECK(ct->addForAllFrames(itype).good());
    OFCHECK(ct->addForAllFrames(atype).good());
    OFCHECK(ct->addForAllFrames(adetails).good());
    OFCHECK(ct->addForAllFrames(dyn).good());
    OFCHECK(ct->addForAllFrames(pos).good());
    OFCHECK(ct->addForAllFrames(geo).good());
    OFCHECK(ct->addForAllFrames(rec).good());
    OFCHECK(ct->addForAllFrames(exp).good());
    OFCHECK(ct->addForAllFrames(det).good());
    OFCHECK(ct->addForAllFrames(trans).good());
    OFCHECK(ct->addForAllFrames(asrc).good());
}

static void addFrames(EctEnhancedCT *ct)
{
    if (!ct)
        return;

    FGFrameContent *fg = new FGFrameContent();
    fg->setStackID("1");
    OFCHECK(fg);
    if (fg)
    {
        EctEnhancedCT::FramesType frames = ct->getFrames();
        for (Uint16 frameNo = 1; frameNo <= NUM_FRAMES; frameNo++)
        {
            OFCHECK(fg->setFrameAcquisitionNumber(frameNo).good());
            OFCHECK(fg->setFrameReferenceDateTime("20190816092557").good());
            OFCHECK(fg->setFrameAcquisitionDateTime("20190816092557").good());
            OFCHECK(fg->setFrameAcquisitionDuration(0.001).good());
            OFCHECK(fg->setInStackPositionNumber(frameNo).good());
            OFCHECK(fg->setDimensionIndexValues(1, 0).good());
            OFCHECK(fg->setDimensionIndexValues(frameNo, 1).good());
            OFVector<FGBase *> groups;
            groups.push_back(fg);

            Uint16 *data = new Uint16[NUM_PIXELS_PER_FRAME];
            for (size_t i = 0; i < NUM_PIXELS_PER_FRAME; ++i)
            {
                data[i] = 0x4141;
            }
            OFCHECK(
                OFget<EctEnhancedCT::Frames<Uint16>>(&frames)->addFrame(data, NUM_PIXELS_PER_FRAME, groups).good());
            delete[] data;
        }
    }
    delete fg;
}

static void addDimensions(EctEnhancedCT *ct)
{
    if (!ct)
        return;
    IODMultiframeDimensionModule &dims = ct->getDimensions();
    OFCHECK(dims.addDimensionIndex(
                    DCM_StackID, "2.25.30855560781715986879861690673941231222", DCM_FrameContentSequence, "STACK_DIM")
                .good());
    OFCHECK(dims.addDimensionIndex(DCM_InStackPositionNumber,
                                   "2.25.30855560781715986879861690673941231222",
                                   DCM_FrameContentSequence,
                                   "STACK_DIM")
                .good());
    OFunique_ptr<IODMultiframeDimensionModule::DimensionOrganizationItem> org(
        new IODMultiframeDimensionModule::DimensionOrganizationItem);
    if (org)
    {
        org->setDimensionOrganizationUID("2.25.30855560781715986879861690673941231222");
        dims.getDimensionOrganizationSequence().push_back(org.release());
    }
}


 *  Copyright (C) 2019-2024, OFFIS e.V.
OFTEST_REGISTER(dcmect_overflow);