@@ -89,32 +89,47 @@ def main():
89
89
# alloc_fns contains all the vanilla allocation/free functions that we look
90
90
# for. Regexp chars are escaped appropriately.
91
91
92
- alloc_fns = [
92
+ operator_news = [
93
93
# Matches |operator new(unsigned T)|, where |T| is |int| or |long|.
94
- r"operator new\ (unsigned" ,
94
+ r"operator new(unsigned" ,
95
95
# Matches |operator new[](unsigned T)|, where |T| is |int| or |long|.
96
- r"operator new\[\]\(unsigned" ,
97
- r"memalign" ,
98
- # These three aren't available on all Linux configurations.
99
- # r'posix_memalign',
100
- # r'aligned_alloc',
101
- # r'valloc',
96
+ r"operator new[](unsigned" ,
102
97
]
103
98
99
+ # operator new may end up inlined and replaced with moz_xmalloc.
100
+ inlined_operator_news = [
101
+ r"moz_xmalloc" ,
102
+ ]
103
+
104
+ alloc_fns = (
105
+ operator_news
106
+ + inlined_operator_news
107
+ + [
108
+ r"memalign" ,
109
+ # These three aren't available on all Linux configurations.
110
+ # r'posix_memalign',
111
+ # r'aligned_alloc',
112
+ # r'valloc',
113
+ ]
114
+ )
115
+
104
116
if args .aggressive :
105
117
alloc_fns += [r"malloc" , r"calloc" , r"realloc" , r"free" , r"strdup" ]
106
118
107
119
# This is like alloc_fns, but regexp chars are not escaped.
108
- alloc_fns_unescaped = [fn . replace ( " \\ " , "" ) for fn in alloc_fns ]
120
+ alloc_fns_escaped = [re . escape ( fn ) for fn in alloc_fns ]
109
121
110
122
# This regexp matches the relevant lines in the output of |nm|, which look
111
123
# like the following.
112
124
#
113
125
# js/src/libjs_static.a:Utility.o: U malloc
114
126
# js/src/libjs_static.a:Utility.o: 00000000000007e0 T js::SetSourceOptions(...)
115
127
#
116
- nm_line_re = re .compile (r"([^:/ ]+):\s*[0-9a-fA-F]*\s+([TU]) (.*)" )
117
- alloc_fns_re = re .compile (r"|" .join (alloc_fns ))
128
+ # It may also, in LTO builds, look like
129
+ # js/src/libjs_static.a:Utility.o: ---------------- T js::SetSourceOptions(...)
130
+ #
131
+ nm_line_re = re .compile (r"([^:/ ]+):\s*(?:[0-9a-fA-F]*|-*)\s+([TUw]) (.*)" )
132
+ alloc_fns_re = re .compile (r"|" .join (alloc_fns_escaped ))
118
133
119
134
# This tracks which allocation/free functions have been seen.
120
135
functions = defaultdict (set )
@@ -202,9 +217,24 @@ def main():
202
217
203
218
# Check that all functions we expect are used in util/Utility.cpp. (This
204
219
# will fail if the function-detection code breaks at any point.)
205
- for fn in alloc_fns_unescaped :
220
+ # operator new and its inlined equivalent are mutually exclusive.
221
+ has_operator_news = any (fn in operator_news for fn in util_Utility_cpp )
222
+ has_inlined_operator_news = any (
223
+ fn in inlined_operator_news for fn in util_Utility_cpp
224
+ )
225
+ if has_operator_news and has_inlined_operator_news :
226
+ fail (
227
+ "Both operator new and moz_xmalloc aren't expected in util/Utility.cpp at the same time"
228
+ )
229
+
230
+ for fn in alloc_fns :
206
231
if fn not in util_Utility_cpp :
207
- fail ("'" + fn + "' isn't used as expected in util/Utility.cpp" )
232
+ if (
233
+ (fn in operator_news and not has_inlined_operator_news )
234
+ or (fn in inlined_operator_news and not has_operator_news )
235
+ or (fn not in operator_news and fn not in inlined_operator_news )
236
+ ):
237
+ fail ("'" + fn + "' isn't used as expected in util/Utility.cpp" )
208
238
else :
209
239
util_Utility_cpp .remove (fn )
210
240
@@ -240,7 +270,9 @@ def main():
240
270
#
241
271
# U malloc util/Utility.cpp:117
242
272
#
243
- alloc_lines_re = r"U ((" + r"|" .join (alloc_fns ) + r").*)\s+(\S+:\d+)$"
273
+ alloc_lines_re = (
274
+ r"[Uw] ((" + r"|" .join (alloc_fns_escaped ) + r").*)\s+(\S+:\d+)$"
275
+ )
244
276
245
277
for line in lines :
246
278
m = re .search (alloc_lines_re , line )
0 commit comments