From a3b761ab266f13292cd067abf3b10a091c4ff392 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Wed, 15 Dec 2021 12:17:20 -0500 Subject: [PATCH] Fixes for literal overflow detection --- IDEHelper/Compiler/BfExprEvaluator.cpp | 2 +- IDEHelper/Compiler/BfModule.cpp | 2 +- IDEHelper/Compiler/BfParser.cpp | 66 +++++++++++--------------- IDEHelper/Compiler/BfParser.h | 1 + IDEHelper/Compiler/BfSystem.cpp | 35 ++++++++++++++ IDEHelper/Compiler/BfSystem.h | 1 + 6 files changed, 68 insertions(+), 39 deletions(-) diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index 5f40ac99..7ab34ee4 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -3578,7 +3578,7 @@ void BfExprEvaluator::GetLiteral(BfAstNode* refNode, const BfVariant& variant) if ((mExpectingType != NULL) && (mExpectingType->IsIntegral()) && (mExpectingType->IsChar() == IsCharType(variant.mTypeCode))) { auto primType = (BfPrimitiveType*)mExpectingType; - if (mModule->mSystem->DoesLiteralFit(primType->mTypeDef->mTypeCode, variant.mInt64)) + if (mModule->mSystem->DoesLiteralFit(primType->mTypeDef->mTypeCode, variant.mUInt64)) { mResult = BfTypedValue(mModule->mBfIRBuilder->CreateConst(primType->mTypeDef->mTypeCode, variant.mUInt64), mExpectingType); break; diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index 1d8a28b2..17fb80af 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -7889,7 +7889,7 @@ bool BfModule::CheckGenericConstraints(const BfGenericParamSource& genericParamS { if (BfIRConstHolder::IsInt(primType->mTypeDef->mTypeCode)) { - if (!mCompiler->mSystem->DoesLiteralFit(primType->mTypeDef->mTypeCode, constExprValueType->mValue.mInt64)) + if (!mCompiler->mSystem->DoesLiteralFit(primType->mTypeDef->mTypeCode, constExprValueType->mValue.mUInt64)) { if ((!ignoreErrors) && (PreFail())) *errorOut = Fail(StrFormat("Const generic argument '%s', declared with const '%lld', does not fit into const constraint '%s' for '%s'", genericParamInst->GetName().c_str(), diff --git a/IDEHelper/Compiler/BfParser.cpp b/IDEHelper/Compiler/BfParser.cpp index dce0e396..e96ba38f 100644 --- a/IDEHelper/Compiler/BfParser.cpp +++ b/IDEHelper/Compiler/BfParser.cpp @@ -2447,10 +2447,9 @@ void BfParser::NextToken(int endIdx, bool outerIsInterpolate) mTokenEnd = mSrcIdx; return; } - - bool wasNeg = false; + bool hadOverflow = false; - int64 val = 0; + uint64 val = 0; int numberBase = 10; int expVal = 0; int expSign = 0; @@ -2460,8 +2459,7 @@ void BfParser::NextToken(int endIdx, bool outerIsInterpolate) int hexDigits = 0; if (c == '-') { - wasNeg = true; //TODO: This never actually gets set any more (eaten as BfToken_Minus above). Move checks that use this to later in pipeline, then remove this - c = mSrc[mSrcIdx++]; + BF_FATAL("Parsing error"); } val = c - '0'; @@ -2641,7 +2639,7 @@ void BfParser::NextToken(int endIdx, bool outerIsInterpolate) // This is actually a integer followed by an Int32 call (like 123.ToString) mSrcIdx -= 2; mTokenEnd = mSrcIdx; - mLiteral.mInt64 = val; + mLiteral.mUInt64 = val; mLiteral.mTypeCode = BfTypeCode_IntUnknown; mSyntaxToken = BfSyntaxToken_Literal; return; @@ -2668,27 +2666,24 @@ void BfParser::NextToken(int endIdx, bool outerIsInterpolate) if (endNumber) { mTokenEnd = mSrcIdx - 1; - mSrcIdx--; - if (wasNeg) - val = -val; + mSrcIdx--; if ((numberBase == 0x10) && ((hexDigits >= 16) || ((hadSeps) && (hexDigits > 8)) || ((hadLeadingHexSep) && (hexDigits == 8)))) { if (hexDigits > 16) mPassInstance->FailAt("Too many hex digits for int64", mSourceData, mTokenStart, mSrcIdx - mTokenStart); - mLiteral.mInt64 = val; - if ((val < 0) && (!wasNeg)) + mLiteral.mUInt64 = val; + if (val >= 0x8000000000000000) mLiteral.mTypeCode = BfTypeCode_UInt64; else mLiteral.mTypeCode = BfTypeCode_Int64; } else { - mLiteral.mInt64 = val; + mLiteral.mUInt64 = val; mLiteral.mTypeCode = BfTypeCode_IntUnknown; - if ((numberBase == 0x10) && (hexDigits == 7)) mLiteral.mWarnType = BfWarning_BF4201_Only7Hex; if ((numberBase == 0x10) && (hexDigits == 9)) @@ -2699,7 +2694,12 @@ void BfParser::NextToken(int endIdx, bool outerIsInterpolate) mPassInstance->FailAt("Value doesn't fit into int64", mSourceData, mTokenStart, mSrcIdx - mTokenStart); mLiteral.mTypeCode = BfTypeCode_Int64; } - else if ((val < -0x80000000LL) || (val > 0xFFFFFFFFLL)) + //else if ((val < -0x80000000LL) || (val > 0xFFFFFFFFLL)) + else if (val >= 0x8000000000000000) + { + mLiteral.mTypeCode = BfTypeCode_UInt64; + } + else if (val > 0xFFFFFFFFLL) { mLiteral.mTypeCode = BfTypeCode_Int64; } @@ -2709,7 +2709,7 @@ void BfParser::NextToken(int endIdx, bool outerIsInterpolate) return; } - int64 prevVal = val; + uint64 prevVal = val; if ((c >= '0') && (c <= '9') && (c < '0' + numberBase)) { if (numberBase == 0x10) @@ -2731,9 +2731,7 @@ void BfParser::NextToken(int endIdx, bool outerIsInterpolate) } else if ((c == 'u') || (c == 'U')) - { - if (wasNeg) - val = -val; + { if ((mSrc[mSrcIdx] == 'l') || (mSrc[mSrcIdx] == 'L')) { if (mSrc[mSrcIdx] == 'l') @@ -2744,7 +2742,7 @@ void BfParser::NextToken(int endIdx, bool outerIsInterpolate) mLiteral.mUInt64 = (uint64)val; if (hexDigits > 16) mPassInstance->FailAt("Too many hex digits for int64", mSourceData, mTokenStart, mSrcIdx - mTokenStart); - else if ((hadOverflow) || (wasNeg)) + else if (hadOverflow) mPassInstance->FailAt("Value doesn't fit into uint64", mSourceData, mTokenStart, mSrcIdx - mTokenStart); mSyntaxToken = BfSyntaxToken_Literal; return; @@ -2752,7 +2750,7 @@ void BfParser::NextToken(int endIdx, bool outerIsInterpolate) mTokenEnd = mSrcIdx; mLiteral.mTypeCode = BfTypeCode_UIntPtr; mLiteral.mUInt32 = (uint32)val; - if ((hadOverflow) || (wasNeg) || ((uint64)val != (uint64)mLiteral.mUInt32)) + if ((hadOverflow) || ((uint64)val != (uint64)mLiteral.mUInt32)) mPassInstance->FailAt("Value doesn't fit into uint32", mSourceData, mTokenStart, mSrcIdx - mTokenStart); mSyntaxToken = BfSyntaxToken_Literal; return; @@ -2760,9 +2758,7 @@ void BfParser::NextToken(int endIdx, bool outerIsInterpolate) else if ((c == 'l') || (c == 'L')) { if (c == 'l') - TokenFail("Uppercase 'L' required for int64"); - if (wasNeg) - val = -val; + TokenFail("Uppercase 'L' required for int64"); if ((mSrc[mSrcIdx] == 'u') || (mSrc[mSrcIdx] == 'U')) { mSrcIdx++; @@ -2771,25 +2767,24 @@ void BfParser::NextToken(int endIdx, bool outerIsInterpolate) mLiteral.mUInt64 = (uint64)val; if (hexDigits > 16) mPassInstance->FailAt("Too many hex digits for int64", mSourceData, mTokenStart, mSrcIdx - mTokenStart); - else if ((hadOverflow) || (wasNeg)) + else if (hadOverflow) mPassInstance->FailAt("Value doesn't fit into uint64", mSourceData, mTokenStart, mSrcIdx - mTokenStart); mSyntaxToken = BfSyntaxToken_Literal; return; - } + } mTokenEnd = mSrcIdx; mLiteral.mTypeCode = BfTypeCode_Int64; mLiteral.mInt64 = (int64)val; - - bool signMatched = true; - if (val != 0) - signMatched = (val < 0) == wasNeg; - + if (val == 0x8000000000000000) + mLiteral.mTypeCode = BfTypeCode_UInt64; + else if (val >= 0x8000000000000000) + hadOverflow = true; if (numberBase == 0x10) { if (hexDigits > 16) mPassInstance->FailAt("Too many hex digits for int64", mSourceData, mTokenStart, mSrcIdx - mTokenStart); } - else if ((hadOverflow) || (!signMatched)) + else if (hadOverflow) mPassInstance->FailAt("Value doesn't fit into int64", mSourceData, mTokenStart, mSrcIdx - mTokenStart); mSyntaxToken = BfSyntaxToken_Literal; return; @@ -2813,17 +2808,14 @@ void BfParser::NextToken(int endIdx, bool outerIsInterpolate) else { mTokenEnd = mSrcIdx - 1; - mSrcIdx--; - if (wasNeg) - val = -val; - mLiteral.mInt64 = val; + mSrcIdx--; + mLiteral.mUInt64 = val; mLiteral.mTypeCode = BfTypeCode_IntUnknown; mSyntaxToken = BfSyntaxToken_Literal; TokenFail("Unexpected character while parsing number", 0); return; } - - //if ((val < 0) && (val != -0x8000000000000000)) + if ((uint64)prevVal > (uint64)val) hadOverflow = true; } diff --git a/IDEHelper/Compiler/BfParser.h b/IDEHelper/Compiler/BfParser.h index cc9a27ed..3c95ed8d 100644 --- a/IDEHelper/Compiler/BfParser.h +++ b/IDEHelper/Compiler/BfParser.h @@ -226,6 +226,7 @@ public: void SetSource(const char* data, int length); void MoveSource(const char* data, int length); // Takes ownership of data ptr void RefSource(const char* data, int length); + void MakeNegative(uint64& val, bool& hadOverflow); void NextToken(int endIdx = -1, bool outerIsInterpolate = false); BfAstNode* CreateNode(); diff --git a/IDEHelper/Compiler/BfSystem.cpp b/IDEHelper/Compiler/BfSystem.cpp index 4ff7e3d1..0f0419bd 100644 --- a/IDEHelper/Compiler/BfSystem.cpp +++ b/IDEHelper/Compiler/BfSystem.cpp @@ -2282,6 +2282,41 @@ bool BfSystem::DoesLiteralFit(BfTypeCode typeCode, int64 value) return false; } +bool BfSystem::DoesLiteralFit(BfTypeCode typeCode, uint64 value) +{ + if (typeCode == BfTypeCode_IntPtr) + typeCode = (mPtrSize == 4) ? BfTypeCode_Int32 : BfTypeCode_Int64; + if (typeCode == BfTypeCode_UIntPtr) + typeCode = (mPtrSize == 4) ? BfTypeCode_UInt32 : BfTypeCode_UInt64; + + if (value >= 0x8000000000000000) + return typeCode == BfTypeCode_UInt64; + + switch (typeCode) + { + case BfTypeCode_Int8: + return (value < 0x80); + case BfTypeCode_Int16: + return (value < 0x8000); + case BfTypeCode_Int32: + return (value < 0x80000000LL); + case BfTypeCode_Int64: + return true; + + case BfTypeCode_UInt8: + return (value < 0x100); + case BfTypeCode_UInt16: + return (value < 0x10000); + case BfTypeCode_UInt32: + return (value < 0x100000000LL); + case BfTypeCode_UInt64: + return true; + default: break; + } + + return false; +} + BfParser* BfSystem::CreateParser(BfProject* bfProject) { AutoCrit crit(mDataLock); diff --git a/IDEHelper/Compiler/BfSystem.h b/IDEHelper/Compiler/BfSystem.h index 42a35340..1a4fbd93 100644 --- a/IDEHelper/Compiler/BfSystem.h +++ b/IDEHelper/Compiler/BfSystem.h @@ -1610,6 +1610,7 @@ public: void CreateBasicTypes(); bool DoesLiteralFit(BfTypeCode typeCode, int64 value); + bool DoesLiteralFit(BfTypeCode typeCode, uint64 value); BfParser* CreateParser(BfProject* bfProject); BfCompiler* CreateCompiler(bool isResolveOnly); BfProject* GetProject(const StringImpl& projName);