Thu, 22 Jan 2015 13:21:57 +0100
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 }