Whereas James England and I had been engaged on Dig Deep Health, we got here throughout a somewhat mysterious ColdFusion conduct. The native reminiscence leak detection mechanism began reporting the existence of an surprising variable known as, ___IMPLICITARRYSTRUCTVAR0
. I would by no means seen this earlier than; however Google pointed me to one thing Adam Cameron talked about it on an outdated Adobe ColdFusion discussion board publish from 2012. Apparently implicit struct and array notation has been creating these hidden variables since ColdFusion 9.
Demonstration of Variable Conduct
First, let’s check out what ColdFusion is doing. This conduct solely appears to manifest when the implicit struct or array notation is used 1) inside a Operate execution and a couple of) inside a ternary operator. As such, we will outline an immediately-invoked operate expression (IIFE) which executes two nonsense ternary operators. Then, we will output the variables
scope.
<cfscript>
(() => {
var arrayValue = false
? "yay"
: []
;
var structValue = false
? "yay"
: {}
;
for ( key in variables.keyArray() ) {
// Observe: wrapping output in array as a result of dumping-out a struct will disguise any
// key that accommodates the substring "___IMPLICITARRYSTRUCTVAR".
writeDump([ key, variables[ key ] ]);
}
})();
</cfscript>
After the 2 ternary operators are executed, I output the keys within the variables
scope. After I do that, I am wrapping the key-value pairs in an array since ColdFusion will actively disguise any struct entry during which the important thing accommodates the substring, ___IMPLICITARRYSTRUCTVAR
. That is in all probability why I’ve by no means seen this earlier than.
Once we run this Adobe ColdFusion 2023 code, we get the next output:
Discover that ColdFusion has created two hidden variables referring to the implicit information construction notation: ___IMPLICITARRYSTRUCTVAR0
and ___IMPLICITARRYSTRUCTVAR1
. These variables comprise the results of the implicit information construction expression execution.
These Variables Are Not Thread Protected
These implicit struct and implicit array variables are saved within the variables
scope. When that is completed inside a ColdFusion template or a ColdFusion customized tag, that is secure as a result of the variables
scope solely lasts so long as the template execution (kind of). However, when that is completed inside a endured ColdFusion element (CFC), it may possibly develop into an issue.
When a ColdFusion element is instantiated and cached for the lifetime of a ColdFusion utility, the variables
scope of stated element turns into a shared reminiscence house that may be accessed by parallel requests and parallel threads. This may create a harmful atmosphere in case you do not take precautions. And, it may possibly create an much more harmful atmosphere when you do not even know {that a} shared variable is being created behind the scenes (particularly one that’s actively hidden from CFDump
and WriteDump()
output).
Let’s check out how the damaging conduct can manifest. We will use the asynchronous iteration options of ColdFusion to launch quite a few parallel threads. These threads will then use implicit struct notation to outline and mutate a native variable:
<cfscript>
arrayNew( 1 )
// Create a group that's giant(ish).
.resize( 1000 )
.set( 1, 1000, 1 )
// Iterate over the gathering utilizing PARALLEL THREADS.
.every(
() => {
var worth = false
? "yay"
: { depend: 0 } // CAUTION: Creates a shared variable.
;
// Increment LOCAL worth.
worth.depend++;
},
true, // Parallel iteration.
20
)
;
// Output the personal web page variables.
for ( key in variables.keyArray() ) {
writeDump([ key, variables[ key ] ]);
}
</cfscript>
As you possibly can see, the worth
variable is asserted as native variable to the iteration operator, which ought to make it secure to subsequently mutate. Nevertheless, once we run this Adobe ColdFusion 2023 code, we get the next error:
As some level, in the course of the parallel iteration, we get the error Component COUNT is undefined in VALUE
. That is once we go to increment the worth.depend
key, which needs to be native to the iterator operate and due to this fact secure to mutate.
What I assume is occurring is that the outcomes of the ternary operator are being mechanised as sequence of assignments:
-
Create empty struct utilizing
___IMPLICITARRYSTRUCTVAR0
worth, saved within thevariables
scope. -
Append
depend:0
entry to___IMPLICITARRYSTRUCTVAR0
. -
Assign
___IMPLICITARRYSTRUCTVAR0
toworth
variable, saved within thenative
scope.
Any time you will have a multi-step course of that touches shared reminiscence, the method is inherently unsafe for parallel computing until locking precautions are utilized. After all, we did not know that this was taking place; so, we did not anticipate this code be unsafe.
Apart: even the
++
and--
operators are unsafe to make use of with regards to a shared reminiscence house.
What’s probably taking place is that simply earlier than one of many iterations goes to increment the .depend
key, a parallel iteration thread has simply overwritten the shared ___IMPLICITARRYSTRUCTVAR0
variable, thereby clobbering the .depend
key for the opposite thread.
To work round this bug, all it’s important to do is transfer the implicit struct expression out of the ternary operator. A technique to do this is to exchange the ternary operator with an if
/else
management move:
<cfscript>
arrayNew( 1 )
// Create a group that's giant(ish).
.resize( 1000 )
.set( 1, 1000, 1 )
// Iterate over the gathering utilizing PARALLEL THREADS.
.every(
() => {
// By shifting the implicit struct OUT of the ternary operator and into an
// if/else block, we take away the implicit variable creation.
if ( false ) {
var worth = "yay";
} else {
var worth = { depend: 0 };
}
// Increment LOCAL worth.
worth.depend++;
},
true,
20
)
;
// Output the personal web page variables.
for ( key in variables.keyArray() ) {
writeDump([ key, variables[ key ] ]);
}
</cfscript>
This time, once we execute this Adobe ColdFusion 2023 code, it executes with out error. And, the resultant web page is clean since no ___IMPLICITARRYSTRUCTVAR0
variable is created within the variables
scope.
Loopy stuff! I do not know if that is restricted to the ternary operator; however, it is the one place that I’ve seen this conduct present itself.
Wish to use code from this publish?
Take a look at the license.
https://bennadel.com/4748