Skip to content

Commit 9610182

Browse files
Improve integer array type safety and error handling
Enhances type safety and error handling for integer array deserialization by using std::clamp and type checks for signed and unsigned types. Improves overflow and underflow detection, and ensures correct value assignment for constant, range, and lattice arrays. Also fixes a minor type issue in AbstractHdfProxy and corrects a namespace closure in AbstractValuesProperty.
1 parent 70c7fa9 commit 9610182

4 files changed

Lines changed: 78 additions & 16 deletions

File tree

src/common/AbstractObject.cpp

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1063,8 +1063,15 @@ namespace {
10631063
T nullValue = (std::numeric_limits<T>::max)();
10641064
if (arrayInput->soap_type() == SOAP_TYPE_gsoap_resqml2_0_1_resqml20__IntegerHdf5Array) {
10651065
auto const* hdfArray = static_cast<gsoap_resqml2_0_1::resqml20__IntegerHdf5Array const*>(arrayInput);
1066-
if (hdfArray->NullValue > (std::numeric_limits<T>::min)() && hdfArray->NullValue < (std::numeric_limits<T>::max)()) {
1067-
nullValue = static_cast<T>(hdfArray->NullValue);
1066+
if constexpr (std::is_signed_v<T>) {
1067+
nullValue = static_cast<T>(std::clamp(hdfArray->NullValue,
1068+
static_cast<int64_t>((std::numeric_limits<T>::min)()), static_cast<int64_t>((std::numeric_limits<T>::max)())));
1069+
}
1070+
else {
1071+
if (hdfArray->NullValue > 0) {
1072+
nullValue = static_cast<T>(std::clamp(static_cast<uint64_t>(hdfArray->NullValue),
1073+
static_cast<uint64_t>(0), static_cast<uint64_t>((std::numeric_limits<T>::max)())));
1074+
}
10681075
}
10691076
dataset = hdfArray->Values;
10701077
pathInHdfFile = hdfArray->Values->PathInHdfFile;
@@ -1086,9 +1093,16 @@ namespace {
10861093
T nullValue = (std::numeric_limits<T>::max)();
10871094
if (arrayInput->soap_type() == SOAP_TYPE_gsoap_eml2_3_eml23__IntegerExternalArray) {
10881095
externalDataArrayParts = static_cast<gsoap_eml2_3::eml23__IntegerExternalArray const*>(arrayInput)->Values->ExternalDataArrayPart;
1089-
auto xmlNullValue = static_cast<gsoap_eml2_3::eml23__IntegerExternalArray const*>(arrayInput)->NullValue;
1090-
if (xmlNullValue > (std::numeric_limits<T>::min)() && xmlNullValue < (std::numeric_limits<T>::max)()) {
1091-
nullValue = static_cast<T>(xmlNullValue);
1096+
const int64_t xmlNullValue = static_cast<gsoap_eml2_3::eml23__IntegerExternalArray const*>(arrayInput)->NullValue;
1097+
if constexpr (std::is_signed_v<T>) {
1098+
nullValue = static_cast<T>(std::clamp(xmlNullValue,
1099+
static_cast<int64_t>((std::numeric_limits<T>::min)()), static_cast<int64_t>((std::numeric_limits<T>::max)())));
1100+
}
1101+
else {
1102+
if (xmlNullValue > 0) {
1103+
nullValue = static_cast<T>(std::clamp(static_cast<uint64_t>(xmlNullValue),
1104+
static_cast<uint64_t>(0), static_cast<uint64_t>((std::numeric_limits<T>::max)())));
1105+
}
10921106
}
10931107
}
10941108
else if (arrayInput->soap_type() == SOAP_TYPE_gsoap_eml2_3_eml23__BooleanExternalArray) {

src/common/AbstractObject.h

Lines changed: 57 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -819,8 +819,18 @@ namespace COMMON_NS
819819
case SOAP_TYPE_gsoap_resqml2_0_1_resqml20__IntegerRangeArray:
820820
{
821821
gsoap_resqml2_0_1::resqml20__IntegerRangeArray const* rangeArray = static_cast<gsoap_resqml2_0_1::resqml20__IntegerRangeArray const *>(arrayInput);
822-
if (rangeArray->Value + rangeArray->Count > (std::numeric_limits<T>::max)()) {
823-
throw std::range_error("The range integer values are superior to maximum value of read datatype.");
822+
if constexpr (std::is_signed_v<T>) {
823+
if (rangeArray->Value < (std::numeric_limits<T>::min)()) {
824+
throw std::overflow_error("Too low integers in XML for the C++ chosen datatype");
825+
}
826+
}
827+
else {
828+
if (rangeArray->Value < 0 ) {
829+
throw std::underflow_error("Cannot deal with negative values when using unsigned integer");
830+
}
831+
}
832+
if (rangeArray->Value + rangeArray->Count > static_cast<uint64_t>((std::numeric_limits<T>::max)())) {
833+
throw std::overflow_error("The range integer values are superior to maximum value of read datatype.");
824834
}
825835
for (T i = 0; i < static_cast<T>(rangeArray->Count); ++i) {
826836
arrayOutput[i] = i + static_cast<T>(rangeArray->Value);
@@ -830,10 +840,17 @@ namespace COMMON_NS
830840
case SOAP_TYPE_gsoap_resqml2_0_1_resqml20__IntegerConstantArray:
831841
{
832842
gsoap_resqml2_0_1::resqml20__IntegerConstantArray const* constantArray = static_cast<gsoap_resqml2_0_1::resqml20__IntegerConstantArray const*>(arrayInput);
833-
if (sizeof(constantArray->Value) > sizeof(T) && constantArray->Value > (std::numeric_limits<T>::max)()) {
834-
throw std::range_error("The constant integer value is superior to maximum value of read datatype.");
843+
T value;
844+
if constexpr (std::is_signed_v<T>) {
845+
value = static_cast<T>(std::clamp(constantArray->Value,
846+
static_cast<int64_t>((std::numeric_limits<T>::min)()), static_cast<int64_t>((std::numeric_limits<T>::max)())));
835847
}
836-
std::fill(arrayOutput, arrayOutput + constantArray->Count, static_cast<T>(constantArray->Value));
848+
else {
849+
value = constantArray->Value > 0
850+
? static_cast<T>(std::clamp(static_cast<uint64_t>(constantArray->Value), static_cast<uint64_t>(0), static_cast<uint64_t>((std::numeric_limits<T>::max)())))
851+
: (std::numeric_limits<T>::max)();
852+
}
853+
std::fill(arrayOutput, arrayOutput + constantArray->Count, value);
837854
return (std::numeric_limits<T>::max)();
838855
}
839856
case SOAP_TYPE_gsoap_resqml2_0_1_resqml20__BooleanConstantArray:
@@ -848,8 +865,26 @@ namespace COMMON_NS
848865
if (latticeArray->Offset.size() > 1) {
849866
throw std::invalid_argument("The integer lattice array contains more than one offset.");
850867
}
851-
for (size_t i = 0; i <= latticeArray->Offset[0]->Count; ++i) {
852-
arrayOutput[i] = latticeArray->StartValue + (i * latticeArray->Offset[0]->Value);
868+
if constexpr (std::is_signed_v<T>) {
869+
if (latticeArray->StartValue < (std::numeric_limits<T>::min)() || latticeArray->Offset[0]->Value < (std::numeric_limits<T>::min)()) {
870+
throw std::underflow_error("Too low integers in XML for the C++ chosen datatype");
871+
}
872+
if (latticeArray->StartValue > (std::numeric_limits<T>::max)() ||
873+
latticeArray->Offset[0]->Value > (std::numeric_limits<T>::max)()) {
874+
throw std::overflow_error("Too big integers in XML for the C++ chosen datatype");
875+
}
876+
}
877+
else {
878+
if (latticeArray->StartValue < 0 || latticeArray->Offset[0]->Value < 0) {
879+
throw std::underflow_error("Cannot deal with negative values when using unsigned integer");
880+
}
881+
if (static_cast<uint64_t>(latticeArray->StartValue) > (std::numeric_limits<T>::max)() ||
882+
static_cast<uint64_t>(latticeArray->Offset[0]->Value) > (std::numeric_limits<T>::max)()) {
883+
throw std::overflow_error("Too big integers in XML for the C++ chosen datatype");
884+
}
885+
}
886+
for (uint64_t i = 0; i <= latticeArray->Offset[0]->Count; ++i) {
887+
arrayOutput[i] = static_cast<T>(latticeArray->StartValue) + (i * static_cast<T>(latticeArray->Offset[0]->Value));
853888
}
854889
return (std::numeric_limits<T>::max)();
855890
}
@@ -864,8 +899,21 @@ namespace COMMON_NS
864899
case SOAP_TYPE_gsoap_eml2_3_eml23__IntegerConstantArray:
865900
{
866901
gsoap_eml2_3::eml23__IntegerConstantArray const* constantArray = static_cast<gsoap_eml2_3::eml23__IntegerConstantArray const*>(arrayInput);
867-
if (sizeof(constantArray->Value) > sizeof(T) && constantArray->Value > (std::numeric_limits<T>::max)()) {
868-
throw std::range_error("The constant integer value is superior to maximum value of read datatype.");
902+
if constexpr (std::is_signed_v<T>) {
903+
if (constantArray->Value < (std::numeric_limits<T>::min)()) {
904+
throw std::underflow_error("Too low integers in XML for the C++ chosen datatype");
905+
}
906+
if (constantArray->Value > (std::numeric_limits<T>::max)()) {
907+
throw std::overflow_error("Too big integers in XML for the C++ chosen datatype");
908+
}
909+
}
910+
else {
911+
if (constantArray->Value < 0) {
912+
throw std::underflow_error("Cannot deal with negative values when using unsigned integer");
913+
}
914+
if (static_cast<uint64_t>(constantArray->Value) > (std::numeric_limits<T>::max)()) {
915+
throw std::overflow_error("Too big integers in XML for the C++ chosen datatype");
916+
}
869917
}
870918
std::fill(arrayOutput, arrayOutput + constantArray->Count, static_cast<T>(constantArray->Value));
871919
return (std::numeric_limits<T>::max)();

src/eml2/AbstractHdfProxy.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,5 +38,5 @@ void AbstractHdfProxy::initGsoapProxy(COMMON_NS::DataObjectRepository * repo, co
3838
uint64_t AbstractHdfProxy::getElementCount(const std::string & datasetName)
3939
{
4040
auto elementCountPerDim = getElementCountPerDimension(datasetName);
41-
return std::accumulate(elementCountPerDim.begin(), elementCountPerDim.end(), 1, std::multiplies<uint64_t>());
41+
return std::accumulate(elementCountPerDim.begin(), elementCountPerDim.end(), 1, std::multiplies<decltype(elementCountPerDim)::value_type>());
4242
}

src/resqml2/AbstractValuesProperty.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1133,7 +1133,7 @@ namespace {
11331133
}
11341134
return xmlStats;
11351135
}
1136-
};
1136+
}
11371137

11381138
gsoap_eml2_3::eml23__IntegerArrayStatistics* AbstractValuesProperty::createIntegerArrayStatisticsFrom(const COMMON_NS::NumberArrayStatistics<int8_t>& stats, size_t index) {
11391139
return template_createIntegerArrayStatisticsFrom(gsoapProxy2_3->soap, stats, index);

0 commit comments

Comments
 (0)