diff options
author | bors-servo <release+servo@mozilla.com> | 2014-04-21 17:13:22 -0400 |
---|---|---|
committer | bors-servo <release+servo@mozilla.com> | 2014-04-21 17:13:22 -0400 |
commit | c6bdc7b7f2d39b522be5767f09f88b1b4ca5577a (patch) | |
tree | 6f40dae2705bb6341af86dba8f65c13d6bf8de9b /src/components/script/script_task.rs | |
parent | 3c175c7ac0815b6c2e2e63806317366f56b38e58 (diff) | |
parent | 3078f580550870156a985fb002f429b6dc35b381 (diff) | |
download | servo-c6bdc7b7f2d39b522be5767f09f88b1b4ca5577a.tar.gz servo-c6bdc7b7f2d39b522be5767f09f88b1b4ca5577a.zip |
auto merge of #2202 : jdm/servo/scriptleak, r=Ms2ger
....
Diffstat (limited to 'src/components/script/script_task.rs')
-rw-r--r-- | src/components/script/script_task.rs | 43 |
1 files changed, 43 insertions, 0 deletions
diff --git a/src/components/script/script_task.rs b/src/components/script/script_task.rs index 4e7a30705b0..f8e7d230420 100644 --- a/src/components/script/script_task.rs +++ b/src/components/script/script_task.rs @@ -485,6 +485,45 @@ pub struct ScriptTask { mouse_over_targets: RefCell<Option<~[JS<Node>]>> } +/// In the event of task failure, all data on the stack runs its destructor. However, there +/// are no reachable, owning pointers to the DOM memory, so it never gets freed by default +/// when the script task fails. The ScriptMemoryFailsafe uses the destructor bomb pattern +/// to forcibly tear down the JS compartments for pages associated with the failing ScriptTask. +struct ScriptMemoryFailsafe<'a> { + owner: Option<&'a ScriptTask>, +} + +impl<'a> ScriptMemoryFailsafe<'a> { + fn neuter(&mut self) { + self.owner = None; + } + + fn new(owner: &'a ScriptTask) -> ScriptMemoryFailsafe<'a> { + ScriptMemoryFailsafe { + owner: Some(owner), + } + } +} + +#[unsafe_destructor] +impl<'a> Drop for ScriptMemoryFailsafe<'a> { + fn drop(&mut self) { + match self.owner { + Some(owner) => { + let mut page_tree = owner.page_tree.borrow_mut(); + for page in page_tree.iter() { + let mut js_info = page.mut_js_info(); + unsafe { + JS_AllowGC(js_info.get_ref().js_context.deref().deref().ptr); + } + *js_info = None; + } + } + None => (), + } + } +} + impl ScriptTask { /// Creates a new script task. pub fn new(id: PipelineId, @@ -547,7 +586,11 @@ impl ScriptTask { resource_task, image_cache_task, window_size); + let mut failsafe = ScriptMemoryFailsafe::new(&*script_task); script_task.start(); + + // This must always be the very last operation performed before the task completes + failsafe.neuter(); }); } |