From 9430f5891435b6683ada9fefe18e828aa48169a1 Mon Sep 17 00:00:00 2001
From: firewave <firewave@users.noreply.github.com>
Date: Thu, 16 Mar 2023 23:17:05 +0100
Subject: [PATCH] fixed #13488 - provide error location of `MathLib::to*()`

---
 lib/checkcondition.cpp     | 28 ++++++++---------
 lib/checkfunctions.cpp     |  2 +-
 lib/checkleakautovar.cpp   |  2 +-
 lib/checkother.cpp         |  2 +-
 lib/checkstring.cpp        |  2 +-
 lib/checkuninitvar.cpp     |  4 +--
 lib/library.cpp            | 14 ++++-----
 lib/mathlib.cpp            | 62 ++++++++++++++++++++++++--------------
 lib/mathlib.h              | 14 +++++++--
 lib/programmemory.cpp      |  2 +-
 lib/symboldatabase.cpp     |  6 ++--
 lib/templatesimplifier.cpp | 10 +++---
 lib/tokenize.cpp           | 20 ++++++------
 lib/valueflow.cpp          |  8 ++---
 lib/vf_common.cpp          |  6 ++--
 oss-fuzz/Makefile          |  2 +-
 test/cli/other_test.py     | 23 ++++++++++++++
 test/testmathlib.cpp       | 37 ++++++++++++++++++++++-
 18 files changed, 163 insertions(+), 81 deletions(-)

diff --git a/lib/checkcondition.cpp b/lib/checkcondition.cpp
index 45202ec1b448..4f5d3a6ff1e4 100644
--- a/lib/checkcondition.cpp
+++ b/lib/checkcondition.cpp
@@ -107,7 +107,7 @@ void CheckCondition::assignIf()
 
             if (Token::Match(tok->next(), "%num% [&|]")) {
                 bitop = tok->strAt(2).at(0);
-                num = MathLib::toBigNumber(tok->strAt(1));
+                num = MathLib::toBigNumber(tok->tokAt(1));
             } else {
                 const Token *endToken = Token::findsimplematch(tok, ";");
 
@@ -117,7 +117,7 @@ void CheckCondition::assignIf()
 
                 if (endToken && Token::Match(endToken->tokAt(-2), "[&|] %num% ;")) {
                     bitop = endToken->strAt(-2).at(0);
-                    num = MathLib::toBigNumber(endToken->strAt(-1));
+                    num = MathLib::toBigNumber(endToken->tokAt(-1));
                 }
             }
 
