tools/footprint/leak-gauge.html

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
     2 	"http://www.w3.org/TR/html4/strict.dtd">
     3 <!--
     4   vim:sw=4:ts=4:et:
     5  This Source Code Form is subject to the terms of the Mozilla Public
     6    - License, v. 2.0. If a copy of the MPL was not distributed with this
     7    - file, You can obtain one at http://mozilla.org/MPL/2.0/.
     8 -->
     9 <html lang="en-US">
    10 <head>
    11 <title>Leak Gauge</title>
    13 <style type="text/css">
    14 pre { margin: 0; }
    15 pre.output { border: medium solid; padding: 1em; margin: 1em; }
    16 </style>
    17 <script type="text/javascript">
    19 function runFile(file) {
    20   var result = "Results of processing log " + file.fileName + " :\n";
    22   var fileReader = new FileReader();
    23   fileReader.onload = function(e)
    24   {
    25     runContents(result, e.target.result);
    26   }
    27   fileReader.readAsText(file, "iso-8859-1");
    28 }
    30 function runContents(result, contents) {
    31     // A hash of objects (keyed by the first word of the line in the log)
    32     // that have two public methods, handle_line and dump (to be called using
    33     // call, above), along with any private data they need.
    34     var handlers = {
    35         "DOMWINDOW": {
    36             count: 0,
    37             windows: {},
    38             handle_line: function(line) {
    39                 var match = line.match(/^([0-9a-f]*) (\S*)(.*)/);
    40                 if (match) {
    41                     var addr = match[1];
    42                     var verb = match[2];
    43                     var rest = match[3];
    44                     if (verb == "created") {
    45                         var m = rest.match(/ outer=([0-9a-f]*)$/);
    46                         if (!m)
    47                             throw "outer expected";
    48                         this.windows[addr] = { outer: m[1] };
    49                         ++this.count;
    50                     } else if (verb == "destroyed") {
    51                         delete this.windows[addr];
    52                     } else if (verb == "SetNewDocument") {
    53                         var m = rest.match(/^ (.*)$/);
    54                         if (!m)
    55                             throw "URI expected";
    56                         this.windows[addr][m[1]] = true;
    57                     }
    58                 }
    59             },
    60             dump: function() {
    61                 for (var addr in this.windows) {
    62                     var winobj = this.windows[addr];
    63                     var outer = winobj.outer;
    64                     delete winobj.outer;
    65                     result += "Leaked " + (outer == "0" ? "outer" : "inner") +
    66                               " window " + addr + " " +
    67                               (outer == "0" ? "" : "(outer " + outer + ") ") +
    68                               "at address " + addr + ".\n";
    69                     for (var uri in winobj) {
    70                         result += " ... with URI \"" + uri + "\".\n";
    71                     }
    72                 }
    73             },
    74             summary: function() {
    75                 var len = 0;
    76                 for (var w in this.windows)
    77                     ++len;
    78                 result += 'Leaked ' + len + ' out of ' +
    79                           this.count + " DOM Windows\n";
    80             }
    81         },
    82         "DOCUMENT": {
    83             count: 0,
    84             docs: {},
    85             handle_line: function(line) {
    86                 var match = line.match(/^([0-9a-f]*) (\S*)(.*)/);
    87                 if (match) {
    88                     var addr = match[1];
    89                     var verb = match[2];
    90                     var rest = match[3];
    91                     if (verb == "created") {
    92                         this.docs[addr] = {};
    93                         ++this.count;
    94                     } else if (verb == "destroyed") {
    95                         delete this.docs[addr];
    96                     } else if (verb == "ResetToURI" ||
    97                                verb == "StartDocumentLoad") {
    98                         var m = rest.match(/^ (.*)$/);
    99                         if (!m)
   100                             throw "URI expected";
   101                         var uri = m[1];
   102                         var doc_info = this.docs[addr];
   103                         doc_info[uri] = true;
   104                         if ("nim" in doc_info) {
   105                             doc_info["nim"][uri] = true;
   106                         }
   107                     }
   108                 }
   109             },
   110             dump: function() {
   111                 for (var addr in this.docs) {
   112                     var doc = this.docs[addr];
   113                     result += "Leaked document at address " + addr + ".\n";
   114                     for (var uri in doc) {
   115                         if (uri != "nim") {
   116                             result += " ... with URI \"" + uri + "\".\n";
   117                         }
   118                     }
   119                 }
   120             },
   121             summary: function() {
   122                 var len = 0;
   123                 for (var w in this.docs)
   124                     ++len;
   125                 result += 'Leaked ' + len + ' out of ' +
   126                           this.count + " documents\n";
   127             }
   128         },
   129         "DOCSHELL": {
   130             count: 0,
   131             shells: {},
   132             handle_line: function(line) {
   133                 var match = line.match(/^([0-9a-f]*) (\S*)(.*)/);
   134                 if (match) {
   135                     var addr = match[1];
   136                     var verb = match[2];
   137                     var rest = match[3];
   138                     if (verb == "created") {
   139                         this.shells[addr] = {};
   140                         ++this.count;
   141                     } else if (verb == "destroyed") {
   142                         delete this.shells[addr];
   143                     } else if (verb == "InternalLoad" ||
   144                                verb == "SetCurrentURI") {
   145                         var m = rest.match(/^ (.*)$/);
   146                         if (!m)
   147                             throw "URI expected";
   148                         this.shells[addr][m[1]] = true;
   149                     }
   150                 }
   151             },
   152             dump: function() {
   153                 for (var addr in this.shells) {
   154                     var doc = this.shells[addr];
   155                     result += "Leaked docshell at address " + addr + ".\n";
   156                     for (var uri in doc) {
   157                         result += " ... which loaded URI \"" + uri + "\".\n";
   158                     }
   159                 }
   160             },
   161             summary: function() {
   162                 var len = 0;
   163                 for (var w in this.shells)
   164                     ++len;
   165                 result += 'Leaked ' + len + ' out of ' +
   166                           this.count + " docshells\n";
   167             }
   168         },
   169         "NODEINFOMANAGER": {
   170             count: 0,
   171             nims: {},
   172             handle_line: function(line) {
   173                 var match = line.match(/^([0-9a-f]*) (\S*)(.*)/);
   174                 if (match) {
   175                     var addr = match[1];
   176                     var verb = match[2];
   177                     var rest = match[3];
   178                     if (verb == "created") {
   179                         this.nims[addr] = {};
   180                         ++this.count;
   181                     } else if (verb == "destroyed") {
   182                         delete this.nims[addr];
   183                     } else if (verb == "Init") {
   184                         var m = rest.match(/^ document=(.*)$/);
   185                         if (!m)
   186                             throw "document pointer expected";
   187                         var nim_info = this.nims[addr];
   188                         var doc = m[1];
   189                         if (doc != "0") {
   190                             var doc_info = handlers["DOCUMENT"].docs[doc];
   191                             for (var uri in doc_info) {
   192                                 nim_info[uri] = true;
   193                             }
   194                             doc_info["nim"] = nim_info;
   195                         }
   196                     }
   197                 }
   198             },
   199             dump: function() {
   200                 for (var addr in this.nims) {
   201                     var nim = this.nims[addr];
   202                     result += "Leaked content nodes associated with node info manager at address " + addr + ".\n";
   203                     for (var uri in nim) {
   204                         result += " ... with document URI \"" + uri + "\".\n";
   205                     }
   206                 }
   207             },
   208             summary: function() {
   209                 var len = 0;
   210                 for (var w in this.nims)
   211                     ++len;
   212                 result += 'Leaked content nodes in ' + len + ' out of ' +
   213                           this.count + " documents\n";
   214             }
   215         }
   216     };
   218     var lines = contents.split(/[\r\n]+/);
   219     for (var j in lines) {
   220         var line = lines[j];
   221         // strip off initial "-", thread id, and thread pointer; separate
   222         // first word and rest
   223         var matches = line.match(/^\-?[0-9]*\[[0-9a-f]*\]: (\S*) (.*)$/);
   224         if (matches) {
   225             var handler = matches[1];
   226             var data = matches[2];
   227             if (typeof(handlers[handler]) != "undefined") {
   228                 handlers[handler].handle_line(data);
   229             }
   230         }
   231     }
   233     for (var handler in handlers)
   234         handlers[handler].dump();
   235     if (result.length)
   236         result += "\n";
   237     result += "Summary:\n";
   238     for (var handler in handlers)
   239         handlers[handler].summary();
   240     result += "\n";
   242     var out = document.createElement("pre");
   243     out.className = "output";
   244     out.appendChild(document.createTextNode(result));
   245     document.body.appendChild(out);
   246 }
   248 function run() {
   249     var input = document.getElementById("fileinput");
   250     var files = input.files;
   251     for (var i = 0; i < files.length; ++i)
   252         runfile(files[i]);
   253     // So the user can process the same filename again (after
   254     // overwriting the log), clear the value on the form input so we
   255     // will always get an onchange event.
   256     input.value = "";
   257 }
   259 </script>
   260 </head>
   261 <body>
   263 <h1>Leak Gauge</h1>
   265 <pre>$Id: leak-gauge.html,v 1.8 2008/02/08 19:55:34 dbaron%dbaron.org Exp $</pre>
   267 <p>This script is designed to help testers isolate and simplify testcases
   268 for many classes of leaks (those that involve large graphs of core
   269 data structures) in Mozilla-based browsers.  It is designed to print
   270 information about what has leaked by processing a log taken while
   271 running the browser.  Such a log can be taken over a long session of
   272 normal browsing and then the log can be processed to find sites that
   273 leak.  Once a site is known to leak, the logging can then be repeated
   274 to figure out under what conditions the leak occurs.</p>
   276 <p>The way to create this log is to set the environment variables:</p>
   277 <pre>  NSPR_LOG_MODULES=DOMLeak:5,DocumentLeak:5,nsDocShellLeak:5,NodeInfoManagerLeak:5
   278   NSPR_LOG_FILE=nspr.log     <i>(or any other filename of your choice)</i></pre>
   279 <p>in your shell and then run the program.</p>
   280 <ul>
   281 <li>In a Windows command prompt, set environment variables with
   282 <pre>    set VAR=value</pre></li>
   283 <li> In an sh-based shell such as bash, set environment variables with
   284 <pre>    export VAR=value</pre></li>
   285 <li>In a csh-based shell such as tcsh, set environment variables with
   286 <pre>    setenv VAR value</pre></li>
   287 </ul>
   289 <p>Once you have this log from a complete run of the browser (you have
   290 to exit; otherwise it will look like everything leaked), you can load
   291 this page (be careful not to overwrite the log when starting the browser
   292 to load this page) and enter the filename of the log:</p>
   294 <p><input type="file" id="fileinput" onchange="run()"></p>
   296 <p>Then you'll see the output below, which will tell you which of
   297 certain core objects leaked and the URLs associated with those
   298 objects.</p>
   300 </body>
   301 </html>

mercurial