Skip to main content
April 16, 2010
Answered

Looping array frequently goes out of bounds

  • April 16, 2010
  • 1 reply
  • 3534 views

Hello all,

I have a process which pulls information from a database, converts the data into an array, in which every element contains a structure with two keys (name and value). That information is then processed and returned to another system. The problem is, often times when looping over the array that contains the structures, the loop will go out of bounds and attempt to access array elements that do not exist. Further more, sometimes either the "name" or "value" key will be blank. I currently am unaware of any pattern to this behavior.

<!--- Get all the data for the given PID (an ID number associated to a contact) --->
<cfquery name="Login" datasource="WebServer" maxrows="1">
     Select *
     From SFContactSync
     Where PID = <cfqueryparam cfsqltype="cf_sql_integer" value="#form.PID#">
</cfquery>

<!--- Assign All the information from the login query into variables we can return --->
<cfloop list="#Login.columnList#" index="columnName">
     <cfset counter = counter + 1>
     <cfset VariablesObject[counter] = structnew()>
     <cfset VariablesObject[counter]["Name"] = columnName>
     <cfset VariablesObject[counter]["Value"] = #Login[columnName][1]#>
</cfloop>

<!--- Create one more entry that contains the full name of the person --->
<cfset counter = counter + 1>
<cfset VariablesObject[counter] = structnew()>
<cfset VariablesObject[counter]["Name"] = "FullName">
<cfset VariablesObject[counter]["Value"] = "#Login.Firstname# #Login.Lastname#">

<!--- Set the next page to go to --->
<cfset nextPage = "/15">

<cfset ReturnObject = server.IVRUtilities.printMessage(nextPage,VariablesObject)>     
     

<!--- Function for creating return AngelXML --->     
<cffunction name="printMessage" access="remote" hint="Print a message for the Angel IVR System">
     <cfargument name="address" default="none" type="string">
     <!--- This is an array of structures, with keys "name" and "value" --->
     <!--- EX variables[1].Name = Gender --->
     <!--- EX variables[1].Value = Male --->
     <cfargument name="variablesToInclude" default="" type="any" required="no">
     <cfargument name="promptText" default="." type="string" required="no">
     <cfoutput>
          <cfsavecontent variable="ReturnMessage">
               <ANGELXML>
                    <MESSAGE>
                         <PLAY>
                              <PROMPT type="text">
                                   <cfoutput>#arguments.promptText#</cfoutput>
                              </PROMPT>
                         </PLAY>
                         <GOTO destination="#listlast(address)#" />
                    </MESSAGE>
                    <cfif IsArray(arguments.variablesToInclude)>
                         <VARIABLES>
                              <cftry>
                                   <cfloop from="1" to="#arraylen(arguments.variablesToInclude)#" index="i">
                                        <cfif structkeyexists(arguments.variablesToInclude,'Name') and  structkeyexists(arguments.variablesToInclude,'value')>
                                             <VAR name="#ucase(arguments.variablesToInclude['Name'])#" value="#ucase(arguments.variablesToInclude['Value'])#" />
                                        </cfif>
                                   </cfloop>
                                   <cfcatch type="any">
                                        <cfset ErrorData = structnew()>
                                        <cfset ErrorData.Error = cfcatch>
                                        <cfset ErrorData.Arguments = arguments>
                                        <cfset ErrorData.form = form>
                                        <cfset SendError = server.utilities.SendErrorReport(ErrorData)>
                                   </cfcatch>
                              </cftry>     
                         </VARIABLES>
                    </cfif>     
                    </ANGELXML>
          </cfsavecontent>
     </cfoutput>
     
     <cfreturn ReturnMessage>
</cffunction>

For example, I have an error sitting in my inbox now that says

The element at position 25 cannot be found.

But viewing the dump of the included elements shows only 24 elements. For some reason the loop here

<cfloop from="1" to="#arraylen(arguments.variablesToInclude)#" index="i">
     <cfif structkeyexists(arguments.variablesToInclude,'Name') and  structkeyexists(arguments.variablesToInclude,'value')>
          <VAR name="#ucase(arguments.variablesToInclude['Name'])#" value="#ucase(arguments.variablesToInclude['Value'])#" />
     </cfif>
</cfloop>

does seem to stop at the right point. The cfif statment would error, becuase it tries to evaluate an array element that does not exist. Whats up with that?

I was thinking of adding more checking to see if the array element exsists, but I am hesitant to add any more "checking" code than I really need beucase this is a somewhat high performance critical app. Any thoughts or comments are welcome.

This topic has been closed for replies.
Correct answer yui8979

Wow, it gets weirder. I just got an error report, it tried to access element 17, even though there was only one argument. Am I maybe dealing with variable scope issue here?

An error has occurred in a Cold Fusion page template. All the information available is included below. Please note that not all included data may be relevent, but is included for completness sake.

Error Info

struct

ARGUMENTS

struct

ADDRESS

/140

PROMPTTEXT

.

VARIABLESTOINCLUDE

array

1

struct

NAME

ID

VALUE

081FAFF5-C299-2427-53D7A6720B424A41

ERROR

struct

Detail

[empty     string]

ErrNumber

0

Message

The     element at position 17 cannot be found.

StackTrace

