xpcom/analysis/stack.js

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this
     3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     5 require({ after_gcc_pass: "cfg" });
     7 include("gcc_util.js");
     8 include("unstable/lazy_types.js");
    10 function process_type(c)
    11 {
    12   if ((c.kind == 'class' || c.kind == 'struct') &&
    13       !c.isIncomplete)
    14     isStack(c);
    15 }
    17 /**
    18  * A BlameChain records a chain of one or more location/message pairs. It
    19  * can be used to issue a complex error message such as:
    20  * location: error: Allocated class Foo on the heap
    21  * locationofFoo:   class Foo inherits from class Bar
    22  * locationofBar:   in class Bar
    23  * locationofBarMem:   Member Bar::mFoo
    24  * locationofBaz:   class Baz is annotated NS_STACK
    25  */
    26 function BlameChain(loc, message, prev)
    27 {
    28   this.loc = loc;
    29   this.message = message;
    30   this.prev = prev;
    31 }
    33 BlameChain.prototype.toString = function()
    34 {
    35   let loc = this.loc;
    36   if (loc === undefined)
    37     loc = "<unknown location>";
    39   let str = '%s:   %s'.format(loc.toString(), this.message);
    40   if (this.prev)
    41     str += "\n%s".format(this.prev);
    42   return str;
    43 };
    45 function isStack(c)
    46 {
    47   function calculate()
    48   {
    49     if (hasAttribute(c, 'NS_stack'))
    50       return new BlameChain(c.loc, '%s %s is annotated NS_STACK_CLASS'.format(c.kind, c.name));
    52     for each (let base in c.bases) {
    53       let r = isStack(base.type);
    54       if (r != null)
    55         return new BlameChain(c.loc, '%s %s is a base of %s %s'.format(base.type.kind, base.type.name, c.kind, c.name), r);
    56     }
    58     for each (let member in c.members) {
    59       if (member.isFunction)
    60         continue;
    62       if (hasAttribute(member, 'NS_okonheap'))
    63         continue;
    65       let type = member.type;
    66       while (true) {
    67         if (type === undefined)
    68           break;
    70         if (type.isArray) {
    71           type = type.type;
    72           continue;
    73         }
    75         if (type.typedef) {
    76           if (hasAttribute(type, 'NS_stack'))
    77             return true;
    79           type = type.typedef;
    80           continue;
    81         }
    82         break;
    83       }
    85       if (type === undefined) {
    86         warning("incomplete type for member " + member + ".", member.loc);
    87         continue;
    88       }
    90       if (type.isPointer || type.isReference)
    91         continue;
    93       if (!type.kind || (type.kind != 'class' && type.kind != 'struct'))
    94         continue;
    96       let r = isStack(type);
    97       if (r != null)
    98         return new BlameChain(c.loc, 'In class %s'.format(c.name),
    99                                  new BlameChain(member.loc, 'Member %s'.format(member.name), r));
   100     }
   101     return null;
   102   }
   104   if (!c.hasOwnProperty('isStack'))
   105     c.isStack = calculate();
   107   return c.isStack;
   108 }
   110 function process_tree(fn)
   111 {
   112   if (hasAttribute(dehydra_convert(fn), 'NS_suppress_stackcheck'))
   113     return;
   115   let cfg = function_decl_cfg(fn);
   117   for (let bb in cfg_bb_iterator(cfg)) {
   118     let it = bb_isn_iterator(bb);
   119     for (let isn in it) {
   120       if (isn.tree_code() != GIMPLE_CALL)
   121         continue;
   123       let name = gimple_call_function_name(isn);
   124       if (name != "operator new" && name != "operator new []")
   125         continue;
   127       // ignore placement new
   128       // TODO? ensure 2nd arg is local stack variable
   129       if (gimple_call_num_args(isn) == 2 &&
   130           TREE_TYPE(gimple_call_arg(isn, 1)).tree_code() == POINTER_TYPE)
   131         continue;
   133       let newLhs = gimple_call_lhs(isn);
   134       if (!newLhs)
   135         error("Non assigning call to operator new", location_of(isn));
   137       // if isn is the last of its block there are other problems...
   138       assign = it.next();
   140       // Calls to |new| are always followed by an assignment, casting the void ptr to which
   141       // |new| was assigned, to a ptr variable of the same type as the allocated object.
   142       // Exception: explicit calls to |::operator new (size_t)|, which can be ignored.
   143       if (assign.tree_code() != GIMPLE_ASSIGN)
   144         continue;
   146       let assignRhs = gimple_op(assign, 1);
   147       if (newLhs != assignRhs)
   148         continue;
   150       let assignLhs = gimple_op(assign, 0);
   151       let type = TREE_TYPE(TREE_TYPE(assignLhs));
   152       let dehydraType = dehydra_convert(type);
   154       let r = isStack(dehydraType);
   155       if (r)
   156         warning("constructed object of type '%s' not on the stack: %s".format(dehydraType.name, r), location_of(isn));
   157     }
   158   }
   159 }

mercurial