views:

245

answers:

2

We've run into a serious issue with CF9 wherein values for certain struct keys can be referenced by other keys, despite those other keys never being set. See the following examples:

Edit: Looks like it isn't just something our servers ate. This is Adobe bug-track ticket 81884: http://cfbugs.adobe.com/cfbugreport/flexbugui/cfbugtracker/main.html#bugId=81884.

Edit: As has been pointed out, Adobe put out the fix: http://kb2.adobe.com/cps/825/cpsid_82547.html

The hotfix summary notes that they were comparing the hash values of variable names instead of the literal value, for speed. I don't know how that would speed anything up, but the chance for name collisions (especially on shorter names) should have been obvious. At least they were fairly quick to correct.

<cfset a = { AO = "foo" } />
<cfset b = { AO = "foo", B0 = "bar" } />

<cfoutput>
The following should throw an error. Instead both keys refer to the same value.
<br />Struct a: <cfdump var="#a#" />
<br />a.AO: #a.AO#
<br />a.B0: #a.B0#
<hr />
The following should show a struct with 2 distinct keys and values. Instead it contains a single key, "AO", with a value of "bar".
<br />Struct b: <cfdump var="#b#" />

This is obviously a complete show-stopper for us. I'd be curious to know if anyone has encountered this or can reproduce this in their environment. For us, it happens 100% of the time on Apache/CF9 running on Linux, both RH4 and RH5. We're using the default JRun install on Java 1.6.0_14.

To see the extent of the problem, we ran a quick loop to find other naming sequences that are affected and found hundreds of matches for 2 letter key names. A similar loop found more conflicts in 3 letter names.

<cfoutput>Testing a range of affected key combinations. This found hundreds of cases on our platform. Aborting after 50 here.</cfoutput>
<cfscript>
teststring = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
stringlen = len(teststring);
matchesfound = 0;
matches = "";

for (i1 = 1; i1 <= stringlen; i1++) {
    symbol1 = mid(teststring, i1, 1);
    for (i2 = 1; i2 <= stringlen; i2++) {
        teststruct = structnew();
        symbol2 = mid(teststring, i2, 1);
        symbolwhole = symbol1 & symbol2;
        teststruct[ symbolwhole ] = "a string";

        for (q1 = 1; q1 <= stringlen; q1++) {
            innersymbol1 = mid(teststring, q1, 1);
            for (q2 = 1; q2 <= stringlen; q2++) {
                innersymbol2 = mid(teststring, q2, 1);
                innersymbolwhole = innersymbol1 & innersymbol2;
                if ((i1 != q1 || i2 != q2) && structkeyexists(teststruct, innersymbolwhole)) {
                    // another affected pair of keys!
                    writeoutput ("<br />#symbolwhole# = #innersymbolwhole#");
                    if (matchesfound++ > 50) {
                        // we've seen enough
                        abort;
                    }
                }
            }
        }
    }
}
</cfscript>

And edit again: This doesn't just affect struct keys but names in the variables scope as well. At least the variables scope has the presence of mind to throw an error, "can't load a null":

<cfset test_b0 = "foo" />
<cfset test_ao = "bar" />
<cfoutput>
test_b0: #test_b0#
<br />test_ao: #test_ao#
</cfoutput>
+6  A: 

UPDATE: HOTFIX RELEASED: http://kb2.adobe.com/cps/825/cpsid_82547.html

I think yes, this is a bug, but here's an emergency workaround:

<cfset a = createObject("java", "java.util.HashMap").init()>
<cfset structInsert(a, "AO", "foo") />

<cfset b = createObject("java", "java.util.HashMap").init()>
<cfset structInsert(b,"AO", "foo") />
<cfset structInsert(b,"B0", "bar") />

<cfoutput>
The following should throw an error. Instead both keys refer to the same value.
<br />Struct a: <cfdump var="#a#" />
<br />a.AO: #a.AO#
<br />a.B0: #a.B0#
<hr />

The following should show a struct with 2 distinct keys and values. Instead it contains a single key, "AO", with a value of "bar".
<br />Struct b: <cfdump var="#b#" />
</cfoutput>

Since a struct is a HashMap, you can still use all the struct functions in CF.

Meanwhile, please file the bug at: http://cfbugs.adobe.com/cfbugreport/flexbugui/cfbugtracker/main.html

Henry
Thanks Henry. I suspected dropping to the java layer might work, but we're hoping to migrate some big old monsters from CF8 with minimal refactoring.The bug report is here: http://cfbugs.adobe.com/cfbugreport/flexbugui/cfbugtracker/main.html#bugId=81884When I entered that I hadn't realized that someone at Adobe picked up the report I made on some other entry form and put it into the bug-tracker. So there are actually 2 tickets that they can hopefully merge.
Gin Doe
Confirmed. It works for me.
johncblandii
Just curious, why HashMap over Hashtable?
Leigh
@Leigh, I don't know know what answer you want. You can google for their difference. Adobe chose HashMap to represent Struct in ColdFusion, so I used that in the workaround.
Henry
Where did you see HashMap? The docs just list the interface (Map), not the concrete class. Though it used to be Hashtable.http://help.adobe.com/en_US/ColdFusion/9.0/Developing/WSc3ff6d0ea77859461172e0811cbec22c24-7884.html
Leigh
@Leigh, ok, maybe you're right. I guess they use some variant of HashMap, not java.util.HashMap exactly.
Henry
Okay. I was just curious. Given the choice of Vectors for Arrays, I wondered if Hashtables were a safer choice. Though perhaps any synchronization issues are already handled by CF internally and it is a non-issue.
Leigh
HOTFIX RELEAESD! http://kb2.adobe.com/cps/825/cpsid_82547.html
Henry
A: 

What I found even more peculiar is that this works:

<cfset b = { AO = "foo", BO = "bar"} />
Scott Stroz
what so peculiar about it?
Henry
Scott Stroz