coldfusion.runtime.CfJspPage$ArrayBoundException:     The element at position 17 cannot be found. at     coldfusion.runtime.CfJspPage.ArrayGetAt(CfJspPage.java:869) at     coldfusion.runtime.CfJspPage._arrayGetAt(CfJspPage.java:930) at     coldfusion.runtime.CfJspPage._arrayGetAt(CfJspPage.java:925) at     cfutilities2ecfc868057140$funcPRINTMESSAGE.runFunction(C:\Website\Components\IVR\utilities.cfc:130)     at coldfusion.runtime.UDFMethod.invoke(UDFMethod.java:418) at     coldfusion.runtime.UDFMethod$ArgumentCollectionFilter.invoke(UDFMethod.java:324)     at     coldfusion.filter.FunctionAccessFilter.invoke(FunctionAccessFilter.java:59)     at coldfusion.runtime.UDFMethod.runFilterChain(UDFMethod.java:277) at     coldfusion.runtime.UDFMethod.invoke(UDFMethod.java:192) at     coldfusion.runtime.TemplateProxy.invoke(TemplateProxy.java:448) at     coldfusion.runtime.TemplateProxy.invoke(TemplateProxy.java:308) at     coldfusion.runtime.CfJspPage._invoke(CfJspPage.java:2272) at     cfLogcallNew2ecfm465243765.runPage(C:\Website\Portal\IVR\LogcallNew.cfm:46)     at coldfusion.runtime.CfJspPage.invoke(CfJspPage.java:196) at     coldfusion.tagext.lang.IncludeTag.doStartTag(IncludeTag.java:370) at     coldfusion.filter.CfincludeFilter.invoke(CfincludeFilter.java:65) at     coldfusion.filter.ApplicationFilter.invoke(ApplicationFilter.java:279) at     coldfusion.filter.RequestMonitorFilter.invoke(RequestMonitorFilter.java:48)     at coldfusion.filter.MonitoringFilter.invoke(MonitoringFilter.java:40) at coldfusion.filter.PathFilter.invoke(PathFilter.java:86)     at coldfusion.filter.ExceptionFilter.invoke(ExceptionFilter.java:70) at     coldfusion.filter.ClientScopePersistenceFilter.invoke(ClientScopePersistenceFilter.java:28)     at coldfusion.filter.BrowserFilter.invoke(BrowserFilter.java:38) at     coldfusion.filter.NoCacheFilter.invoke(NoCacheFilter.java:46) at     coldfusion.filter.GlobalsFilter.invoke(GlobalsFilter.java:38) at     coldfusion.filter.DatasourceFilter.invoke(DatasourceFilter.java:22) at     coldfusion.CfmServlet.service(CfmServlet.java:175) at     coldfusion.bootstrap.BootstrapServlet.service(BootstrapServlet.java:89) at     jrun.servlet.FilterChain.doFilter(FilterChain.java:86) at     coldfusion.monitor.event.MonitoringServletFilter.doFilter(MonitoringServletFilter.java:42)     at coldfusion.bootstrap.BootstrapFilter.doFilter(BootstrapFilter.java:46)     at jrun.servlet.FilterChain.doFilter(FilterChain.java:94) at     jrun.servlet.FilterChain.service(FilterChain.java:101) at     jrun.servlet.ServletInvoker.invoke(ServletInvoker.java:106) at jrun.servlet.JRunInvokerChain.invokeNext(JRunInvokerChain.java:42)     at     jrun.servlet.JRunRequestDispatcher.invoke(JRunRequestDispatcher.java:286)     at     jrun.servlet.ServletEngineService.dispatch(ServletEngineService.java:543)     at jrun.servlet.jrpp.JRunProxyService.invokeRunnable(JRunProxyService.java:203)     at     jrunx.scheduler.ThreadPool$DownstreamMetrics.invokeRunnable(ThreadPool.java:320)     at     jrunx.scheduler.ThreadPool$ThreadThrottle.invokeRunnable(ThreadPool.java:428)     at jrunx.scheduler.ThreadPool$UpstreamMetrics.invokeRunnable(ThreadPool.java:266)     at jrunx.scheduler.WorkerThread.run(WorkerThread.java:66)

TagContext

array

1

struct

COLUMN

0

ID

??

LINE

130

RAW_TRACE

at         cfutilities2ecfc868057140$funcPRINTMESSAGE.runFunction(C:\Website\Components\IVR\utilities.cfc:130)

TEMPLATE

C:\Website\Components\IVR\utilities.cfc

TYPE

CFML

2

struct

COLUMN

0

ID

CF_TEMPLATEPROXY

LINE

46

RAW_TRACE

at         cfLogcallNew2ecfm465243765.runPage(C:\Website\Portal\IVR\LogcallNew.cfm:46)

TEMPLATE

C:\Website\Portal\IVR\LogcallNew.cfm

TYPE

CFML

Type

Expression

aDimension

-1

aIndex

17

FORM

struct

CONTACTATTEMPT

1

DATESTAMP

{ts     '2010-04-16 14:36:54'}

ID

081FAFF5-C299-2427-53D7A6720B424A41

Subject

Error   in template


You might be on to something there ... your function is Server scoped? you

need to var scope the variables in your cfffunction for them to be trully

local

<cfset var x = "">

<cfset var ReturnMessage = "">

etc.

1 reply

Inspiring
April 16, 2010

Look's like a case of overengineering.  What do you think you can accomplish with an array of structures that you can't accomplish with the initial query?

April 16, 2010

Mostly the fact that I wanted that function to be reuseable, there are several occasions where I need to create the AngelXML data, and I don't know ahead of time what kind of data I am going to be passing, if any. The array of structures gives me the flexibility to pass it any kind of data. Sometimes i need to populate it from a query, other times I pass it just a hard coded ID.

April 16, 2010
Please download the attached file to view this post