Showing posts with label ColdFusion 2021. Show all posts
Showing posts with label ColdFusion 2021. Show all posts

Tuesday 18 May 2021

I play the game "how long will it take me to find a new bug in ColdFusion" again, after a few years

G'day:

Answer: about two minutes to guess what would likely be broken, and I think I had an initial repro created in another minute after that.

Last time I tried this it took 44min: "ColdFusion bug challenge: how quickly can one find a bug in ColdFusion 11?".

This time I figured "ah what's a language feature in CF2021? I reckon anything more than superficial use of one of those will break. Um… the rest operator. I bet it can't handle type-checking properly". Actually that didn't even take two minutes to type, but it was about how long I thought about it. So: given I was actually right about that guess, it took me - what - 20seconds? I'm not claiming to be smart or anything here. It's just so frickin easy to find things wrong with CFML that that is as long as it might take.

For context, here's the rest operator in action in a simple situation:

function untypedVariadicArguments(string s, ...x) {
    return arguments
}
result = untypedVariadicArguments("some string", 1, "two", ["three"])

writeDump(result)

The rest operator enables one to define variadic functions: ones that can take any number of arguments. Of course CFML already supported this: you can pass whatever you like to a UDF / method, and all the values will be there in the arguments scope, whether you specify them in the function signature or not. The difference is that in a variadic function, all the trailing arguments are put in the same one parameter value as an array. The output of above is:

 


 That is working properly.

The bug comes in when I try to type-check the that x parameter, eg: it can have any number of x values but they all need to be numbers. I would expect the syntax to be like this:

function typedVariadicArguments(string s, numeric ...x) {
    return arguments
}

In most curly-brace languages I can find that do type-checked variadic functions, the type declaration is done before the parameter declaration (irrespective of whether the parameter syntax is ...paramName or paramName..., as that can vary). See the examples on that page on Wikipedia I link to above on variadic functions. If I run that code in ColdFusion though, I get this:

Invalid CFML construct found on line 2 at column 52. on line 2

(Ha, by the by I also just found a wee bug in Lucee. Lucee does not support the rest operation, and when I accidentally tried to run this on Lucee cos I was not paying attention to what I was doing on trycf.com, it errored with "invalid argument definition on line 2": it's a parameter not an argument. The parameter is the definition. The argument is the value you pass)

So I went "OK well there's a good chance they just did it wrong with ColdFusion", so I tried it like this:

function typedVariadicArguments(string s, ...numeric x) {
    return arguments
}

Now that at least compiled, however it seems to be completely ignoring the rest operator. I'm testing it with the same test code as above:

result = typedVariadicArguments("some string", 1, "two", ["three"])

writeDump(result)

This is how one would expect it to work with just a signature like this:

function typedVariadicArguments(string s, numeric x) {
    return arguments
}

ColdFusion really ought not be going "buggered if I know what those dots are doing there: I'll just ignore them". Note that is understanding that as the rest operator. If you try two dots or four dots, you'll get a compile error.

I'm going with two bugs here, actually:

  • An implementation omission in that numeric ...x should work. That's the syntax they should have used, and it's not valid to not implement the type check there.
  • ColdFusion should not be ignoring th rest operator in a method signature if it doesn't know what to do with it. It should error.
  • OK a third bug I think. It'll allow the rest operator on the non-last parameter without erroring (untypedVariadicArguments(...s, x)): it doesn't work, but again it just ignores it.

I'm gonna stop looking now.

Am I missing something? There are all bugs right? I'm not getting something wrong?

Righto.

--
Adam