Skip to main content
June 17, 2015
Question

for-in loop bug

  • June 17, 2015
  • 0 replies
  • 239 views

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.

    This topic has been closed for replies.