1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-08 19:48:20 +02:00

Fixes for literal overflow detection

This commit is contained in:
Brian Fiete 2021-12-15 12:17:20 -05:00
parent 6a95cbb3b8
commit a3b761ab26
6 changed files with 68 additions and 39 deletions

View file

@ -3578,7 +3578,7 @@ void BfExprEvaluator::GetLiteral(BfAstNode* refNode, const BfVariant& variant)
if ((mExpectingType != NULL) && (mExpectingType->IsIntegral()) && (mExpectingType->IsChar() == IsCharType(variant.mTypeCode))) if ((mExpectingType != NULL) && (mExpectingType->IsIntegral()) && (mExpectingType->IsChar() == IsCharType(variant.mTypeCode)))
{ {
auto primType = (BfPrimitiveType*)mExpectingType; 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); mResult = BfTypedValue(mModule->mBfIRBuilder->CreateConst(primType->mTypeDef->mTypeCode, variant.mUInt64), mExpectingType);
break; break;

View file

@ -7889,7 +7889,7 @@ bool BfModule::CheckGenericConstraints(const BfGenericParamSource& genericParamS
{ {
if (BfIRConstHolder::IsInt(primType->mTypeDef->mTypeCode)) 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())) 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(), *errorOut = Fail(StrFormat("Const generic argument '%s', declared with const '%lld', does not fit into const constraint '%s' for '%s'", genericParamInst->GetName().c_str(),

View file

@ -2447,10 +2447,9 @@ void BfParser::NextToken(int endIdx, bool outerIsInterpolate)
mTokenEnd = mSrcIdx; mTokenEnd = mSrcIdx;
return; return;
} }
bool wasNeg = false;
bool hadOverflow = false; bool hadOverflow = false;
int64 val = 0; uint64 val = 0;
int numberBase = 10; int numberBase = 10;
int expVal = 0; int expVal = 0;
int expSign = 0; int expSign = 0;
@ -2460,8 +2459,7 @@ void BfParser::NextToken(int endIdx, bool outerIsInterpolate)
int hexDigits = 0; int hexDigits = 0;
if (c == '-') 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 BF_FATAL("Parsing error");
c = mSrc[mSrcIdx++];
} }
val = c - '0'; 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) // This is actually a integer followed by an Int32 call (like 123.ToString)
mSrcIdx -= 2; mSrcIdx -= 2;
mTokenEnd = mSrcIdx; mTokenEnd = mSrcIdx;
mLiteral.mInt64 = val; mLiteral.mUInt64 = val;
mLiteral.mTypeCode = BfTypeCode_IntUnknown; mLiteral.mTypeCode = BfTypeCode_IntUnknown;
mSyntaxToken = BfSyntaxToken_Literal; mSyntaxToken = BfSyntaxToken_Literal;
return; return;
@ -2668,27 +2666,24 @@ void BfParser::NextToken(int endIdx, bool outerIsInterpolate)
if (endNumber) if (endNumber)
{ {
mTokenEnd = mSrcIdx - 1; mTokenEnd = mSrcIdx - 1;
mSrcIdx--; mSrcIdx--;
if (wasNeg)
val = -val;
if ((numberBase == 0x10) && if ((numberBase == 0x10) &&
((hexDigits >= 16) || ((hadSeps) && (hexDigits > 8)) || ((hadLeadingHexSep) && (hexDigits == 8)))) ((hexDigits >= 16) || ((hadSeps) && (hexDigits > 8)) || ((hadLeadingHexSep) && (hexDigits == 8))))
{ {
if (hexDigits > 16) if (hexDigits > 16)
mPassInstance->FailAt("Too many hex digits for int64", mSourceData, mTokenStart, mSrcIdx - mTokenStart); mPassInstance->FailAt("Too many hex digits for int64", mSourceData, mTokenStart, mSrcIdx - mTokenStart);
mLiteral.mInt64 = val; mLiteral.mUInt64 = val;
if ((val < 0) && (!wasNeg)) if (val >= 0x8000000000000000)
mLiteral.mTypeCode = BfTypeCode_UInt64; mLiteral.mTypeCode = BfTypeCode_UInt64;
else else
mLiteral.mTypeCode = BfTypeCode_Int64; mLiteral.mTypeCode = BfTypeCode_Int64;
} }
else else
{ {
mLiteral.mInt64 = val; mLiteral.mUInt64 = val;
mLiteral.mTypeCode = BfTypeCode_IntUnknown; mLiteral.mTypeCode = BfTypeCode_IntUnknown;
if ((numberBase == 0x10) && (hexDigits == 7)) if ((numberBase == 0x10) && (hexDigits == 7))
mLiteral.mWarnType = BfWarning_BF4201_Only7Hex; mLiteral.mWarnType = BfWarning_BF4201_Only7Hex;
if ((numberBase == 0x10) && (hexDigits == 9)) 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); mPassInstance->FailAt("Value doesn't fit into int64", mSourceData, mTokenStart, mSrcIdx - mTokenStart);
mLiteral.mTypeCode = BfTypeCode_Int64; 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; mLiteral.mTypeCode = BfTypeCode_Int64;
} }
@ -2709,7 +2709,7 @@ void BfParser::NextToken(int endIdx, bool outerIsInterpolate)
return; return;
} }
int64 prevVal = val; uint64 prevVal = val;
if ((c >= '0') && (c <= '9') && (c < '0' + numberBase)) if ((c >= '0') && (c <= '9') && (c < '0' + numberBase))
{ {
if (numberBase == 0x10) if (numberBase == 0x10)
@ -2731,9 +2731,7 @@ void BfParser::NextToken(int endIdx, bool outerIsInterpolate)
} }
else if ((c == 'u') || (c == 'U')) else if ((c == 'u') || (c == 'U'))
{ {
if (wasNeg)
val = -val;
if ((mSrc[mSrcIdx] == 'l') || (mSrc[mSrcIdx] == 'L')) if ((mSrc[mSrcIdx] == 'l') || (mSrc[mSrcIdx] == 'L'))
{ {
if (mSrc[mSrcIdx] == 'l') if (mSrc[mSrcIdx] == 'l')
@ -2744,7 +2742,7 @@ void BfParser::NextToken(int endIdx, bool outerIsInterpolate)
mLiteral.mUInt64 = (uint64)val; mLiteral.mUInt64 = (uint64)val;
if (hexDigits > 16) if (hexDigits > 16)
mPassInstance->FailAt("Too many hex digits for int64", mSourceData, mTokenStart, mSrcIdx - mTokenStart); 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); mPassInstance->FailAt("Value doesn't fit into uint64", mSourceData, mTokenStart, mSrcIdx - mTokenStart);
mSyntaxToken = BfSyntaxToken_Literal; mSyntaxToken = BfSyntaxToken_Literal;
return; return;
@ -2752,7 +2750,7 @@ void BfParser::NextToken(int endIdx, bool outerIsInterpolate)
mTokenEnd = mSrcIdx; mTokenEnd = mSrcIdx;
mLiteral.mTypeCode = BfTypeCode_UIntPtr; mLiteral.mTypeCode = BfTypeCode_UIntPtr;
mLiteral.mUInt32 = (uint32)val; 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); mPassInstance->FailAt("Value doesn't fit into uint32", mSourceData, mTokenStart, mSrcIdx - mTokenStart);
mSyntaxToken = BfSyntaxToken_Literal; mSyntaxToken = BfSyntaxToken_Literal;
return; return;
@ -2760,9 +2758,7 @@ void BfParser::NextToken(int endIdx, bool outerIsInterpolate)
else if ((c == 'l') || (c == 'L')) else if ((c == 'l') || (c == 'L'))
{ {
if (c == 'l') if (c == 'l')
TokenFail("Uppercase 'L' required for int64"); TokenFail("Uppercase 'L' required for int64");
if (wasNeg)
val = -val;
if ((mSrc[mSrcIdx] == 'u') || (mSrc[mSrcIdx] == 'U')) if ((mSrc[mSrcIdx] == 'u') || (mSrc[mSrcIdx] == 'U'))
{ {
mSrcIdx++; mSrcIdx++;
@ -2771,25 +2767,24 @@ void BfParser::NextToken(int endIdx, bool outerIsInterpolate)
mLiteral.mUInt64 = (uint64)val; mLiteral.mUInt64 = (uint64)val;
if (hexDigits > 16) if (hexDigits > 16)
mPassInstance->FailAt("Too many hex digits for int64", mSourceData, mTokenStart, mSrcIdx - mTokenStart); 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); mPassInstance->FailAt("Value doesn't fit into uint64", mSourceData, mTokenStart, mSrcIdx - mTokenStart);
mSyntaxToken = BfSyntaxToken_Literal; mSyntaxToken = BfSyntaxToken_Literal;
return; return;
} }
mTokenEnd = mSrcIdx; mTokenEnd = mSrcIdx;
mLiteral.mTypeCode = BfTypeCode_Int64; mLiteral.mTypeCode = BfTypeCode_Int64;
mLiteral.mInt64 = (int64)val; mLiteral.mInt64 = (int64)val;
if (val == 0x8000000000000000)
bool signMatched = true; mLiteral.mTypeCode = BfTypeCode_UInt64;
if (val != 0) else if (val >= 0x8000000000000000)
signMatched = (val < 0) == wasNeg; hadOverflow = true;
if (numberBase == 0x10) if (numberBase == 0x10)
{ {
if (hexDigits > 16) if (hexDigits > 16)
mPassInstance->FailAt("Too many hex digits for int64", mSourceData, mTokenStart, mSrcIdx - mTokenStart); 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); mPassInstance->FailAt("Value doesn't fit into int64", mSourceData, mTokenStart, mSrcIdx - mTokenStart);
mSyntaxToken = BfSyntaxToken_Literal; mSyntaxToken = BfSyntaxToken_Literal;
return; return;
@ -2813,17 +2808,14 @@ void BfParser::NextToken(int endIdx, bool outerIsInterpolate)
else else
{ {
mTokenEnd = mSrcIdx - 1; mTokenEnd = mSrcIdx - 1;
mSrcIdx--; mSrcIdx--;
if (wasNeg) mLiteral.mUInt64 = val;
val = -val;
mLiteral.mInt64 = val;
mLiteral.mTypeCode = BfTypeCode_IntUnknown; mLiteral.mTypeCode = BfTypeCode_IntUnknown;
mSyntaxToken = BfSyntaxToken_Literal; mSyntaxToken = BfSyntaxToken_Literal;
TokenFail("Unexpected character while parsing number", 0); TokenFail("Unexpected character while parsing number", 0);
return; return;
} }
//if ((val < 0) && (val != -0x8000000000000000))
if ((uint64)prevVal > (uint64)val) if ((uint64)prevVal > (uint64)val)
hadOverflow = true; hadOverflow = true;
} }

View file

@ -226,6 +226,7 @@ public:
void SetSource(const char* data, int length); void SetSource(const char* data, int length);
void MoveSource(const char* data, int length); // Takes ownership of data ptr void MoveSource(const char* data, int length); // Takes ownership of data ptr
void RefSource(const char* data, int length); void RefSource(const char* data, int length);
void MakeNegative(uint64& val, bool& hadOverflow);
void NextToken(int endIdx = -1, bool outerIsInterpolate = false); void NextToken(int endIdx = -1, bool outerIsInterpolate = false);
BfAstNode* CreateNode(); BfAstNode* CreateNode();

View file

@ -2282,6 +2282,41 @@ bool BfSystem::DoesLiteralFit(BfTypeCode typeCode, int64 value)
return false; 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) BfParser* BfSystem::CreateParser(BfProject* bfProject)
{ {
AutoCrit crit(mDataLock); AutoCrit crit(mDataLock);

View file

@ -1610,6 +1610,7 @@ public:
void CreateBasicTypes(); void CreateBasicTypes();
bool DoesLiteralFit(BfTypeCode typeCode, int64 value); bool DoesLiteralFit(BfTypeCode typeCode, int64 value);
bool DoesLiteralFit(BfTypeCode typeCode, uint64 value);
BfParser* CreateParser(BfProject* bfProject); BfParser* CreateParser(BfProject* bfProject);
BfCompiler* CreateCompiler(bool isResolveOnly); BfCompiler* CreateCompiler(bool isResolveOnly);
BfProject* GetProject(const StringImpl& projName); BfProject* GetProject(const StringImpl& projName);