Opened 13 years ago

Closed 13 years ago

#1124 closed defect (fixed)

"Maximum call stack size exceeded" error on Safari 2.0.4 & Dojo 0.3.1

Reported by: guest Owned by: alex
Priority: high Milestone: 0.9
Component: Parser Version: 0.3
Keywords: Cc:
Blocked By: Blocking:

Description

I get the error, "Maximum call stack size exceeded @ line 64" in Safari when i open up my example page.

On initial inspection, it seems to be related to the use of the nested tables and other elements in the page (since if i remove them, the error is no longer reported and dojo works).

Of course, i'm no javascript / dojo guru, so i have not been able to debug this any further.

Example page code:

<html>

<script type="text/javascript" src="./dojo.js"></script>
<script type="text/javascript">
	//dojo.require("dojo.io.*");
	//dojo.require("dojo.widget.Editor2");
	//dojo.require("dojo.widget.*");
	dojo.require("dojo.widget.InlineEditBox");
	dojo.require("dojo.event.*"); 
	
	function saveHandler(newValue, oldValue) {
		dojo.debug("New Value: " + newValue + " Old Value: " + oldValue);
	}

	function init() {
		var editable = dojo.widget.byId("dialog1");
		editable.onSave = saveHandler;
		editable = dojo.widget.byId("dialog2");
		editable.onSave = saveHandler;
		editable = dojo.widget.byId("dialog3");
		editable.onSave = saveHandler;
		editable = dojo.widget.byId("dialog4");
		editable.onSave = saveHandler;
		editable = dojo.widget.byId("dialog5");
		editable.onSave = saveHandler;
		editable = dojo.widget.byId("dialog6");
		editable.onSave = saveHandler;
	}

	dojo.addOnLoad(init)
	
</script>

<head>
<link rel="stylesheet" href="stripstyle.css" type="text/css" /></head>
<title>Testing Canvas</title>
</head>
<body>

