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