@@ -230,33 +230,68 @@ static void PrintStackAllocations(const StackAllocationsRingBuffer *sa,
230
230
tag_t obj_tag = base_tag ^ local.tag_offset ;
231
231
if (obj_tag != addr_tag)
232
232
continue ;
233
- // Guess top bits of local variable from the faulting address, because
234
- // we only store bits 4-19 of FP (bits 0-3 are guaranteed to be zero).
235
- uptr local_beg = (fp + local.frame_offset ) |
236
- (untagged_addr & ~(uptr (kRecordFPModulus ) - 1 ));
237
- uptr local_end = local_beg + local.size ;
233
+
234
+ // We only store bits 4-19 of FP (bits 0-3 are guaranteed to be zero).
235
+ // So we know only `FP % kRecordFPModulus`, and we can only calculate
236
+ // `local_beg % kRecordFPModulus`.
237
+ // Out of all possible `local_beg` we will only consider 2 candidates
238
+ // nearest to the `untagged_addr`.
239
+ uptr local_beg_mod = (fp + local.frame_offset ) % kRecordFPModulus ;
240
+ // Pick `local_beg` in the same 1 MiB block as `untagged_addr`.
241
+ uptr local_beg =
242
+ RoundDownTo (untagged_addr, kRecordFPModulus ) + local_beg_mod;
243
+ // Pick the largest `local_beg <= untagged_addr`. It's either the current
244
+ // one or the one before.
245
+ if (local_beg > untagged_addr)
246
+ local_beg -= kRecordFPModulus ;
247
+
248
+ uptr offset = -1ull ;
249
+ const char *whence;
250
+ const char *cause = nullptr ;
251
+ uptr best_beg;
252
+
253
+ // Try two 1 MiB blocks options and pick nearest one.
254
+ for (uptr i = 0 ; i < 2 ; ++i, local_beg += kRecordFPModulus ) {
255
+ uptr local_end = local_beg + local.size ;
256
+ if (local_beg > local_end)
257
+ continue ; // This is a wraparound.
258
+ if (local_beg <= untagged_addr && untagged_addr < local_end) {
259
+ offset = untagged_addr - local_beg;
260
+ whence = " inside" ;
261
+ cause = " use-after-scope" ;
262
+ best_beg = local_beg;
263
+ break ; // This is as close at it can be.
264
+ }
265
+
266
+ if (untagged_addr >= local_end) {
267
+ uptr new_offset = untagged_addr - local_end;
268
+ if (new_offset < offset) {
269
+ offset = new_offset;
270
+ whence = " after" ;
271
+ cause = " stack-buffer-overflow" ;
272
+ best_beg = local_beg;
273
+ }
274
+ } else {
275
+ uptr new_offset = local_beg - untagged_addr;
276
+ if (new_offset < offset) {
277
+ offset = new_offset;
278
+ whence = " before" ;
279
+ cause = " stack-buffer-overflow" ;
280
+ best_beg = local_beg;
281
+ }
282
+ }
283
+ }
284
+
285
+ // To fail the `untagged_addr` must be near nullptr, which is impossible
286
+ // with Linux user space memory layout.
287
+ if (!cause)
288
+ continue ;
238
289
239
290
if (!found_local) {
240
291
Printf (" \n Potentially referenced stack objects:\n " );
241
292
found_local = true ;
242
293
}
243
294
244
- uptr offset;
245
- const char *whence;
246
- const char *cause;
247
- if (local_beg <= untagged_addr && untagged_addr < local_end) {
248
- offset = untagged_addr - local_beg;
249
- whence = " inside" ;
250
- cause = " use-after-scope" ;
251
- } else if (untagged_addr >= local_end) {
252
- offset = untagged_addr - local_end;
253
- whence = " after" ;
254
- cause = " stack-buffer-overflow" ;
255
- } else {
256
- offset = local_beg - untagged_addr;
257
- whence = " before" ;
258
- cause = " stack-buffer-overflow" ;
259
- }
260
295
Decorator d;
261
296
Printf (" %s" , d.Error ());
262
297
Printf (" Cause: %s\n " , cause);
@@ -267,10 +302,11 @@ static void PrintStackAllocations(const StackAllocationsRingBuffer *sa,
267
302
common_flags ()->symbolize_vs_style ,
268
303
common_flags ()->strip_path_prefix );
269
304
Printf (
270
- " %p is located %zd bytes %s a %zd-byte local variable %s [%p,%p) "
305
+ " %p is located %zd bytes %s a %zd-byte local variable %s "
306
+ " [%p,%p) "
271
307
" in %s %s\n " ,
272
- untagged_addr, offset, whence, local_end - local_beg , local.name ,
273
- local_beg, local_end , local.function_name , location.data ());
308
+ untagged_addr, offset, whence, local. size , local.name , best_beg ,
309
+ best_beg + local. size , local.function_name , location.data ());
274
310
location.clear ();
275
311
Printf (" %s\n " , d.Default ());
276
312
}
0 commit comments