<!-- begin comic -->
	<table border="0" width="774" ID="comicborder" cellspacing="0" cellpadding="0" align="center" bgcolor="#000000">
	
	<!-- 7px gap -->

	<tr> <td height="7"> </td></tr>
	
	<tr><td>
	    <!-- Nested table -->
		<table border="0" width="100%" cellpadding="2" cellspacing="2">
		<tr><td valign="middle">
		<table width=100%>
		<tr><td><font color="#ffffff" face="arial"><b><a href="about:blank" style="color: white; text-decoration: none" title="">Test. Test</a> <font color="black"></font></b></font></td><td align="right"><font color="white" face="arial" size="2"><b>by <a href="about:blank" style="color: white; text-decoration: none">test</a><br />7-07-06</b></font></td></td></tr></table></tr>

		</table>
	</td></tr>
	
	<!--Panels -->
	<tr><td>
		<table width="100%" border="0" cellspacing="7" cellpadding="0" align="center">
		<tr bgcolor="#ffffff" height="320">
		
		<!-- Panel 1 -->
		<td id="panel1" height="100%" valign="top" bgcolor="" background="none.jpg">
			<!-- Nested table (panel 1) -->

			<table cellpadding="0" id="panel1inside" cellspacing="0" border="0" width="250" height="100%">
	
			<!-- narration begin -->
	
			<tr><td colspan="2" id="nar1td" background="yellow.gif"  style="visibility: hidden" height="1" style="height: 1px;" valign="top">
				<!-- Nested table for narration -->
				<table cellpadding="0" cellspacing="2" border="0">
				<tr><td><font face="arial" size="2"><b><span id="nar1"></span></b></font></td></tr>
				</table>
			</td></tr>
			
			<!-- Narration end border -->

			<tr style="height: 2px"><td colspan="2" id="nar1border" background="black.gif" height="2" style="visibility: hidden">
			</td></tr>
	
			<!-- narration end -->
	
			<!-- Begin slots -->
			<tr>
			<!-- First Balloon -->
			<td width="50%" valign="bottom">
				<!-- Nested balloon -->
				<div id="dialogballoon1" style="visibility: visible">

					<!-- Nested table for padding -->
					<table cellpadding="1" cellspacing="0" border="0" style="margin-left:auto; margin-right:auto; text-align: center;">
					<tr><td>
						<!-- Nested table in balloon -->
						<table cellpadding="0" cellspacing="0" border="0" id="dialog1table" style="vertical-align: middle;margin-left:auto; margin-right:auto; text-align: center;">
						<!-- Top of baloon -->
						<tr><td valign="center"><img src="upperleftcorner.gif" alt="" width="6" height="6" border="0" /></td><td class="btop"></td><td><img src="upperrightcorner.gif" alt="" width="6" height="6" border="0" /></td></tr>
						<!-- Middle of balloon (including text) -->
						<tr><td class="bleftside"></td><td background="_white.gif" style="text-align: center;">

						<span style="font-family: arial; font-size: 12px"><b><span id="dialog1" dojotype="inlineEditBox">Dialog 1</span></b></span>
						</td><td class="brightside"></td></tr>
						<!-- Bottom of balloon -->
						<tr><td><img src="lowerleftcorner.gif" alt="" width="6" height="6" border="0" /></td><td class="bbottom"></td><td><img src="lowerrightcorner.gif" alt="" width="6" height="6" border="0" /></td></tr>
						</table>
					</td></tr>
					</table>
					
					<!-- Balloon tail -->

					<div style="text-align: center;">
					<img name="dtail1" id="dtail1" src="thought-left.gif" border="0" alt="" />
					</div>
				</div>
				
				<!-- Character graphic, no alignment -->
				<img src="squirrel2-1.gif" ID="char1" name="char1" border="0" alt="" />
			</td>
		
			<!-- Second Balloon -->
			<td width="50%" valign="bottom">

				<div id="dialogballoon2" style="visibility: hidden">
					<table cellpadding="1" cellspacing="0" border="0" style="margin-left:auto; margin-right:auto;">
					<tr><td>
						<table cellpadding="0" cellspacing="0" border="0" id="dialog2table" style="margin-left:auto; margin-right:auto;">
						<!-- Top of baloon -->
						<tr><td><img src="upperleftcorner.gif" alt="" width="6" height="6" border="0" /></td><td class="btop"></td><td><img src="upperrightcorner.gif" alt="" width="6" height="6" border="0" /></td></tr>
						<!-- Middle of balloon (including text) -->
						<tr><td class="bleftside"></td><td bgcolor="#ffffff" align="center">
						<b><span id="dialog2" style="font-family: arial; font-size: 12px" dojotype="inlineEditBox">Dialog 2</span></b>

						</td><td class="brightside"></td></tr>
						<!-- Bottom of balloon -->
						<tr><td><img src="lowerleftcorner.gif" alt="" width="6" height="6" border="0" /></td><td class="bbottom"></td><td><img src="lowerrightcorner.gif" alt="" width="6" height="6" border="0" /></td></tr>
						</table>
					</td></tr>
					</table>
					
					<!-- Balloon tail -->
					<div style="text-align: center;">
					<img name="dtail2" id="dtail2"  src="dialog-right.gif" border="0" alt="" />

					</div>
				</div>
				
				<!-- Character graphic, aligned to right -->
				<div align="right">
					<img src="big-gabe1.gif" id="char2" name="char2" border="0" alt="" />
				</div>
			</td></tr> <!-- End slots -->  
			</table>
			<!-- End of panel 1 nested table -->

		</td>
	
</tr> <!-- End of strip -->
	</table>


<h1 id="editable" dojoType="inlineEditBox">Edit me - I will trigger a custom onSave Handler</h1>

</body>
</html>

Change History (14)

comment:1 Changed 13 years ago by scott.severtson@…

Component: GeneralWidgets
Owner: changed from anonymous to bill
Priority: normalhigh
severity: normalmajor
Version: 0.20.3

We're also seeing this issue in Dojo 0.31/Safari 2.0.4, in widget/Parse.js:64:

if ((frag)&&(typeof frag == "object")&&(frag!=fragment.nodeRef)&&(frag!=fragment["tagName"])){
	comps = comps.concat(this.createComponents(frag, parentComp));
}

This does not occur on every page, only if more than 4 levels of nested tables are present. Hope this helps!

comment:2 Changed 13 years ago by dylan

Milestone: 0.5

comment:3 Changed 13 years ago by dylan

Milestone: 0.50.4
Owner: changed from bill to alex
severity: majorblocker

