jsonparser.gs expects "val" to be never used (leads into numbers being replaced by an unrelated String)

I'm tired : I just passed SIX hours trying to understand a bug with one of my several-includes-long script, before understanding it was from my json parser all along, based on a miniscript parser found on google.

... It seems that we're based on the same one because it shares 99% of the source, including the same bug, so I'll document it here just in case you get it one day :)
I can't really provide a minimal example for this one, but basically, the json parser can provide a glitched result based on some (unknown) use of a variable named "val" in the calling function

Result of the bug : If the parser is glitched, all numbers in the JSON will be parsed as the same (seemingly unrelated) String
As a secondary result, the same input can result into two different objects at two different point in a script's lifetime (really sneaky, right?)
In other words : 'toJSON(parse(input)) != input) because parse doesn't provide the expected JSON anymore

Reason of the bug : The 'problem' lies in _parseNumber, line 254 : 'result = val(self.source[startPos : self._p])', note that in this case val is not a method of String, like String.to_int
My calling script somehow redirected the 'val' standard call to a local variable named 'val'. A search-and-replace of all uses of "val" into "value" in my scripts fixed the JSON loading problem

How to avoid the bug :

  1. Make sure to never use a variable named 'val' anywhere just to be safe
  2. If a script is uber-critical, don't use numerical values in an object meant to be converted into JSON

How to correct the bug :
... Honestly, I don't know at this time.
A) I finally understood this bug when I replaced this unknown val call with a (str).to_int, but it breaks the compatibility for floating numbers...
Other UNTESTED ideas :
B) Maybe there's a way to avoid triggering it from function variables by using "globals.val(" ?
C) SAVING @val in the Parser object should avoid redirecting the variable during the lifespan of the script, but even that wouldn't save against a script highjacking the global variable before the json parser got included

In my case, it broke all my vulnerabilities saving system because
{"complete":1,"libName":"libssh.so","libVersion":"1.0.0","exploits":{"0x4696F4D9":[{"value":"minusb","result":"","conditions":[]},{"value":"trangeundostartion","result":"","conditions":[{"type":5}]}]}}'
became
{"complete":"minusb","libName":"libssh.so","libVersion":"1.0.0","exploits":{"0x4696F4D9":[{"value":"minusb","result":"","conditions":[]},{"value":"trangeundostartion","result":"","conditions":[{"type":"minusb"}]}]}}
because the memory VALue of my first exploit was stored in "val" before calling the toJSON method

[EDIT] Minimal example ( complete src file ):

  1. Copy jsonparser.gs (we'll name it "wtfjson.src")
  2. Add a bit of code at the end to allow to run the test

JSONbreaker = function()
json = "{""numeric"":5}"
print(toJSON(parse(json),true))
val = "wtf"
print(toJSON(parse(json),true))
end function
JSONbreaker()

  1. Run "build wtfjson.src /bin/" then "wtfjson"
    Console output :
    Unit testing : json
    All tests passed. Huzzah!
    {"numeric":5}
    {"numeric":"wtf"}

Note that this test did NOT use the preprocessor

Modification effectuée par LaplongeJunior