Hello,
I tried to add this as a bug to the Coldfusion Bug tracker (https://bugbase.adobe.com/) but ironically, I get a default Coldfusion error page when I log in.
I believe there is a serious bug with the for-in construct when used in a particular fashion. In particular, if the "in" expression is a function call, it appears that the function is invoked multiple times (to be precise, it always appears to be 5 times).
Clearly there are many situations where this could have serious consequences, not least if the function does any serious work.
Key points:
- Tested on Coldfusion 10 update 16
- Using a for-in construct where the "in" expression invokes a function results in that function being invoked multiple times.
- It doesn't seem to matter what the function returns (e.g. struct, array, potentially other iterables)
Workaround:
- Assign the result of the function call to a local variable outside the for-in construct
Severity:
This a serious issue as,
- It is easy to cause using a common idiom
- It is completed unexpected
- The fact that it is happening is essentially invisible to the developer
- The results are potentially very serious
Speculation:
I speculate that the code is pre-processed into a construct that does (in clause).size() (in clause).iterator(), etc
Test Case:
See below for some code which tests this:
component displayname="ForInTest" { ForInTest function init() { variables.count = 0; return this; } void function test1() { variables.count = 0; for( var item in getArray() ) { // do something interesting } if( variables.count==1 ) { writeoutput( "getArray() was called once." ); } else { writeoutput( "getArray() was called multiple times! (" & variables.count & ")" ); } } void function test2() { variables.count = 0; var items = getArray(); for( var item in items ) { // do something interesting } if( variables.count==1 ) { writeoutput( "getArray() was called once." ); } else { writeoutput( "getArray() was called multiple times! (" & variables.count & ")" ); } } private array function getArray() { variables.count++; var data = [1,2,3]; return data; } }
var test = new ForInTest(); test.test1(); test.test2();
Output:
getArray() was called multiple times! (5) getArray() was called once.