I saw this today myself... bumping priority as it completely breaks dojo in safari.

comment:4 Changed 13 years ago by dylan

The obvious workaround is:

parseWidgets: false, parseIds: ["blah", "zed", "blarp"]

comment:5 Changed 13 years ago by Tom Trenka

Owner: changed from alex to Adam Peller

I'm reassigning to Adam; looking through the parse code it looks like it's related to the Namespace changes made recently.

comment:6 Changed 13 years ago by Tom Trenka

Doing some tracing, it looks like the problem is related to attempting to load widgets when they are recognized the first time by the parser.

comment:7 Changed 13 years ago by James Burke

FWIW, I've seen this error in Safari with the xdomain loading for this test:

http://archive.dojotoolkit.org/nightly/tests/xdomain/test_xdomainTooltip.html

I kept meaning to ask some sort of Safari list to see what it means (or how to get around it) -- I think it just means the nesting of function calls in some of our javascript goes so deep that Safari just freaks out. I could see that being the case in xdomain loading, where instead of doing eval on the package contents (as is the case for normal, synchronous XHR loading), I'm waiting until all package files are loaded, and calling functions that define each package.

For xdomain loading, I think I can fix it I think by calling eval for all the package contents, but it seemed less efficient, since I already wrapped the package definitions in a function.

comment:8 Changed 13 years ago by Adam Peller

Here's some more info: http://www.nabble.com/Debugging-a-(JavaScript)-%22Maximum-call-stack-size-exceeded%22-exception-t1910546.html

As we suspected, is sounds like KHTML just has a tiny stack compared to Firefox, so what we're looking at just might be a matter of code that's less than optimal hitting the ceiling. It sounds inevitable that Safari will need to just make their stack bigger. Perhaps we can tune around this in the meantime.

Unfortunately, Drosera doesn't let you catch exceptions, so I'm unable to get any useful diagnostics there. Does anyone know where the recursion is and how one might tune this or locate it in Venkman on FF?

comment:9 Changed 13 years ago by Adam Peller

I take it back. Apparently you can catch an exception in Drosera. If you run in Drosera, you will see a single item on the call stack after the exception occurs. Hit step into a couple of times and then it will show you a stack with nearly 100 items (this is the limit in Safari)

It would seem that in this example, the code is boucing back and forth between lines 70 and 83 (createComponents and createSubComponents) over 90 times. Without a better understanding of the code or the parse tree that was built, it's hard to tell if this is an infinite loop or just a really deep tree (or why it would be such a deep tree) It is at least possible that the code is doing the right thing and Safari just isn't giving it enough memory. I'll have to see if I can compare this example against a run in FF.

comment:10 Changed 13 years ago by Adam Peller

Ok, looking at the nodes visited it does seem to reflect the document somewhat (though it's hard to follow) Preliminary debug statements show us to be ~43 nested nodes deep in the document, which is possible given the nested table structure. Sooo... 43*2 plus maybe a dozen lines of bootstrapping gets you awful close to the Safari stack limit of 100. It would seem the parser is working as advertised and we just don't have enough memory to process. Safari really ought to up the limit, but aside from that it seems we could:

a) rework the parser not to be recursive b) put in some recursion limit to stop before Safari's limit to avoid blowing the stack, but the document wouldn't get fully parsed (a kludge of questionable value) c) some other workaround I cannot think of d) document this as a Safari (KHTML?) limitation

Any other ideas?

At least I think I can document this well enough such that we can compare other rumored problems against this stack trace and see if they're truly related. It's possible we have deep recursion elsewhere in the codebase as well.

comment:11 Changed 13 years ago by dylan

Milestone: 0.40.5

hard to fix, not common, workaround exists, though painful. Pushing to 0.5

comment:12 Changed 13 years ago by Adam Peller

see #1852

comment:13 Changed 13 years ago by Adam Peller

Component: WidgetsParser
Owner: changed from Adam Peller to alex
severity: blockercritical

Back to Alex

comment:14 Changed 13 years ago by bill

Resolution: fixed
Status: newclosed

The new dijit architecture makes this not a bug (since we are using dojo.query()). Please reopen if still an issue with Dojo 0.9 and with the latest webkit safari (not safari 2.0.4; we aren't supporting that)

Note: See TracTickets for help on using tickets.