ID:2910985
 
Resolved
At some point, a change in the C libraries caused text2num() to parse "NaN", which was a change from previous versions. This has been deemed undesirable behavior, so text2num() will no longer parse NaN or infinity; it will return null in those cases like it used to.
BYOND Version:515.1630
Operating System:Windows 10 Pro 64-bit
Web Browser:Chrome 121.0.0.0
Applies to:Dream Daemon
Status: Resolved (515.1631)

This issue has been resolved.
Descriptive Problem Summary:
515 has changed the result of isnum() when processing not a number. In 514.1589 isnum would guard it at least in the scenario of text2num (but not necessarily in other cases). But now in 515.1610, 515.1630 and likely many other versions of 515, the behavior has regressed. Not a Number literally is not a number; that doesn't make it a number. I see no reason why this behavior should regress. If you do want to some reason accept NaN in 515 then you have isnan or testing against self to detect that and handle accordingly.

Numbered Steps to Reproduce Problem:
Update to 515.
Realize bad players are exploiting number inputs in your game by sending topics with nan.
Update your code to also guard via if(thing != thing) return

Code Snippet (if applicable) to Reproduce Problem:
var/one = text2num("nan")
var/two = text2num("NaN")
var/three = text2num("naN")
var/four = text2num("4")

world.log << isnum(one)
world.log << isnum(two)
world.log << isnum(three)
world.log << isnum(four)

world.log << (one != one)
world.log << (two != two)
world.log << (three != three)
world.log << (four != four)


Expected Results:
(514.1589)

0
0
0
1
0
0
0
0

The first 3 falses here are isnum returning false for nan.

Actual Results:
(515.1630)

1
1
1
1
1
1
1
0

The first 3 trues here are isnum returning true for NaN

Does the problem occur:
Every time? Or how often?
Yes
In other games?
Yes
In other user accounts?
Yes
On other computers?
Yes

When does the problem NOT occur?
514.1589

Did the problem NOT occur in any earlier versions? If so, what was the last version that worked? (Visit http://www.byond.com/download/build to download old versions for testing.)
514.1589

Workarounds:
Don't use 515 or guard it with a != check or maybe isnan check if you exclusively are on 515 (untested).

So there must be more going on here than you think, because the behavior of isnum() hasn't changed since 514. I just verified that by looking at the old code. If the value type is NUM_REF, isnum() returns true regardless of whether the float is NaN or not. This is intended behavior, and 515 gives us isnan() so you can check against NaN.

What remains an open question is whether text2num() and inputs are what changed, which should be testable via checking \ref and JSON results on the values you get.
Test the snippet on 514 vs 515 and you will get the results I provided.

var/nan = "nan"
var/four = "4"
world.log << "[nan] [\ref(nan)] [json_encode(nan)]"
world.log << "[four] [\ref(four)] [json_encode(four)]"

nan = text2num(nan)
four = text2num(four)
world.log << "[nan] [\ref(nan)] [json_encode(nan)]"
world.log << "[four] [\ref(four)] [json_encode(four)]"

world.log << "isnum? [isnum(nan)]"
world.log << "isnum? [isnum(four)]"

world.log << "!=self? [nan != nan]"
world.log << "!=self? [four != four]"


Welcome BYOND! (5.0 Public Version 514.1589)
Logging in...connected
Logged in as Drathek.
Connecting to file://Test.dmb...nan [0x600019e] "nan"
4 [0x600019f] "4"
[0x0] null
4 [0x6a800000] 4
isnum? 0
isnum? 1
!=self? 0
!=self? 0
connected

Welcome BYOND! (5.0 Beta Version 515.1630)
Logging in...
BYOND pager is offline. Connecting as Guest.
Connecting to file://Test.dmb...nan [0x60001a4] "nan"
4 [0x60001a5] "4"
nan [0x7fffffff] {"__number__":"NaN"}
4 [0x6a800000] 4
isnum? 1
isnum? 1
!=self? 1
!=self? 0
connected
Besides whatever this bug is, NaN is true for isnum anyways per BYOND's impl.
You want:
#define isnan(x) ( (x) != (x) )

Or,
/// Returns true if the number is infinity or -infinity
#define isinf(x) (isnum((x)) && (((x) == INFINITY) || ((x) == -INFINITY)))
/// NaN isn't a number, damn it. Infinity is a problem too.
#define isnum_safe(x) ( isnum((x)) && !isnan((x)) && !isinf((x)) ) //By ike709
Lummox JR resolved issue with message:
At some point, a change in the C libraries caused text2num() to parse "NaN", which was a change from previous versions. This has been deemed undesirable behavior, so text2num() will no longer parse NaN or infinity; it will return null in those cases like it used to.