0 Replies Latest reply on Jun 17, 2015 3:35 AM by uncalc

    for-in loop bug

    uncalc

      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.