From a0315a508dd97cfdc14aabf1a31c8462f21a7185 Mon Sep 17 00:00:00 2001 From: James Bardin Date: Tue, 30 Jan 2024 17:16:14 -0500 Subject: [PATCH] Use integer comparison for equality If we are comparing 2 numbers that are even integers, compare them via big.Int values rather than formatted strings. This avoids problems with large integers stored in big.Float with different precisions which could format differently. --- cty/primitive_type.go | 16 +++++++++++++++- cty/value_ops_test.go | 5 +++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/cty/primitive_type.go b/cty/primitive_type.go index 3ce2540b..2beea652 100644 --- a/cty/primitive_type.go +++ b/cty/primitive_type.go @@ -1,6 +1,8 @@ package cty -import "math/big" +import ( + "math/big" +) // primitiveType is the hidden implementation of the various primitive types // that are exposed as variables in this package. @@ -77,6 +79,18 @@ func rawNumberEqual(a, b *big.Float) bool { case a.Sign() != b.Sign(): return false default: + // First check if these are integers, and compare them directly. Floats + // need a more nuanced approach. + aInt, aAcc := a.Int(nil) + bInt, bAcc := b.Int(nil) + if aAcc != bAcc { + // only one is an exact integer value, so they can't be equal + return false + } + if aAcc == big.Exact { + return aInt.Cmp(bInt) == 0 + } + // This format and precision matches that used by cty/json.Marshal, // and thus achieves our definition of "two numbers are equal if // we'd use the same JSON serialization for both of them". diff --git a/cty/value_ops_test.go b/cty/value_ops_test.go index d3ad9027..d4fb6a50 100644 --- a/cty/value_ops_test.go +++ b/cty/value_ops_test.go @@ -91,6 +91,11 @@ func TestValueEquals(t *testing.T) { NumberFloatVal(1.22222), BoolVal(true), }, + { + MustParseNumberVal("9223372036854775808"), + NumberFloatVal(float64(9223372036854775808)), + BoolVal(true), + }, // Strings {