@@ -170,7 +170,7 @@ bool CheckCondition::assignIfParseScope(const Token * const assignTok,
 
     for (const Token *tok2 = startTok; tok2; tok2 = tok2->next()) {
         if ((bitop == '&') && Token::Match(tok2->tokAt(2), "%varid% %cop% %num% ;", varid) && tok2->strAt(3) == std::string(1U, bitop)) {
-            const MathLib::bigint num2 = MathLib::toBigNumber(tok2->strAt(4));
+            const MathLib::bigint num2 = MathLib::toBigNumber(tok2->tokAt(4));
             if (0 == (num & num2))
                 mismatchingBitAndError(assignTok, num, tok2, num2);
         }
@@ -178,7 +178,7 @@ bool CheckCondition::assignIfParseScope(const Token * const assignTok,
             return true;
         }
         if (bitop == '&' && Token::Match(tok2, "%varid% &= %num% ;", varid)) {
-            const MathLib::bigint num2 = MathLib::toBigNumber(tok2->strAt(2));
+            const MathLib::bigint num2 = MathLib::toBigNumber(tok2->tokAt(2));
             if (0 == (num & num2))
                 mismatchingBitAndError(assignTok, num, tok2, num2);
         }
@@ -213,7 +213,7 @@ bool CheckCondition::assignIfParseScope(const Token * const assignTok,
                 }
                 if (Token::Match(tok2,"&&|%oror%|( %varid% ==|!= %num% &&|%oror%|)", varid)) {
                     const Token *vartok = tok2->next();
-                    const MathLib::bigint num2 = MathLib::toBigNumber(vartok->strAt(2));
+                    const MathLib::bigint num2 = MathLib::toBigNumber(vartok->tokAt(2));
                     if ((num & num2) != ((bitop=='&') ? num2 : num)) {
                         const std::string& op(vartok->strAt(1));
                         const bool alwaysTrue = op == "!=";
@@ -267,11 +267,11 @@ void CheckCondition::mismatchingBitAndError(const Token *tok1, const MathLib::bi
 static void getnumchildren(const Token *tok, std::list<MathLib::bigint> &numchildren)
 {
     if (tok->astOperand1() && tok->astOperand1()->isNumber())
-        numchildren.push_back(MathLib::toBigNumber(tok->astOperand1()->str()));
+        numchildren.push_back(MathLib::toBigNumber(tok->astOperand1()));
     else if (tok->astOperand1() && tok->str() == tok->astOperand1()->str())
         getnumchildren(tok->astOperand1(), numchildren);
     if (tok->astOperand2() && tok->astOperand2()->isNumber())
-        numchildren.push_back(MathLib::toBigNumber(tok->astOperand2()->str()));
+        numchildren.push_back(MathLib::toBigNumber(tok->astOperand2()));
     else if (tok->astOperand2() && tok->str() == tok->astOperand2()->str())
         getnumchildren(tok->astOperand2(), numchildren);
 }
@@ -464,8 +464,8 @@ bool CheckCondition::isOverlappingCond(const Token * const cond1, const Token *
         if (!isSameExpression(true, expr1, expr2, *mSettings, pure, false))
             return false;
 
-        const MathLib::bigint value1 = MathLib::toBigNumber(num1->str());
-        const MathLib::bigint value2 = MathLib::toBigNumber(num2->str());
+        const MathLib::bigint value1 = MathLib::toBigNumber(num1);
+        const MathLib::bigint value2 = MathLib::toBigNumber(num2);
         if (cond2->str() == "&")
             return ((value1 & value2) == value2);
         return ((value1 & value2) > 0);
@@ -1267,14 +1267,14 @@ void CheckCondition::checkIncorrectLogicOperator()
             if (isfloat && (op1 == "==" || op1 == "!=" || op2 == "==" || op2 == "!="))
                 continue;
 
-
+            // the expr are not the token of the value but they provide better context
             const double d1 = (isfloat) ? MathLib::toDoubleNumber(value1) : 0;
             const double d2 = (isfloat) ? MathLib::toDoubleNumber(value2) : 0;
-            const MathLib::bigint i1 = (isfloat) ? 0 : MathLib::toBigNumber(value1);
-            const MathLib::bigint i2 = (isfloat) ? 0 : MathLib::toBigNumber(value2);
+            const MathLib::bigint i1 = (isfloat) ? 0 : MathLib::toBigNumber(value1, expr1);
+            const MathLib::bigint i2 = (isfloat) ? 0 : MathLib::toBigNumber(value2, expr2);
             const bool useUnsignedInt = (std::numeric_limits<MathLib::bigint>::max()==i1) || (std::numeric_limits<MathLib::bigint>::max()==i2);
-            const MathLib::biguint u1 = (useUnsignedInt) ? MathLib::toBigUNumber(value1) : 0;
-            const MathLib::biguint u2 = (useUnsignedInt) ? MathLib::toBigUNumber(value2) : 0;
+            const MathLib::biguint u1 = (useUnsignedInt) ? MathLib::toBigUNumber(value1, expr1) : 0;
+            const MathLib::biguint u2 = (useUnsignedInt) ? MathLib::toBigUNumber(value2, expr2) : 0;
             // evaluate if expression is always true/false
             bool alwaysTrue = true, alwaysFalse = true;
             bool firstTrue = true, secondTrue = true;
diff --git a/lib/checkfunctions.cpp b/lib/checkfunctions.cpp
index 607d083aaa2c..49abcc505958 100644
--- a/lib/checkfunctions.cpp
+++ b/lib/checkfunctions.cpp
@@ -582,7 +582,7 @@ void CheckFunctions::memsetInvalid2ndParam()
             }
 
             if (printWarning && secondParamTok->isNumber()) { // Check if the second parameter is a literal and is out of range
-                const MathLib::bigint value = MathLib::toBigNumber(secondParamTok->str());
+                const MathLib::bigint value = MathLib::toBigNumber(secondParamTok);
                 const long long sCharMin = mSettings->platform.signedCharMin();
                 const long long uCharMax = mSettings->platform.unsignedCharMax();
                 if (value < sCharMin || value > uCharMax)
diff --git a/lib/checkleakautovar.cpp b/lib/checkleakautovar.cpp
index bdc92a8f6ed9..b621b2558c01 100644
--- a/lib/checkleakautovar.cpp
+++ b/lib/checkleakautovar.cpp
@@ -474,7 +474,7 @@ bool CheckLeakAutoVar::checkScope(const Token * const startToken,
 
             // Assigning non-zero value variable. It might be used to
             // track the execution for a later if condition.
-            if (Token::Match(varTok->tokAt(2), "%num% ;") && MathLib::toBigNumber(varTok->strAt(2)) != 0)
+            if (Token::Match(varTok->tokAt(2), "%num% ;") && MathLib::toBigNumber(varTok->tokAt(2)) != 0)
                 notzero.insert(varTok->varId());
             else if (Token::Match(varTok->tokAt(2), "- %type% ;") && varTok->tokAt(3)->isUpperCaseName())
                 notzero.insert(varTok->varId());
diff --git a/lib/checkother.cpp b/lib/checkother.cpp
index 73c9f03e7e2e..f71ecbb7e8d4 100644
--- a/lib/checkother.cpp
+++ b/lib/checkother.cpp
@@ -3216,7 +3216,7 @@ void CheckOther::checkIncompleteArrayFill()
                 if (!var || !var->isArray() || var->dimensions().empty() || !var->dimension(0))
                     continue;
 
-                if (MathLib::toBigNumber(tok->linkAt(1)->strAt(-1)) == var->dimension(0)) {
+                if (MathLib::toBigNumber(tok->linkAt(1)->tokAt(-1)) == var->dimension(0)) {
                     int size = mTokenizer->sizeOfType(var->typeStartToken());
                     if (size == 0 && var->valueType()->pointer)
                         size = mSettings->platform.sizeof_pointer;
diff --git a/lib/checkstring.cpp b/lib/checkstring.cpp
index 462f053446a8..1d145f30cbbd 100644
--- a/lib/checkstring.cpp
+++ b/lib/checkstring.cpp
@@ -294,7 +294,7 @@ void CheckString::checkIncorrectStringCompare()
                 tok = tok->linkAt(1);
 
             if (Token::simpleMatch(tok, ". substr (") && Token::Match(tok->tokAt(3)->nextArgument(), "%num% )")) {
-                const MathLib::biguint clen = MathLib::toBigUNumber(tok->linkAt(2)->strAt(-1));
+                const MathLib::biguint clen = MathLib::toBigUNumber(tok->linkAt(2)->tokAt(-1));
                 const Token* begin = tok->previous();
                 for (;;) { // Find start of statement
                     while (begin->link() && Token::Match(begin, "]|)|>"))
diff --git a/lib/checkuninitvar.cpp b/lib/checkuninitvar.cpp
index 3fe012470bf2..541a46c071fc 100644
--- a/lib/checkuninitvar.cpp
+++ b/lib/checkuninitvar.cpp
@@ -332,9 +332,9 @@ static void conditionAlwaysTrueOrFalse(const Token *tok, const std::map<nonneg i
             return;
 
         if (tok->str() == "==")
-            *alwaysTrue  = (it->second == MathLib::toBigNumber(numtok->str()));
+            *alwaysTrue  = (it->second == MathLib::toBigNumber(numtok));
         else if (tok->str() == "!=")
-            *alwaysTrue  = (it->second != MathLib::toBigNumber(numtok->str()));
+            *alwaysTrue  = (it->second != MathLib::toBigNumber(numtok));
         else
             return;
         *alwaysFalse = !(*alwaysTrue);
diff --git a/lib/library.cpp b/lib/library.cpp
index 8c7f6e335ba0..6872553c791d 100644
--- a/lib/library.cpp
+++ b/lib/library.cpp
@@ -1059,13 +1059,13 @@ bool Library::isIntArgValid(const Token *ftok, int argnr, const MathLib::bigint
     TokenList tokenList(nullptr);
     gettokenlistfromvalid(ac->valid, ftok->isCpp(), tokenList);
     for (const Token *tok = tokenList.front(); tok; tok = tok->next()) {
-        if (tok->isNumber() && argvalue == MathLib::toBigNumber(tok->str()))
+        if (tok->isNumber() && argvalue == MathLib::toBigNumber(tok))
             return true;
-        if (Token::Match(tok, "%num% : %num%") && argvalue >= MathLib::toBigNumber(tok->str()) && argvalue <= MathLib::toBigNumber(tok->strAt(2)))
+        if (Token::Match(tok, "%num% : %num%") && argvalue >= MathLib::toBigNumber(tok) && argvalue <= MathLib::toBigNumber(tok->tokAt(2)))
             return true;
-        if (Token::Match(tok, "%num% : ,") && argvalue >= MathLib::toBigNumber(tok->str()))
+        if (Token::Match(tok, "%num% : ,") && argvalue >= MathLib::toBigNumber(tok))
             return true;
-        if ((!tok->previous() || tok->strAt(-1) == ",") && Token::Match(tok,": %num%") && argvalue <= MathLib::toBigNumber(tok->strAt(1)))
+        if ((!tok->previous() || tok->strAt(-1) == ",") && Token::Match(tok,": %num%") && argvalue <= MathLib::toBigNumber(tok->tokAt(1)))
             return true;
     }
     return false;
@@ -1079,11 +1079,11 @@ bool Library::isFloatArgValid(const Token *ftok, int argnr, double argvalue) con
     TokenList tokenList(nullptr);
     gettokenlistfromvalid(ac->valid, ftok->isCpp(), tokenList);
     for (const Token *tok = tokenList.front(); tok; tok = tok->next()) {
-        if (Token::Match(tok, "%num% : %num%") && argvalue >= MathLib::toDoubleNumber(tok->str()) && argvalue <= MathLib::toDoubleNumber(tok->strAt(2)))
+        if (Token::Match(tok, "%num% : %num%") && argvalue >= MathLib::toDoubleNumber(tok) && argvalue <= MathLib::toDoubleNumber(tok->tokAt(2)))
             return true;
-        if (Token::Match(tok, "%num% : ,") && argvalue >= MathLib::toDoubleNumber(tok->str()))
+        if (Token::Match(tok, "%num% : ,") && argvalue >= MathLib::toDoubleNumber(tok))
             return true;
-        if ((!tok->previous() || tok->strAt(-1) == ",") && Token::Match(tok,": %num%") && argvalue <= MathLib::toDoubleNumber(tok->strAt(1)))
+        if ((!tok->previous() || tok->strAt(-1) == ",") && Token::Match(tok,": %num%") && argvalue <= MathLib::toDoubleNumber(tok->tokAt(1)))
             return true;
         if (Token::Match(tok, "%num%") && MathLib::isFloat(tok->str()) && MathLib::isEqual(tok->str(), MathLib::toString(argvalue)))
             return true;
diff --git a/lib/mathlib.cpp b/lib/mathlib.cpp
index 75378d9006e2..a818681acbca 100644
--- a/lib/mathlib.cpp
+++ b/lib/mathlib.cpp
@@ -19,6 +19,7 @@
 
 #include "mathlib.h"
 #include "errortypes.h"
+#include "token.h"
 #include "utils.h"
 
 #include <cctype>
@@ -285,8 +286,13 @@ MathLib::value MathLib::value::shiftRight(const MathLib::value &v) const
     return ret;
 }
 
+MathLib::biguint MathLib::toBigUNumber(const Token * tok)
+{
+    return toBigUNumber(tok->str(), tok);
+}
+
 // TODO: remove handling of non-literal stuff
-MathLib::biguint MathLib::toBigUNumber(const std::string & str)
+MathLib::biguint MathLib::toBigUNumber(const std::string & str, const Token * const tok)
 {
     // hexadecimal numbers:
     if (isIntHex(str)) {
@@ -294,9 +300,9 @@ MathLib::biguint MathLib::toBigUNumber(const std::string & str)
             const biguint ret = std::stoull(str, nullptr, 16);
             return ret;
         } catch (const std::out_of_range& /*e*/) {
-            throw InternalError(nullptr, "Internal Error. MathLib::toBigUNumber: out_of_range: " + str);
+            throw InternalError(tok, "Internal Error. MathLib::toBigUNumber: out_of_range: " + str);
         } catch (const std::invalid_argument& /*e*/) {
-            throw InternalError(nullptr, "Internal Error. MathLib::toBigUNumber: invalid_argument: " + str);
+            throw InternalError(tok, "Internal Error. MathLib::toBigUNumber: invalid_argument: " + str);
         }
     }
 
@@ -306,9 +312,9 @@ MathLib::biguint MathLib::toBigUNumber(const std::string & str)
             const biguint ret = std::stoull(str, nullptr, 8);
             return ret;
         } catch (const std::out_of_range& /*e*/) {
-            throw InternalError(nullptr, "Internal Error. MathLib::toBigUNumber: out_of_range: " + str);
+            throw InternalError(tok, "Internal Error. MathLib::toBigUNumber: out_of_range: " + str);
         } catch (const std::invalid_argument& /*e*/) {
-            throw InternalError(nullptr, "Internal Error. MathLib::toBigUNumber: invalid_argument: " + str);
+            throw InternalError(tok, "Internal Error. MathLib::toBigUNumber: invalid_argument: " + str);
         }
     }
 
@@ -331,7 +337,7 @@ MathLib::biguint MathLib::toBigUNumber(const std::string & str)
         // Things are going to be less precise now: the value can't be represented in the biguint type.
         // Use min/max values as an approximation. See #5843
         // TODO: bail out when we are out of range?
-        const double doubleval = toDoubleNumber(str);
+        const double doubleval = toDoubleNumber(str, tok);
         if (doubleval > (double)std::numeric_limits<biguint>::max())
             return std::numeric_limits<biguint>::max();
         // cast to bigint to avoid UBSAN warning about negative double being out-of-range
@@ -347,13 +353,13 @@ MathLib::biguint MathLib::toBigUNumber(const std::string & str)
         if (idx != str.size()) {
             const std::string s = str.substr(idx);
             if (!isValidIntegerSuffix(s, true))
-                throw InternalError(nullptr, "Internal Error. MathLib::toBigUNumber: input was not completely consumed: " + str);
+                throw InternalError(tok, "Internal Error. MathLib::toBigUNumber: input was not completely consumed: " + str);
         }
         return ret;
     } catch (const std::out_of_range& /*e*/) {
-        throw InternalError(nullptr, "Internal Error. MathLib::toBigUNumber: out_of_range: " + str);
+        throw InternalError(tok, "Internal Error. MathLib::toBigUNumber: out_of_range: " + str);
     } catch (const std::invalid_argument& /*e*/) {
-        throw InternalError(nullptr, "Internal Error. MathLib::toBigUNumber: invalid_argument: " + str);
+        throw InternalError(tok, "Internal Error. MathLib::toBigUNumber: invalid_argument: " + str);
     }
 }
 
@@ -364,8 +370,13 @@ unsigned int MathLib::encodeMultiChar(const std::string& str)
     });
 }
 
+MathLib::bigint MathLib::toBigNumber(const Token * tok)
+{
+    return toBigNumber(tok->str(), tok);
+}
+
 // TODO: remove handling of non-literal stuff
-MathLib::bigint MathLib::toBigNumber(const std::string & str)
+MathLib::bigint MathLib::toBigNumber(const std::string & str, const Token * const tok)
 {
     // hexadecimal numbers:
     if (isIntHex(str)) {
@@ -373,9 +384,9 @@ MathLib::bigint MathLib::toBigNumber(const std::string & str)
             const biguint ret = std::stoull(str, nullptr, 16);
             return (bigint)ret;
         } catch (const std::out_of_range& /*e*/) {
-            throw InternalError(nullptr, "Internal Error. MathLib::toBigNumber: out_of_range: " + str);
+            throw InternalError(tok, "Internal Error. MathLib::toBigNumber: out_of_range: " + str);
         } catch (const std::invalid_argument& /*e*/) {
-            throw InternalError(nullptr, "Internal Error. MathLib::toBigNumber: invalid_argument: " + str);
+            throw InternalError(tok, "Internal Error. MathLib::toBigNumber: invalid_argument: " + str);
         }
     }
 
@@ -385,9 +396,9 @@ MathLib::bigint MathLib::toBigNumber(const std::string & str)
             const biguint ret = std::stoull(str, nullptr, 8);
             return ret;
         } catch (const std::out_of_range& /*e*/) {
-            throw InternalError(nullptr, "Internal Error. MathLib::toBigNumber: out_of_range: " + str);
+            throw InternalError(tok, "Internal Error. MathLib::toBigNumber: out_of_range: " + str);
         } catch (const std::invalid_argument& /*e*/) {
-            throw InternalError(nullptr, "Internal Error. MathLib::toBigNumber: invalid_argument: " + str);
+            throw InternalError(tok, "Internal Error. MathLib::toBigNumber: invalid_argument: " + str);
         }
     }
 
@@ -410,7 +421,7 @@ MathLib::bigint MathLib::toBigNumber(const std::string & str)
         // Things are going to be less precise now: the value can't be represented in the bigint type.
         // Use min/max values as an approximation. See #5843
         // TODO: bail out when we are out of range?
-        const double doubleval = toDoubleNumber(str);
+        const double doubleval = toDoubleNumber(str, tok);
         if (doubleval > (double)std::numeric_limits<bigint>::max())
             return std::numeric_limits<bigint>::max();
         if (doubleval < (double)std::numeric_limits<bigint>::min())
@@ -427,13 +438,13 @@ MathLib::bigint MathLib::toBigNumber(const std::string & str)
         if (idx != str.size()) {
             const std::string s = str.substr(idx);
             if (!isValidIntegerSuffix(s, true))
-                throw InternalError(nullptr, "Internal Error. MathLib::toBigNumber: input was not completely consumed: " + str);
+                throw InternalError(tok, "Internal Error. MathLib::toBigNumber: input was not completely consumed: " + str);
         }
         return ret;
     } catch (const std::out_of_range& /*e*/) {
-        throw InternalError(nullptr, "Internal Error. MathLib::toBigNumber: out_of_range: " + str);
+        throw InternalError(tok, "Internal Error. MathLib::toBigNumber: out_of_range: " + str);
     } catch (const std::invalid_argument& /*e*/) {
-        throw InternalError(nullptr, "Internal Error. MathLib::toBigNumber: invalid_argument: " + str);
+        throw InternalError(tok, "Internal Error. MathLib::toBigNumber: invalid_argument: " + str);
     }
 }
 
@@ -484,17 +495,22 @@ static double floatHexToDoubleNumber(const std::string& str)
     return factor1 * factor2;
 }
 
-double MathLib::toDoubleNumber(const std::string &str)
+double MathLib::toDoubleNumber(const Token * tok)
+{
+    return toDoubleNumber(tok->str(), tok);
+}
+
+double MathLib::toDoubleNumber(const std::string &str, const Token * const tok)
 {
     if (isCharLiteral(str)) {
         try {
             return simplecpp::characterLiteralToLL(str);
         } catch (const std::exception& e) {
-            throw InternalError(nullptr, "Internal Error. MathLib::toDoubleNumber: characterLiteralToLL(" + str + ") => " + e.what());
+            throw InternalError(tok, "Internal Error. MathLib::toDoubleNumber: characterLiteralToLL(" + str + ") => " + e.what());
         }
     }
     if (isIntHex(str))
-        return static_cast<double>(toBigNumber(str));
+        return static_cast<double>(toBigNumber(str, tok));
 #ifdef _LIBCPP_VERSION
     if (isFloat(str)) // Workaround libc++ bug at https://github.com/llvm/llvm-project/issues/18156
         // TODO: handle locale
@@ -508,13 +524,13 @@ double MathLib::toDoubleNumber(const std::string &str)
     istr.imbue(std::locale::classic());
     double ret;
     if (!(istr >> ret))
-        throw InternalError(nullptr, "Internal Error. MathLib::toDoubleNumber: conversion failed: " + str);
+        throw InternalError(tok, "Internal Error. MathLib::toDoubleNumber: conversion failed: " + str);
     std::string s;
     if (istr >> s) {
         if (isDecimalFloat(str))
             return ret;
         if (!isValidIntegerSuffix(s, true))
-            throw InternalError(nullptr, "Internal Error. MathLib::toDoubleNumber: input was not completely consumed: " + str);
+            throw InternalError(tok, "Internal Error. MathLib::toDoubleNumber: input was not completely consumed: " + str);
     }
     return ret;
 }
diff --git a/lib/mathlib.h b/lib/mathlib.h
index f83894c62b52..f0f1e2a7e6f3 100644
--- a/lib/mathlib.h
+++ b/lib/mathlib.h
@@ -30,6 +30,8 @@
 #include <boost/multiprecision/cpp_int.hpp>
 #endif
 
+class Token;
+
 /// @addtogroup Core
 /// @{
 
@@ -81,13 +83,19 @@ class CPPCHECKLIB MathLib {
     static const int bigint_bits;
 
     /** @brief for conversion of numeric literals - for atoi-like conversions please use strToInt() */
-    static bigint toBigNumber(const std::string & str);
+    static bigint toBigNumber(const Token * tok);
+    /** @brief for conversion of numeric literals - for atoi-like conversions please use strToInt() */
+    static bigint toBigNumber(const std::string & str, const Token *tok = nullptr);
     /** @brief for conversion of numeric literals - for atoi-like conversions please use strToInt() */
-    static biguint toBigUNumber(const std::string & str);
+    static biguint toBigUNumber(const Token * tok);
+    /** @brief for conversion of numeric literals - for atoi-like conversions please use strToInt() */
+    static biguint toBigUNumber(const std::string & str, const Token *tok = nullptr);
 
     template<class T> static std::string toString(T value) = delete;
     /** @brief for conversion of numeric literals */
-    static double toDoubleNumber(const std::string & str);
+    static double toDoubleNumber(const Token * tok);
+    /** @brief for conversion of numeric literals */
+    static double toDoubleNumber(const std::string & str, const Token * tok = nullptr);
 
     static bool isInt(const std::string & str);
     static bool isFloat(const std::string &str);
diff --git a/lib/programmemory.cpp b/lib/programmemory.cpp
index f64b919f4f95..4f96c8f4be37 100644
--- a/lib/programmemory.cpp
+++ b/lib/programmemory.cpp
@@ -1383,7 +1383,7 @@ namespace {
             if (expr->isNumber()) {
                 if (MathLib::isFloat(expr->str()))
                     return unknown();
-                MathLib::bigint i = MathLib::toBigNumber(expr->str());
+                MathLib::bigint i = MathLib::toBigNumber(expr);
                 if (i < 0 && astIsUnsigned(expr))
                     return unknown();
                 return ValueFlow::Value{i};
diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp
index 76cf60eadaf0..6c3aa0b2ea1e 100644
--- a/lib/symboldatabase.cpp
+++ b/lib/symboldatabase.cpp
@@ -1831,7 +1831,7 @@ void SymbolDatabase::setArrayDimensionsUsingValueFlow()
 
                 if (Token::Match(tokenList.front(), "; %num% ;")) {
                     dimension.known = true;
-                    dimension.num = MathLib::toBigNumber(tokenList.front()->strAt(1));
+                    dimension.num = MathLib::toBigNumber(tokenList.front()->tokAt(1));
                 }
 
                 continue;
@@ -3698,7 +3698,7 @@ bool Variable::arrayDimensions(const Settings& settings, bool& isContainer)
             if (Token::Match(tok, "%num% [,>]")) {
                 dimension_.tok = tok;
                 dimension_.known = true;
-                dimension_.num = MathLib::toBigNumber(tok->str());
+                dimension_.num = MathLib::toBigNumber(tok);
             } else if (tok) {
                 dimension_.tok = tok;
                 dimension_.known = false;
@@ -7441,7 +7441,7 @@ void SymbolDatabase::setValueTypeInTokenList(bool reportDebugWarnings, Token *to
                 const bool unsignedSuffix = (tokStr.find_last_of("uU") != std::string::npos);
                 ValueType::Sign sign = unsignedSuffix ? ValueType::Sign::UNSIGNED : ValueType::Sign::SIGNED;
                 ValueType::Type type = ValueType::Type::INT;
-                const MathLib::biguint value = MathLib::toBigUNumber(tokStr);
+                const MathLib::biguint value = MathLib::toBigUNumber(tokStr, tok);
                 for (std::size_t pos = tokStr.size() - 1U; pos > 0U; --pos) {
                     const char suffix = tokStr[pos];
                     if (suffix == 'u' || suffix == 'U')
diff --git a/lib/templatesimplifier.cpp b/lib/templatesimplifier.cpp
index b81ff82da9d2..f72f48914fed 100644
--- a/lib/templatesimplifier.cpp
+++ b/lib/templatesimplifier.cpp
@@ -2516,9 +2516,9 @@ void TemplateSimplifier::simplifyTemplateArgs(Token *start, const Token *end, st
                        MathLib::isInt(tok->strAt(2))) {
                 if ((Token::Match(tok->previous(), "(|&&|%oror%|,") || tok == start) &&
                     (Token::Match(tok->tokAt(3), ")|&&|%oror%|?") || tok->tokAt(3) == end)) {
-                    const MathLib::bigint op1(MathLib::toBigNumber(tok->str()));
+                    const MathLib::bigint op1(MathLib::toBigNumber(tok));
                     const std::string &cmp(tok->strAt(1));
-                    const MathLib::bigint op2(MathLib::toBigNumber(tok->strAt(2)));
+                    const MathLib::bigint op2(MathLib::toBigNumber(tok->tokAt(2)));
 
                     std::string result;
 
@@ -2689,7 +2689,7 @@ bool TemplateSimplifier::simplifyCalculations(Token* frontToken, const Token *ba
 
         if (validTokenEnd(bounded, tok, backToken, 3) &&
             Token::Match(tok->previous(), "(|&&|%oror% %char% %comp% %num% &&|%oror%|)")) {
-            tok->str(MathLib::toString(MathLib::toBigNumber(tok->str())));
+            tok->str(MathLib::toString(MathLib::toBigNumber(tok)));
         }
 
         if (validTokenEnd(bounded, tok, backToken, 5) &&
@@ -2885,9 +2885,9 @@ bool TemplateSimplifier::simplifyCalculations(Token* frontToken, const Token *ba
                 if (validTokenStart(bounded, tok, frontToken, -1) &&
                     Token::Match(tok->previous(), "(|&&|%oror%") &&
                     Token::Match(tok->tokAt(3), ")|&&|%oror%|?")) {
-                    const MathLib::bigint op1(MathLib::toBigNumber(tok->str()));
+                    const MathLib::bigint op1(MathLib::toBigNumber(tok));
                     const std::string &cmp(tok->strAt(1));
-                    const MathLib::bigint op2(MathLib::toBigNumber(tok->strAt(2)));
+                    const MathLib::bigint op2(MathLib::toBigNumber(tok->tokAt(2)));
 
                     std::string result;
 
diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp
index 907c7c48ac3e..ea4fde043558 100644
--- a/lib/tokenize.cpp
+++ b/lib/tokenize.cpp
@@ -3839,7 +3839,7 @@ void Tokenizer::arraySize()
                 if (tok2->link() && Token::Match(tok2, "{|(|[|<")) {
                     if (tok2->str() == "[" && tok2->link()->strAt(1) == "=") { // designated initializer
                         if (Token::Match(tok2, "[ %num% ]"))
-                            sz = std::max(sz, MathLib::toBigUNumber(tok2->strAt(1)) + 1U);
+                            sz = std::max(sz, MathLib::toBigUNumber(tok2->tokAt(1)) + 1U);
                         else {
                             sz = 0;
                             break;
@@ -4019,8 +4019,8 @@ void Tokenizer::simplifyCaseRange()
 {
     for (Token* tok = list.front(); tok; tok = tok->next()) {
         if (Token::Match(tok, "case %num%|%char% ... %num%|%char% :")) {
-            const MathLib::bigint start = MathLib::toBigNumber(tok->strAt(1));
-            MathLib::bigint end = MathLib::toBigNumber(tok->strAt(3));
+            const MathLib::bigint start = MathLib::toBigNumber(tok->tokAt(1));
+            MathLib::bigint end = MathLib::toBigNumber(tok->tokAt(3));
             end = std::min(start + 50, end); // Simplify it 50 times at maximum
             if (start < end) {
                 tok = tok->tokAt(2);
@@ -9353,10 +9353,10 @@ void Tokenizer::simplifyCppcheckAttribute()
         if (vartok->isName()) {
             if (Token::Match(tok->previous(), "__cppcheck_low__ ( %num% )"))
                 vartok->setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::LOW,
-                                             MathLib::toBigNumber(tok->strAt(1)));
+                                             MathLib::toBigNumber(tok->tokAt(1)));
             else if (Token::Match(tok->previous(), "__cppcheck_high__ ( %num% )"))
                 vartok->setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::HIGH,
-                                             MathLib::toBigNumber(tok->strAt(1)));
+                                             MathLib::toBigNumber(tok->tokAt(1)));
         }
 
         // Delete cppcheck attribute..
@@ -9428,16 +9428,16 @@ void Tokenizer::simplifyCPPAttribute()
                 if (argtok && argtok->str() == vartok->str()) {
                     if (vartok->strAt(1) == ">=")
                         argtok->setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::LOW,
-                                                     MathLib::toBigNumber(vartok->strAt(2)));
+                                                     MathLib::toBigNumber(vartok->tokAt(2)));
                     else if (vartok->strAt(1) == ">")
                         argtok->setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::LOW,
-                                                     MathLib::toBigNumber(vartok->strAt(2)) + 1);
+                                                     MathLib::toBigNumber(vartok->tokAt(2)) + 1);
                     else if (vartok->strAt(1) == "<=")
                         argtok->setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::HIGH,
-                                                     MathLib::toBigNumber(vartok->strAt(2)));
+                                                     MathLib::toBigNumber(vartok->tokAt(2)));
                     else if (vartok->strAt(1) == "<")
                         argtok->setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::HIGH,
-                                                     MathLib::toBigNumber(vartok->strAt(2)) - 1);
+                                                     MathLib::toBigNumber(vartok->tokAt(2)) - 1);
                 }
             }
         } else {
@@ -9894,7 +9894,7 @@ void Tokenizer::simplifyBitfields()
             !Token::simpleMatch(tok->tokAt(2), "default :")) {
             Token *tok1 = (tok->strAt(1) == "const") ? tok->tokAt(3) : tok->tokAt(2);
             if (Token::Match(tok1, "%name% : %num% [;=]"))
-                tok1->setBits(static_cast<unsigned char>(MathLib::toBigNumber(tok1->strAt(2))));
+                tok1->setBits(static_cast<unsigned char>(MathLib::toBigNumber(tok1->tokAt(2))));
             if (tok1 && tok1->tokAt(2) &&
                 (Token::Match(tok1->tokAt(2), "%bool%|%num%") ||
                  !Token::Match(tok1->tokAt(2), "public|protected|private| %type% ::|<|,|{|;"))) {
diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp
index 88035c2d162a..69ce0b280c58 100644
--- a/lib/valueflow.cpp
+++ b/lib/valueflow.cpp
@@ -824,9 +824,9 @@ static void valueFlowBitAnd(TokenList& tokenlist, const Settings& settings)
 
         MathLib::bigint number;
         if (MathLib::isInt(tok->astOperand1()->str()))
-            number = MathLib::toBigNumber(tok->astOperand1()->str());
+            number = MathLib::toBigNumber(tok->astOperand1());
         else if (MathLib::isInt(tok->astOperand2()->str()))
-            number = MathLib::toBigNumber(tok->astOperand2()->str());
+            number = MathLib::toBigNumber(tok->astOperand2());
         else
             continue;
 
@@ -5467,7 +5467,7 @@ static void valueFlowSwitchVariable(const TokenList& tokenlist,
             }
             if (Token::Match(tok, "case %num% :")) {
                 std::list<ValueFlow::Value> values;
-                values.emplace_back(MathLib::toBigNumber(tok->strAt(1)));
+                values.emplace_back(MathLib::toBigNumber(tok->tokAt(1)));
                 values.back().condition = tok;
                 values.back().errorPath.emplace_back(tok,
                                                      "case " + tok->strAt(1) + ": " + vartok->str() + " is " +
@@ -5481,7 +5481,7 @@ static void valueFlowSwitchVariable(const TokenList& tokenlist,
                     tok = tok->tokAt(3);
                     if (!tok->isName())
                         tok = tok->next();
-                    values.emplace_back(MathLib::toBigNumber(tok->strAt(1)));
+                    values.emplace_back(MathLib::toBigNumber(tok->tokAt(1)));
                     values.back().condition = tok;
                     values.back().errorPath.emplace_back(tok,
                                                          "case " + tok->strAt(1) + ": " + vartok->str() + " is " +
diff --git a/lib/vf_common.cpp b/lib/vf_common.cpp
index 306f90d8db97..0717cb6db663 100644
--- a/lib/vf_common.cpp
+++ b/lib/vf_common.cpp
@@ -120,7 +120,7 @@ namespace ValueFlow
     {
         if ((tok->isNumber() && MathLib::isInt(tok->str())) || (tok->tokType() == Token::eChar)) {
             try {
-                MathLib::bigint signedValue = MathLib::toBigNumber(tok->str());
+                MathLib::bigint signedValue = MathLib::toBigNumber(tok);
                 const ValueType* vt = tok->valueType();
                 if (vt && vt->sign == ValueType::UNSIGNED && signedValue < 0 && getSizeOf(*vt, settings) < sizeof(MathLib::bigint)) {
                     MathLib::bigint minValue{}, maxValue{};
@@ -137,7 +137,7 @@ namespace ValueFlow
         } else if (tok->isNumber() && MathLib::isFloat(tok->str())) {
             Value value;
             value.valueType = Value::ValueType::FLOAT;
-            value.floatValue = MathLib::toDoubleNumber(tok->str());
+            value.floatValue = MathLib::toDoubleNumber(tok);
             if (!tok->isTemplateArg())
                 value.setKnown();
             setTokenValue(tok, std::move(value), settings);
@@ -291,7 +291,7 @@ namespace ValueFlow
                     const Token* num = brac->astOperand2();
                     if (num && ((num->isNumber() && MathLib::isInt(num->str())) || num->tokType() == Token::eChar)) {
                         try {
-                            const MathLib::biguint dim = MathLib::toBigUNumber(num->str());
+                            const MathLib::biguint dim = MathLib::toBigUNumber(num);
                             sz *= dim;
                             brac = brac->astParent();
                             continue;
diff --git a/oss-fuzz/Makefile b/oss-fuzz/Makefile
index db4fa5cd6c51..4203c9deb466 100644
--- a/oss-fuzz/Makefile
+++ b/oss-fuzz/Makefile
@@ -285,7 +285,7 @@ $(libcppdir)/keywords.o: ../lib/keywords.cpp ../lib/config.h ../lib/keywords.h .
 $(libcppdir)/library.o: ../lib/library.cpp ../externals/tinyxml2/tinyxml2.h ../lib/astutils.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h ../lib/xml.h
 	$(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/library.cpp
 
-$(libcppdir)/mathlib.o: ../lib/mathlib.cpp ../externals/simplecpp/simplecpp.h ../lib/config.h ../lib/errortypes.h ../lib/mathlib.h ../lib/utils.h
+$(libcppdir)/mathlib.o: ../lib/mathlib.cpp ../externals/simplecpp/simplecpp.h ../lib/config.h ../lib/errortypes.h ../lib/mathlib.h ../lib/templatesimplifier.h ../lib/token.h ../lib/utils.h ../lib/vfvalue.h
 	$(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/mathlib.cpp
 
 $(libcppdir)/path.o: ../lib/path.cpp ../externals/simplecpp/simplecpp.h ../lib/config.h ../lib/path.h ../lib/standards.h ../lib/utils.h
diff --git a/test/cli/other_test.py b/test/cli/other_test.py
index c5668c8f4fdb..720b483d4585 100644
--- a/test/cli/other_test.py
+++ b/test/cli/other_test.py
@@ -2719,3 +2719,26 @@ def test_xml_builddir(tmp_path):  # #13391 / #13485
     assert exitcode_1 == exitcode_2, stdout_2
     assert stdout_1 == stdout_2
     assert stderr_1 == stderr_2
+
+
+def test_internal_error_loc_int(tmp_path):
+    test_file = tmp_path / 'test.c'
+    with open(test_file, 'wt') as f:
+        f.write(
+"""
+void f() {
+    int i = 0x10000000000000000;
+}
+""")
+
+    args = [
+        '-q',
+        '--template=simple',
+        str(test_file)
+    ]
+    exitcode, stdout, stderr = cppcheck(args)
+    assert exitcode == 0, stdout
+    assert stdout.splitlines() == []
+    assert stderr.splitlines() == [
+        '{}:3:13: error: Internal Error. MathLib::toBigUNumber: out_of_range: 0x10000000000000000 [internalError]'.format(test_file)
+    ]
\ No newline at end of file
diff --git a/test/testmathlib.cpp b/test/testmathlib.cpp
index 70cc9b947a40..c2494b6712be 100644
--- a/test/testmathlib.cpp
+++ b/test/testmathlib.cpp
@@ -17,8 +17,10 @@
  */
 
 #include "config.h"
-#include "mathlib.h"
 #include "fixture.h"
+#include "mathlib.h"
+#include "token.h"
+#include "tokenlist.h"
 
 #include <limits>
 #include <string>
@@ -405,6 +407,17 @@ class TestMathLib : public TestFixture {
         ASSERT_THROW_INTERNAL_EQUALS(MathLib::toBigNumber("1invalid"), INTERNAL, "Internal Error. MathLib::toBigNumber: input was not completely consumed: 1invalid");
         ASSERT_THROW_INTERNAL_EQUALS(MathLib::toBigNumber("1 invalid"), INTERNAL, "Internal Error. MathLib::toBigNumber: input was not completely consumed: 1 invalid");
 
+        {
+            TokenList list{&settingsDefault};
+            list.appendFileIfNew("test.c");
+            TokensFrontBack tokensFrontBack(list);
+            auto *tok = new Token(tokensFrontBack);
+            tok->str("invalid");
+            ASSERT_THROW_INTERNAL_EQUALS(MathLib::toBigNumber(tok), INTERNAL, "Internal Error. MathLib::toBigNumber: invalid_argument: invalid");
+            ASSERT_THROW_INTERNAL_EQUALS(MathLib::toBigNumber("invalid", tok), INTERNAL, "Internal Error. MathLib::toBigNumber: invalid_argument: invalid");
+            TokenList::deleteTokens(tok);
+        }
+
         // TODO: test binary
         // TODO: test floating point
 
@@ -570,6 +583,17 @@ class TestMathLib : public TestFixture {
         ASSERT_THROW_INTERNAL_EQUALS(MathLib::toBigUNumber("1invalid"), INTERNAL, "Internal Error. MathLib::toBigUNumber: input was not completely consumed: 1invalid");
         ASSERT_THROW_INTERNAL_EQUALS(MathLib::toBigUNumber("1 invalid"), INTERNAL, "Internal Error. MathLib::toBigUNumber: input was not completely consumed: 1 invalid");
 
+        {
+            TokenList list{&settingsDefault};
+            list.appendFileIfNew("test.c");
+            TokensFrontBack tokensFrontBack(list);
+            auto *tok = new Token(tokensFrontBack);
+            tok->str("invalid");
+            ASSERT_THROW_INTERNAL_EQUALS(MathLib::toBigUNumber(tok), INTERNAL, "Internal Error. MathLib::toBigUNumber: invalid_argument: invalid");
+            ASSERT_THROW_INTERNAL_EQUALS(MathLib::toBigUNumber("invalid", tok), INTERNAL, "Internal Error. MathLib::toBigUNumber: invalid_argument: invalid");
+            TokenList::deleteTokens(tok);
+        }
+
         // TODO: test binary
         // TODO: test floating point
 
@@ -689,6 +713,17 @@ class TestMathLib : public TestFixture {
         //ASSERT_THROW_INTERNAL_EQUALS(MathLib::toDoubleNumber("1.0ll"), INTERNAL, "Internal Error. MathLib::toDoubleNumber: input was not completely consumed: 1.0ll");
         //ASSERT_THROW_INTERNAL_EQUALS(MathLib::toDoubleNumber("1.0LL"), INTERNAL, "Internal Error. MathLib::toDoubleNumber: input was not completely consumed: 1.0LL");
 
+        {
+            TokenList list{&settingsDefault};
+            list.appendFileIfNew("test.c");
+            TokensFrontBack tokensFrontBack(list);
+            auto *tok = new Token(tokensFrontBack);
+            tok->str("invalid");
+            ASSERT_THROW_INTERNAL_EQUALS(MathLib::toDoubleNumber(tok), INTERNAL, "Internal Error. MathLib::toDoubleNumber: conversion failed: invalid");
+            ASSERT_THROW_INTERNAL_EQUALS(MathLib::toDoubleNumber("invalid", tok), INTERNAL, "Internal Error. MathLib::toDoubleNumber: conversion failed: invalid");
+            TokenList::deleteTokens(tok);
+        }
+
         // verify: string --> double --> string conversion
         // TODO: add L, min/max
         ASSERT_EQUALS("1.0",  MathLib::toString(MathLib::toDoubleNumber("1.0f")));