File: | projects/compiler-rt/lib/asan/asan_descriptions.cc |
Warning: | line 455, column 3 Value stored to 'addr' is never read |
1 | //===-- asan_descriptions.cc ------------------------------------*- C++ -*-===// |
2 | // |
3 | // The LLVM Compiler Infrastructure |
4 | // |
5 | // This file is distributed under the University of Illinois Open Source |
6 | // License. See LICENSE.TXT for details. |
7 | // |
8 | //===----------------------------------------------------------------------===// |
9 | // |
10 | // This file is a part of AddressSanitizer, an address sanity checker. |
11 | // |
12 | // ASan functions for getting information about an address and/or printing it. |
13 | //===----------------------------------------------------------------------===// |
14 | |
15 | #include "asan_descriptions.h" |
16 | #include "asan_mapping.h" |
17 | #include "asan_report.h" |
18 | #include "asan_stack.h" |
19 | #include "sanitizer_common/sanitizer_stackdepot.h" |
20 | |
21 | namespace __asan { |
22 | |
23 | // Return " (thread_name) " or an empty string if the name is empty. |
24 | const char *ThreadNameWithParenthesis(AsanThreadContext *t, char buff[], |
25 | uptr buff_len) { |
26 | const char *name = t->name; |
27 | if (name[0] == '\0') return ""; |
28 | buff[0] = 0; |
29 | internal_strncat(buff, " (", 3); |
30 | internal_strncat(buff, name, buff_len - 4); |
31 | internal_strncat(buff, ")", 2); |
32 | return buff; |
33 | } |
34 | |
35 | const char *ThreadNameWithParenthesis(u32 tid, char buff[], uptr buff_len) { |
36 | if (tid == kInvalidTid) return ""; |
37 | asanThreadRegistry().CheckLocked(); |
38 | AsanThreadContext *t = GetThreadContextByTidLocked(tid); |
39 | return ThreadNameWithParenthesis(t, buff, buff_len); |
40 | } |
41 | |
42 | void DescribeThread(AsanThreadContext *context) { |
43 | CHECK(context)do { __sanitizer::u64 v1 = (u64)((context)); __sanitizer::u64 v2 = (u64)(0); if (__builtin_expect(!!(!(v1 != v2)), 0)) __sanitizer ::CheckFailed("/tmp/buildd/llvm-toolchain-snapshot-5.0~svn306458/projects/compiler-rt/lib/asan/asan_descriptions.cc" , 43, "(" "(context)" ") " "!=" " (" "0" ")", v1, v2); } while (false); |
44 | asanThreadRegistry().CheckLocked(); |
45 | // No need to announce the main thread. |
46 | if (context->tid == 0 || context->announced) { |
47 | return; |
48 | } |
49 | context->announced = true; |
50 | char tname[128]; |
51 | InternalScopedString str(1024); |
52 | str.append("Thread T%d%s", context->tid, |
53 | ThreadNameWithParenthesis(context->tid, tname, sizeof(tname))); |
54 | if (context->parent_tid == kInvalidTid) { |
55 | str.append(" created by unknown thread\n"); |
56 | Printf("%s", str.data()); |
57 | return; |
58 | } |
59 | str.append( |
60 | " created by T%d%s here:\n", context->parent_tid, |
61 | ThreadNameWithParenthesis(context->parent_tid, tname, sizeof(tname))); |
62 | Printf("%s", str.data()); |
63 | StackDepotGet(context->stack_id).Print(); |
64 | // Recursively described parent thread if needed. |
65 | if (flags()->print_full_thread_history) { |
66 | AsanThreadContext *parent_context = |
67 | GetThreadContextByTidLocked(context->parent_tid); |
68 | DescribeThread(parent_context); |
69 | } |
70 | } |
71 | |
72 | // Shadow descriptions |
73 | static bool GetShadowKind(uptr addr, ShadowKind *shadow_kind) { |
74 | CHECK(!AddrIsInMem(addr))do { __sanitizer::u64 v1 = (u64)((!AddrIsInMem(addr))); __sanitizer ::u64 v2 = (u64)(0); if (__builtin_expect(!!(!(v1 != v2)), 0) ) __sanitizer::CheckFailed("/tmp/buildd/llvm-toolchain-snapshot-5.0~svn306458/projects/compiler-rt/lib/asan/asan_descriptions.cc" , 74, "(" "(!AddrIsInMem(addr))" ") " "!=" " (" "0" ")", v1, v2 ); } while (false); |
75 | if (AddrIsInShadowGap(addr)) { |
76 | *shadow_kind = kShadowKindGap; |
77 | } else if (AddrIsInHighShadow(addr)) { |
78 | *shadow_kind = kShadowKindHigh; |
79 | } else if (AddrIsInLowShadow(addr)) { |
80 | *shadow_kind = kShadowKindLow; |
81 | } else { |
82 | CHECK(0 && "Address is not in memory and not in shadow?")do { __sanitizer::u64 v1 = (u64)((0 && "Address is not in memory and not in shadow?" )); __sanitizer::u64 v2 = (u64)(0); if (__builtin_expect(!!(! (v1 != v2)), 0)) __sanitizer::CheckFailed("/tmp/buildd/llvm-toolchain-snapshot-5.0~svn306458/projects/compiler-rt/lib/asan/asan_descriptions.cc" , 82, "(" "(0 && \"Address is not in memory and not in shadow?\")" ") " "!=" " (" "0" ")", v1, v2); } while (false); |
83 | return false; |
84 | } |
85 | return true; |
86 | } |
87 | |
88 | bool DescribeAddressIfShadow(uptr addr) { |
89 | ShadowAddressDescription descr; |
90 | if (!GetShadowAddressInformation(addr, &descr)) return false; |
91 | descr.Print(); |
92 | return true; |
93 | } |
94 | |
95 | bool GetShadowAddressInformation(uptr addr, ShadowAddressDescription *descr) { |
96 | if (AddrIsInMem(addr)) return false; |
97 | ShadowKind shadow_kind; |
98 | if (!GetShadowKind(addr, &shadow_kind)) return false; |
99 | if (shadow_kind != kShadowKindGap) descr->shadow_byte = *(u8 *)addr; |
100 | descr->addr = addr; |
101 | descr->kind = shadow_kind; |
102 | return true; |
103 | } |
104 | |
105 | // Heap descriptions |
106 | static void GetAccessToHeapChunkInformation(ChunkAccess *descr, |
107 | AsanChunkView chunk, uptr addr, |
108 | uptr access_size) { |
109 | descr->bad_addr = addr; |
110 | if (chunk.AddrIsAtLeft(addr, access_size, &descr->offset)) { |
111 | descr->access_type = kAccessTypeLeft; |
112 | } else if (chunk.AddrIsAtRight(addr, access_size, &descr->offset)) { |
113 | descr->access_type = kAccessTypeRight; |
114 | if (descr->offset < 0) { |
115 | descr->bad_addr -= descr->offset; |
116 | descr->offset = 0; |
117 | } |
118 | } else if (chunk.AddrIsInside(addr, access_size, &descr->offset)) { |
119 | descr->access_type = kAccessTypeInside; |
120 | } else { |
121 | descr->access_type = kAccessTypeUnknown; |
122 | } |
123 | descr->chunk_begin = chunk.Beg(); |
124 | descr->chunk_size = chunk.UsedSize(); |
125 | descr->alloc_type = chunk.GetAllocType(); |
126 | } |
127 | |
128 | static void PrintHeapChunkAccess(uptr addr, const ChunkAccess &descr) { |
129 | Decorator d; |
130 | InternalScopedString str(4096); |
131 | str.append("%s", d.Location()); |
132 | switch (descr.access_type) { |
133 | case kAccessTypeLeft: |
134 | str.append("%p is located %zd bytes to the left of", |
135 | (void *)descr.bad_addr, descr.offset); |
136 | break; |
137 | case kAccessTypeRight: |
138 | str.append("%p is located %zd bytes to the right of", |
139 | (void *)descr.bad_addr, descr.offset); |
140 | break; |
141 | case kAccessTypeInside: |
142 | str.append("%p is located %zd bytes inside of", (void *)descr.bad_addr, |
143 | descr.offset); |
144 | break; |
145 | case kAccessTypeUnknown: |
146 | str.append( |
147 | "%p is located somewhere around (this is AddressSanitizer bug!)", |
148 | (void *)descr.bad_addr); |
149 | } |
150 | str.append(" %zu-byte region [%p,%p)\n", descr.chunk_size, |
151 | (void *)descr.chunk_begin, |
152 | (void *)(descr.chunk_begin + descr.chunk_size)); |
153 | str.append("%s", d.EndLocation()); |
154 | Printf("%s", str.data()); |
155 | } |
156 | |
157 | bool GetHeapAddressInformation(uptr addr, uptr access_size, |
158 | HeapAddressDescription *descr) { |
159 | AsanChunkView chunk = FindHeapChunkByAddress(addr); |
160 | if (!chunk.IsValid()) { |
161 | return false; |
162 | } |
163 | descr->addr = addr; |
164 | GetAccessToHeapChunkInformation(&descr->chunk_access, chunk, addr, |
165 | access_size); |
166 | CHECK_NE(chunk.AllocTid(), kInvalidTid)do { __sanitizer::u64 v1 = (u64)((chunk.AllocTid())); __sanitizer ::u64 v2 = (u64)((kInvalidTid)); if (__builtin_expect(!!(!(v1 != v2)), 0)) __sanitizer::CheckFailed("/tmp/buildd/llvm-toolchain-snapshot-5.0~svn306458/projects/compiler-rt/lib/asan/asan_descriptions.cc" , 166, "(" "(chunk.AllocTid())" ") " "!=" " (" "(kInvalidTid)" ")", v1, v2); } while (false); |
167 | descr->alloc_tid = chunk.AllocTid(); |
168 | descr->alloc_stack_id = chunk.GetAllocStackId(); |
169 | descr->free_tid = chunk.FreeTid(); |
170 | if (descr->free_tid != kInvalidTid) |
171 | descr->free_stack_id = chunk.GetFreeStackId(); |
172 | return true; |
173 | } |
174 | |
175 | static StackTrace GetStackTraceFromId(u32 id) { |
176 | CHECK(id)do { __sanitizer::u64 v1 = (u64)((id)); __sanitizer::u64 v2 = (u64)(0); if (__builtin_expect(!!(!(v1 != v2)), 0)) __sanitizer ::CheckFailed("/tmp/buildd/llvm-toolchain-snapshot-5.0~svn306458/projects/compiler-rt/lib/asan/asan_descriptions.cc" , 176, "(" "(id)" ") " "!=" " (" "0" ")", v1, v2); } while (false ); |
177 | StackTrace res = StackDepotGet(id); |
178 | CHECK(res.trace)do { __sanitizer::u64 v1 = (u64)((res.trace)); __sanitizer::u64 v2 = (u64)(0); if (__builtin_expect(!!(!(v1 != v2)), 0)) __sanitizer ::CheckFailed("/tmp/buildd/llvm-toolchain-snapshot-5.0~svn306458/projects/compiler-rt/lib/asan/asan_descriptions.cc" , 178, "(" "(res.trace)" ") " "!=" " (" "0" ")", v1, v2); } while (false); |
179 | return res; |
180 | } |
181 | |
182 | bool DescribeAddressIfHeap(uptr addr, uptr access_size) { |
183 | HeapAddressDescription descr; |
184 | if (!GetHeapAddressInformation(addr, access_size, &descr)) { |
185 | Printf( |
186 | "AddressSanitizer can not describe address in more detail " |
187 | "(wild memory access suspected).\n"); |
188 | return false; |
189 | } |
190 | descr.Print(); |
191 | return true; |
192 | } |
193 | |
194 | // Stack descriptions |
195 | bool GetStackAddressInformation(uptr addr, uptr access_size, |
196 | StackAddressDescription *descr) { |
197 | AsanThread *t = FindThreadByStackAddress(addr); |
198 | if (!t) return false; |
199 | |
200 | descr->addr = addr; |
201 | descr->tid = t->tid(); |
202 | // Try to fetch precise stack frame for this access. |
203 | AsanThread::StackFrameAccess access; |
204 | if (!t->GetStackFrameAccessByAddr(addr, &access)) { |
205 | descr->frame_descr = nullptr; |
206 | return true; |
207 | } |
208 | |
209 | descr->offset = access.offset; |
210 | descr->access_size = access_size; |
211 | descr->frame_pc = access.frame_pc; |
212 | descr->frame_descr = access.frame_descr; |
213 | |
214 | #if SANITIZER_PPC64V10 |
215 | // On PowerPC64 ELFv1, the address of a function actually points to a |
216 | // three-doubleword data structure with the first field containing |
217 | // the address of the function's code. |
218 | descr->frame_pc = *reinterpret_cast<uptr *>(descr->frame_pc); |
219 | #endif |
220 | descr->frame_pc += 16; |
221 | |
222 | return true; |
223 | } |
224 | |
225 | static void PrintAccessAndVarIntersection(const StackVarDescr &var, uptr addr, |
226 | uptr access_size, uptr prev_var_end, |
227 | uptr next_var_beg) { |
228 | uptr var_end = var.beg + var.size; |
229 | uptr addr_end = addr + access_size; |
230 | const char *pos_descr = nullptr; |
231 | // If the variable [var.beg, var_end) is the nearest variable to the |
232 | // current memory access, indicate it in the log. |
233 | if (addr >= var.beg) { |
234 | if (addr_end <= var_end) |
235 | pos_descr = "is inside"; // May happen if this is a use-after-return. |
236 | else if (addr < var_end) |
237 | pos_descr = "partially overflows"; |
238 | else if (addr_end <= next_var_beg && |
239 | next_var_beg - addr_end >= addr - var_end) |
240 | pos_descr = "overflows"; |
241 | } else { |
242 | if (addr_end > var.beg) |
243 | pos_descr = "partially underflows"; |
244 | else if (addr >= prev_var_end && addr - prev_var_end >= var.beg - addr_end) |
245 | pos_descr = "underflows"; |
246 | } |
247 | InternalScopedString str(1024); |
248 | str.append(" [%zd, %zd)", var.beg, var_end); |
249 | // Render variable name. |
250 | str.append(" '"); |
251 | for (uptr i = 0; i < var.name_len; ++i) { |
252 | str.append("%c", var.name_pos[i]); |
253 | } |
254 | str.append("'"); |
255 | if (var.line > 0) { |
256 | str.append(" (line %d)", var.line); |
257 | } |
258 | if (pos_descr) { |
259 | Decorator d; |
260 | // FIXME: we may want to also print the size of the access here, |
261 | // but in case of accesses generated by memset it may be confusing. |
262 | str.append("%s <== Memory access at offset %zd %s this variable%s\n", |
263 | d.Location(), addr, pos_descr, d.EndLocation()); |
264 | } else { |
265 | str.append("\n"); |
266 | } |
267 | Printf("%s", str.data()); |
268 | } |
269 | |
270 | bool DescribeAddressIfStack(uptr addr, uptr access_size) { |
271 | StackAddressDescription descr; |
272 | if (!GetStackAddressInformation(addr, access_size, &descr)) return false; |
273 | descr.Print(); |
274 | return true; |
275 | } |
276 | |
277 | // Global descriptions |
278 | static void DescribeAddressRelativeToGlobal(uptr addr, uptr access_size, |
279 | const __asan_global &g) { |
280 | InternalScopedString str(4096); |
281 | Decorator d; |
282 | str.append("%s", d.Location()); |
283 | if (addr < g.beg) { |
284 | str.append("%p is located %zd bytes to the left", (void *)addr, |
285 | g.beg - addr); |
286 | } else if (addr + access_size > g.beg + g.size) { |
287 | if (addr < g.beg + g.size) addr = g.beg + g.size; |
288 | str.append("%p is located %zd bytes to the right", (void *)addr, |
289 | addr - (g.beg + g.size)); |
290 | } else { |
291 | // Can it happen? |
292 | str.append("%p is located %zd bytes inside", (void *)addr, addr - g.beg); |
293 | } |
294 | str.append(" of global variable '%s' defined in '", |
295 | MaybeDemangleGlobalName(g.name)); |
296 | PrintGlobalLocation(&str, g); |
297 | str.append("' (0x%zx) of size %zu\n", g.beg, g.size); |
298 | str.append("%s", d.EndLocation()); |
299 | PrintGlobalNameIfASCII(&str, g); |
300 | Printf("%s", str.data()); |
301 | } |
302 | |
303 | bool GetGlobalAddressInformation(uptr addr, uptr access_size, |
304 | GlobalAddressDescription *descr) { |
305 | descr->addr = addr; |
306 | int globals_num = GetGlobalsForAddress(addr, descr->globals, descr->reg_sites, |
307 | ARRAY_SIZE(descr->globals)(sizeof(descr->globals)/sizeof((descr->globals)[0]))); |
308 | descr->size = globals_num; |
309 | descr->access_size = access_size; |
310 | return globals_num != 0; |
311 | } |
312 | |
313 | bool DescribeAddressIfGlobal(uptr addr, uptr access_size, |
314 | const char *bug_type) { |
315 | GlobalAddressDescription descr; |
316 | if (!GetGlobalAddressInformation(addr, access_size, &descr)) return false; |
317 | |
318 | descr.Print(bug_type); |
319 | return true; |
320 | } |
321 | |
322 | void ShadowAddressDescription::Print() const { |
323 | Printf("Address %p is located in the %s area.\n", addr, ShadowNames[kind]); |
324 | } |
325 | |
326 | void GlobalAddressDescription::Print(const char *bug_type) const { |
327 | for (int i = 0; i < size; i++) { |
328 | DescribeAddressRelativeToGlobal(addr, access_size, globals[i]); |
329 | if (bug_type && |
330 | 0 == internal_strcmp(bug_type, "initialization-order-fiasco") && |
331 | reg_sites[i]) { |
332 | Printf(" registered at:\n"); |
333 | StackDepotGet(reg_sites[i]).Print(); |
334 | } |
335 | } |
336 | } |
337 | |
338 | void StackAddressDescription::Print() const { |
339 | Decorator d; |
340 | char tname[128]; |
341 | Printf("%s", d.Location()); |
342 | Printf("Address %p is located in stack of thread T%d%s", addr, tid, |
343 | ThreadNameWithParenthesis(tid, tname, sizeof(tname))); |
344 | |
345 | if (!frame_descr) { |
346 | Printf("%s\n", d.EndLocation()); |
347 | return; |
348 | } |
349 | Printf(" at offset %zu in frame%s\n", offset, d.EndLocation()); |
350 | |
351 | // Now we print the frame where the alloca has happened. |
352 | // We print this frame as a stack trace with one element. |
353 | // The symbolizer may print more than one frame if inlining was involved. |
354 | // The frame numbers may be different than those in the stack trace printed |
355 | // previously. That's unfortunate, but I have no better solution, |
356 | // especially given that the alloca may be from entirely different place |
357 | // (e.g. use-after-scope, or different thread's stack). |
358 | Printf("%s", d.EndLocation()); |
359 | StackTrace alloca_stack(&frame_pc, 1); |
360 | alloca_stack.Print(); |
361 | |
362 | InternalMmapVector<StackVarDescr> vars(16); |
363 | if (!ParseFrameDescription(frame_descr, &vars)) { |
364 | Printf( |
365 | "AddressSanitizer can't parse the stack frame " |
366 | "descriptor: |%s|\n", |
367 | frame_descr); |
368 | // 'addr' is a stack address, so return true even if we can't parse frame |
369 | return; |
370 | } |
371 | uptr n_objects = vars.size(); |
372 | // Report the number of stack objects. |
373 | Printf(" This frame has %zu object(s):\n", n_objects); |
374 | |
375 | // Report all objects in this frame. |
376 | for (uptr i = 0; i < n_objects; i++) { |
377 | uptr prev_var_end = i ? vars[i - 1].beg + vars[i - 1].size : 0; |
378 | uptr next_var_beg = i + 1 < n_objects ? vars[i + 1].beg : ~(0UL); |
379 | PrintAccessAndVarIntersection(vars[i], offset, access_size, prev_var_end, |
380 | next_var_beg); |
381 | } |
382 | Printf( |
383 | "HINT: this may be a false positive if your program uses " |
384 | "some custom stack unwind mechanism or swapcontext\n"); |
385 | if (SANITIZER_WINDOWS0) |
386 | Printf(" (longjmp, SEH and C++ exceptions *are* supported)\n"); |
387 | else |
388 | Printf(" (longjmp and C++ exceptions *are* supported)\n"); |
389 | |
390 | DescribeThread(GetThreadContextByTidLocked(tid)); |
391 | } |
392 | |
393 | void HeapAddressDescription::Print() const { |
394 | PrintHeapChunkAccess(addr, chunk_access); |
395 | |
396 | asanThreadRegistry().CheckLocked(); |
397 | AsanThreadContext *alloc_thread = GetThreadContextByTidLocked(alloc_tid); |
398 | StackTrace alloc_stack = GetStackTraceFromId(alloc_stack_id); |
399 | |
400 | char tname[128]; |
401 | Decorator d; |
402 | AsanThreadContext *free_thread = nullptr; |
403 | if (free_tid != kInvalidTid) { |
404 | free_thread = GetThreadContextByTidLocked(free_tid); |
405 | Printf("%sfreed by thread T%d%s here:%s\n", d.Allocation(), |
406 | free_thread->tid, |
407 | ThreadNameWithParenthesis(free_thread, tname, sizeof(tname)), |
408 | d.EndAllocation()); |
409 | StackTrace free_stack = GetStackTraceFromId(free_stack_id); |
410 | free_stack.Print(); |
411 | Printf("%spreviously allocated by thread T%d%s here:%s\n", d.Allocation(), |
412 | alloc_thread->tid, |
413 | ThreadNameWithParenthesis(alloc_thread, tname, sizeof(tname)), |
414 | d.EndAllocation()); |
415 | } else { |
416 | Printf("%sallocated by thread T%d%s here:%s\n", d.Allocation(), |
417 | alloc_thread->tid, |
418 | ThreadNameWithParenthesis(alloc_thread, tname, sizeof(tname)), |
419 | d.EndAllocation()); |
420 | } |
421 | alloc_stack.Print(); |
422 | DescribeThread(GetCurrentThread()); |
423 | if (free_thread) DescribeThread(free_thread); |
424 | DescribeThread(alloc_thread); |
425 | } |
426 | |
427 | AddressDescription::AddressDescription(uptr addr, uptr access_size, |
428 | bool shouldLockThreadRegistry) { |
429 | if (GetShadowAddressInformation(addr, &data.shadow)) { |
430 | data.kind = kAddressKindShadow; |
431 | return; |
432 | } |
433 | if (GetHeapAddressInformation(addr, access_size, &data.heap)) { |
434 | data.kind = kAddressKindHeap; |
435 | return; |
436 | } |
437 | |
438 | bool isStackMemory = false; |
439 | if (shouldLockThreadRegistry) { |
440 | ThreadRegistryLock l(&asanThreadRegistry()); |
441 | isStackMemory = GetStackAddressInformation(addr, access_size, &data.stack); |
442 | } else { |
443 | isStackMemory = GetStackAddressInformation(addr, access_size, &data.stack); |
444 | } |
445 | if (isStackMemory) { |
446 | data.kind = kAddressKindStack; |
447 | return; |
448 | } |
449 | |
450 | if (GetGlobalAddressInformation(addr, access_size, &data.global)) { |
451 | data.kind = kAddressKindGlobal; |
452 | return; |
453 | } |
454 | data.kind = kAddressKindWild; |
455 | addr = 0; |
Value stored to 'addr' is never read | |
456 | } |
457 | |
458 | void PrintAddressDescription(uptr addr, uptr access_size, |
459 | const char *bug_type) { |
460 | ShadowAddressDescription shadow_descr; |
461 | if (GetShadowAddressInformation(addr, &shadow_descr)) { |
462 | shadow_descr.Print(); |
463 | return; |
464 | } |
465 | |
466 | GlobalAddressDescription global_descr; |
467 | if (GetGlobalAddressInformation(addr, access_size, &global_descr)) { |
468 | global_descr.Print(bug_type); |
469 | return; |
470 | } |
471 | |
472 | StackAddressDescription stack_descr; |
473 | if (GetStackAddressInformation(addr, access_size, &stack_descr)) { |
474 | stack_descr.Print(); |
475 | return; |
476 | } |
477 | |
478 | HeapAddressDescription heap_descr; |
479 | if (GetHeapAddressInformation(addr, access_size, &heap_descr)) { |
480 | heap_descr.Print(); |
481 | return; |
482 | } |
483 | |
484 | // We exhausted our possibilities. Bail out. |
485 | Printf( |
486 | "AddressSanitizer can not describe address in more detail " |
487 | "(wild memory access suspected).\n"); |
488 | } |
489 | } // namespace __asan |