edbrowse-dev - development list for edbrowse
 help / color / mirror / Atom feed
* [Edbrowse-dev] Garbage Collection and Boom
@ 2017-07-15 17:03 Karl Dahlke
  0 siblings, 0 replies; only message in thread
From: Karl Dahlke @ 2017-07-15 17:03 UTC (permalink / raw)
  To: Edbrowse-dev

[-- Attachment #1: Type: text/plain, Size: 5023 bytes --]

Ok, this is a long explanation of what I think is happening, and a reason for the increased fragility of duktape over moz.

On the duktape branch, look at jseng-duk.c.
At line 1696, just before the break command, add in this line.
It's for playing, so I don't really want to push it to github.

  {const char *gc = getenv("GC"); if(gc && *gc) duk_gc(jcx, 0); }

Under the control of an environment variable, I can force duktape to do garbage collection after each script runs.
If gc contributes to a seg fault, then it is more reproducible, and not at the random whim of whenever gc decides to run on its own.
So now, we have this test program.

<body>
hello world
<script type=text/javascript>
(function() {
var i = document.createElement("input");
var f = document.createElement("form");
f.appendChild(i);
})();
</script>
<script>
(function() {
var i = document.createElement("input");
var f = document.createElement("form");
f.appendChild(i);
})();
</script>
</body>

It's basically the same script run twice.
It creates some nodes, but never links them under document, so at some point gc will throw them away.
I had to create the nodes inside a function, because outside a function, all variables are global, even variables in blocks are global, and are immune to gc, so that's why I wrote it this way.
If gc doesn't run, this program browses just fine.
Try it, without GC, or with
export GC=

Next, set GC=1 and browse again.
The js process crashes.
After the first script runs, duktape throws those nodes away, but aha, side effects go over to the edbrowse process.
It tries to do something with those nodes, gets and sets properties etc, thinking the nodes are valid.
After all, why would real-world javascript create nodes only to throw them away?
Well in this test program edbrowse makes js calls using object pointers that have been thrown away.
This is very reproducible, at least for me.

GC=
browse
works fine
GC=1
browse
crash

As mentioned before, I had to create the nodes inside a function, so they would not be global, so gc would throw them away.
The following program works with or without gc.

<body>
hello world
<script type=text/javascript>
var i = document.createElement("input");
var f = document.createElement("form");
f.appendChild(i);
</script>
<script>
var i = document.createElement("input");
var f = document.createElement("form");
f.appendChild(i);
</script>
</body>

So why would this bother us in the real world?
Because our DOM is not perfect, and a js script rarely runs to the end.
It creates nodes, maybe a whole subtree of nodes, but has some kind of reference error before it can link those nodes under document.
The js script could be 200K, so understandable that gc might run when it is finished, or might not, who knows, but if it does,
and those nodes are not linked in properly, they go away, and edbrowse tries to mess with them as its side effects, and js crashes.
I think that's what happens on real websites.

This was less of an issue under moz, because, perhaps, it didn't garbage collect as often,
or it tolerated pointers to invalid objects better than duktape,
or it messed up in some way that didn't cause a seg fault.
In any case the responsibility is ours, though duktape is less tolerant, and has brought this to light, so we need to get on the stick and finish our DOM, so that all scripts run to completion, so all nodes get linked under document, so gc doesn't throw them away, so this doesn't happen.
Yeah well, that's gonna take a long time.
What to do in the meantime?
The only thing I can think of, and it's crude and heavy handed,
is to ignore side effects that result from a script or js handler that did not run to completion, and even that I'm not sure how to implement.
If the function didn't complete, then the nodes it created might not be linked in, and might not be valid.
Another approach is to change my one pass system into a two pass system, the first performing all the links,
and then, if all the nodes do indeed track back up to document, perform the other operations on those nodes, in a second pass, because we know they are valid.
Jesus! That's not trivial.

We're going to keep js as a separate process for a long time, fragile as it is; at least you don't lose all your edbrowse sessions when it crashes.
You might want to spin off a separate js process for each edbrowse window, so a crash still allows js to run in other windows, but you can't do that because we're going to want interwindow communication, so all js contexts are in the same heap, and in the same process.

Here's another problem, our jsrt regression test.
We wrote that ourselves, so the script runs to completion.
All nodes link to document and there shouldn't be a problem, but there is.
It runs with GC off, but crashes with GC=1.
This is showing a problem with edbrowse, but still related to gc, that I haven't figured out.

Are we having fun yet?

Karl Dahlke

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2017-07-15 17:03 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-07-15 17:03 [Edbrowse-dev] Garbage Collection and Boom Karl Dahlke

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).