Browse Source

Fixes for literal overflow detection

Brian Fiete 3 years ago
parent
commit
a3b761ab26

+ 1 - 1
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)))
 		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;

+ 1 - 1
IDEHelper/Compiler/BfModule.cpp

@@ -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(),

+ 29 - 37
IDEHelper/Compiler/BfParser.cpp

@@ -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
-					c = mSrc[mSrcIdx++];
+					BF_FATAL("Parsing error");
 				}
 				}
 
 
 				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--;
-						if (wasNeg)
-							val = -val;
+						mSrcIdx--;						
 
 
 						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;
-							if ((val < 0) && (!wasNeg))
+							mLiteral.mUInt64 = val;
+							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");
-						if (wasNeg)
-							val = -val;
+							TokenFail("Uppercase 'L' required for int64");						
 						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;
-
-						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 (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--;
-						if (wasNeg)
-							val = -val;
-						mLiteral.mInt64 = val;
+						mSrcIdx--;						
+						mLiteral.mUInt64 = 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;
 				}
 				}

+ 1 - 0
IDEHelper/Compiler/BfParser.h

@@ -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();	
 		
 		

+ 35 - 0
IDEHelper/Compiler/BfSystem.cpp

@@ -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);

+ 1 - 0
IDEHelper/Compiler/BfSystem.h

@@ -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);