1 // Copyright 2011 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef PARTITION_ALLOC_PARTITION_ALLOC_BASE_DEBUG_ALIAS_H_ 6 #define PARTITION_ALLOC_PARTITION_ALLOC_BASE_DEBUG_ALIAS_H_ 7 8 #include <cstddef> 9 10 #include "partition_alloc/partition_alloc_base/component_export.h" 11 12 namespace partition_alloc::internal::base::debug { 13 14 // Make the optimizer think that |var| is aliased. This can be used to inhibit 15 // three different kinds of optimizations: 16 // 17 // Case #1: Prevent a local variable from being optimized out if it would not 18 // otherwise be live at the point of a potential crash. This can only be done 19 // with local variables, not globals, object members, or function return values 20 // - these must be copied to locals if you want to ensure they are recorded in 21 // crash dumps. Function arguments are fine to use since the 22 // base::debug::Alias() call on them will make sure they are copied to the stack 23 // even if they were passed in a register. Note that if the local variable is a 24 // pointer then its value will be retained but the memory that it points to will 25 // probably not be saved in the crash dump - by default only stack memory is 26 // saved. Therefore the aliasing technique is usually only worthwhile with 27 // non-pointer variables. If you have a pointer to an object and you want to 28 // retain the object's state you need to copy the object or its fields to local 29 // variables. 30 // 31 // Example usage: 32 // int last_error = err_; 33 // base::debug::Alias(&last_error); 34 // char name_copy[16]; 35 // strncpy(name_copy, p->name, sizeof(name_copy)-1); 36 // name_copy[sizeof(name_copy)-1] = '\0';; 37 // base::debug::alias(name_copy); 38 // CHECK(false); 39 // 40 // Case #2: Prevent a tail call into a function. This is useful to make sure the 41 // function containing the call to base::debug::Alias() will be present in the 42 // call stack. In this case there is no memory that needs to be on 43 // the stack so we can use nullptr. The call to base::debug::Alias() needs to 44 // happen after the call that is suspected to be tail called. Note: This 45 // technique will prevent tail calls at the specific call site only. To prevent 46 // them for all invocations of a function look at PA_NOT_TAIL_CALLED. 47 // 48 // Example usage: 49 // PA_NOINLINE void Foo(){ 50 // ... code ... 51 // 52 // Bar(); 53 // base::debug::Alias(nullptr); 54 // } 55 // 56 // Case #3: Prevent code folding of a non-unique function. Code folding can 57 // cause the same address to be assigned to different functions if they are 58 // identical. If finding the precise signature of a function in the call-stack 59 // is important and it's suspected the function is identical to other functions 60 // it can be made unique using PA_NO_CODE_FOLDING which is a wrapper around 61 // base::debug::Alias(); 62 // 63 // Example usage: 64 // PA_NOINLINE void Foo(){ 65 // PA_NO_CODE_FOLDING(); 66 // Bar(); 67 // } 68 // 69 // Finally please note that these effects compound. This means that saving a 70 // stack variable (case #1) using base::debug::Alias() will also inhibit 71 // tail calls for calls in earlier lines and prevent code folding. 72 73 void PA_COMPONENT_EXPORT(PARTITION_ALLOC_BASE) Alias(const void* var); 74 75 } // namespace partition_alloc::internal::base::debug 76 77 // Code folding is a linker optimization whereby the linker identifies functions 78 // that are bit-identical and overlays them. This saves space but it leads to 79 // confusing call stacks because multiple symbols are at the same address and 80 // it is unpredictable which one will be displayed. Disabling of code folding is 81 // particularly useful when function names are used as signatures in crashes. 82 // This macro doesn't guarantee that code folding will be prevented but it 83 // greatly reduces the odds and always prevents it within one source file. 84 // If using in a function that terminates the process it is safest to put the 85 // PA_NO_CODE_FOLDING macro at the top of the function. 86 // Use like: 87 // void FooBarFailure(size_t size) { PA_NO_CODE_FOLDING(); OOM_CRASH(size); } 88 #define PA_NO_CODE_FOLDING() \ 89 const int line_number = __LINE__; \ 90 ::partition_alloc::internal::base::debug::Alias(&line_number) 91 92 #endif // PARTITION_ALLOC_PARTITION_ALLOC_BASE_DEBUG_ALIAS_H_ 93