fix(lua): compare float with int strictly in equality (#7611)

Co-authored-by: Peter Feerick <peter.feerick@gmail.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Giuseppe Rojas
2026-08-30 18:48:47 +10:00
committed by GitHub
co-authored by Peter Feerick Claude Sonnet 5
parent db18294f78
commit 34afae5a26
3 changed files with 50 additions and 1 deletions
+40
View File
@@ -198,6 +198,46 @@ TEST(Lua, Switches)
#endif
}
TEST(Lua, testFloatIntegerEquality)
{
// 0.5 is not an integer, so it must not equal 0 (regression #7587)
// both directions asserted explicitly so the intent is obvious at a glance
luaExecStr("if 0.5 == 0 then error('0.5 == 0') end");
luaExecStr("if not (0.5 ~= 0) then error('0.5 ~= 0') end");
luaExecStr("if 0.50 == 0 then error('0.50 == 0') end");
luaExecStr("if not (0.50 ~= 0) then error('0.50 ~= 0') end");
luaExecStr("if 0.50 == 0.0 then error('0.50 == 0.0') end");
// ... even when the value comes from a variable, as in the reported issue
luaExecStr("local v = 0.50; if v == 0 then error('v == 0') end");
luaExecStr("local v = 0.50; if not (v ~= 0) then error('v ~= 0') end");
// negative non-integral floats must not equal integers either
luaExecStr("if -0.5 == 0 then error('-0.5 == 0') end");
luaExecStr("if not (-0.5 ~= 0) then error('-0.5 ~= 0') end");
luaExecStr("if not (-0.5 < 0) then error('-0.5 < 0') end");
luaExecStr("if -0.5 > 0 then error('-0.5 > 0') end");
// integral floats still compare equal to their integer counterpart
luaExecStr("if 1.0 ~= 1 then error('1.0 ~= 1') end");
luaExecStr("if 0.0 ~= 0 then error('0.0 ~= 0') end");
luaExecStr("if -1.0 ~= -1 then error('-1.0 ~= -1') end");
// order comparisons on the same values must remain consistent
luaExecStr("if not (0.5 >= 0) then error('0.5 >= 0') end");
luaExecStr("if 0.5 <= 0 then error('0.5 <= 0') end");
luaExecStr("if not (0.5 > 0) then error('0.5 > 0') end");
luaExecStr("if 0.5 < 0 then error('0.5 < 0') end");
luaExecStr("if not (0.50 >= 0) then error('0.50 >= 0') end");
luaExecStr("if 0.50 <= 0 then error('0.50 <= 0') end");
luaExecStr("if not (1.0 >= 1) then error('1.0 >= 1') end");
luaExecStr("if not (1.0 <= 1) then error('1.0 <= 1') end");
luaExecStr("if not (0.0 >= 0) then error('0.0 >= 0') end");
luaExecStr("if not (0.0 <= 0) then error('0.0 <= 0') end");
// mixed arithmetic must still yield floats; the fix only affects equality
luaExecStr("if math.type(0.5 + 0) ~= 'float' then error('0.5 + 0') end");
luaExecStr("if math.type(1.0 + 1) ~= 'float' then error('1.0 + 1') end");
luaExecStr("if math.type(1 / 2) ~= 'float' then error('1 / 2') end");
luaExecStr("if math.type(7.5 % 2) ~= 'float' then error('7.5 % 2') end");
luaExecStr("if math.type(0.5 * 2) ~= 'float' then error('0.5 * 2') end");
}
TEST(Lua, testLegacyNames)
{
MODEL_RESET();
+1 -1
View File
@@ -401,7 +401,7 @@ int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) {
return 0; /* only numbers can be equal with different variants */
else { /* two numbers with different variants */
lua_Integer i1, i2; /* compare them as integers */
return (tointeger(t1, &i1) && tointeger(t2, &i2) && i1 == i2);
return (tointegerexact(t1, &i1) && tointegerexact(t2, &i2) && i1 == i2);
}
}
/* values have same type and same variant */
+9
View File
@@ -43,6 +43,15 @@
#define tointeger(o,i) \
(ttisinteger(o) ? (*(i) = ivalue(o), 1) : luaV_tointeger(o,i,LUA_FLOORN2I))
/* non-soft conversion: only integral values are converted.
** This is the strict semantic used by equality ('==' and '~='), where a
** non-integral float such as 0.5 must not compare equal to an integer.
** 'tointeger' (soft, LUA_FLOORN2I) is intentionally kept for API argument
** coercion so that EdgeTX API functions accept unrounded floats; do not
** switch this macro back to the soft conversion. */
#define tointegerexact(o,i) \
(ttisinteger(o) ? (*(i) = ivalue(o), 1) : luaV_tointeger(o,i,0))
#define intop(op,v1,v2) l_castU2S(l_castS2U(v1) op l_castS2U(v2))
#define luaV_rawequalobj(t1,t2) luaV_equalobj(NULL,t1,t2)