diff --git a/include/utils/errors.h b/include/utils/errors.h index 6e2511638..fc40138dc 100644 --- a/include/utils/errors.h +++ b/include/utils/errors.h @@ -26,6 +26,11 @@ #define ERRORS_H #include +#include +#include +#include +#include +#include enum class ReturnValue { SuccessCode = 0, @@ -66,4 +71,34 @@ struct base_error : public std::exception { } }; +inline uint32_t toBoundedTokenCount(uint64_t count) { + if (count > std::numeric_limits::max()) { + throw base_error("Number of tokens exceeded ", std::numeric_limits::max()); + } + return static_cast(count); +} + +inline int32_t parse_bounded_int32(std::string_view text) { + if (text.empty()) { + throw base_error("Expected an integer constant, got \"\""); + } + + int32_t value = 0; + const char* const first = text.data(); + const char* const last = first + text.size(); + const std::from_chars_result result = std::from_chars(first, last, value); + if (result.ec == std::errc::invalid_argument || result.ptr == first || result.ptr != last) { + throw base_error("Expected an integer constant, got \"", text, "\""); + } + if (result.ec == std::errc::result_out_of_range) { + if (text.front() == '-') { + throw base_error("Integer constant ", text, " is less than ", + std::numeric_limits::min()); + } + throw base_error("Integer constant ", text, " exceeded ", + std::numeric_limits::max()); + } + return value; +} + #endif /* ERRORS_H */ diff --git a/src/PetriEngine/Colored/Multiset.cpp b/src/PetriEngine/Colored/Multiset.cpp index 23dbbc19c..060becf1d 100644 --- a/src/PetriEngine/Colored/Multiset.cpp +++ b/src/PetriEngine/Colored/Multiset.cpp @@ -30,7 +30,7 @@ namespace PetriEngine { : _set(), _type(nullptr) { for (auto& c : colors) { - (*this)[c.first] += c.second; + (*this)[c.first] = toBoundedTokenCount(static_cast((*this)[c.first]) + c.second); } } @@ -65,7 +65,7 @@ namespace PetriEngine { const Color* color = &(*ColorType::dotInstance()->begin()); if (_type != nullptr) color = &((*_type)[c.first]); - (*this)[color] += c.second; + (*this)[color] = toBoundedTokenCount(static_cast((*this)[color]) + c.second); } } @@ -86,7 +86,7 @@ namespace PetriEngine { void Multiset::operator *=(uint32_t scalar) { for (auto& c : _set) { - c.second *= scalar; + c.second = toBoundedTokenCount(static_cast(c.second) * scalar); } } diff --git a/src/PetriEngine/PQL/PQLQueryParser.y b/src/PetriEngine/PQL/PQLQueryParser.y index 1cb0b17fa..20a026180 100644 --- a/src/PetriEngine/PQL/PQLQueryParser.y +++ b/src/PetriEngine/PQL/PQLQueryParser.y @@ -140,7 +140,10 @@ term : term MULTIPLY factor { $$ = new MultiplyExpr(std::vector({Expr_ ; factor : LPAREN expr RPAREN { $$ = $2; } - | INT { $$ = new LiteralExpr(atol($1->c_str())); delete $1; } + | INT { + std::unique_ptr token($1); + $$ = new LiteralExpr(parse_bounded_int32(*token)); + } | named { $$ = $1; } ; diff --git a/src/PetriParse/PNMLParser.cpp b/src/PetriParse/PNMLParser.cpp index 4e8a6749a..482e7ad07 100644 --- a/src/PetriParse/PNMLParser.cpp +++ b/src/PetriParse/PNMLParser.cpp @@ -1005,7 +1005,7 @@ void PNMLParser::parseValue(rapidxml::xml_node<>* element, std::string& text) { uint32_t PNMLParser::parseNumberConstant(rapidxml::xml_node<>* element) { if (strcmp(element->name(), "numberconstant") == 0) { auto value = element->first_attribute("value")->value(); - return (uint32_t)atoll(value); + return toBoundedTokenCount(static_cast(atoll(value))); } else if (strcmp(element->name(), "subterm") == 0) { return parseNumberConstant(element->first_node()); } diff --git a/src/PetriParse/QueryXMLParser.cpp b/src/PetriParse/QueryXMLParser.cpp index 813d3e3b8..9bdca72c2 100644 --- a/src/PetriParse/QueryXMLParser.cpp +++ b/src/PetriParse/QueryXMLParser.cpp @@ -466,13 +466,7 @@ Condition_ptr QueryXMLParser::parseBooleanFormula(rapidxml::xml_node<>* element Expr_ptr QueryXMLParser::parseIntegerExpression(rapidxml::xml_node<>* element) { std::string elementName = element->name(); if (elementName == "integer-constant") { - int i; - if (sscanf(element->value(), "%d", &i) == EOF) - { - assert(false); - return nullptr; - } - return std::make_shared(i); + return std::make_shared(parse_bounded_int32(element->value())); } else if (elementName == "tokens-count") { auto children = element->first_node(); std::vector ids;