1/*
2 * Copyright (C) 2014 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "BPlatform.h"
27#include "Environment.h"
28#include "ProcessCheck.h"
29#include <cstdlib>
30#include <cstring>
31#if BOS(DARWIN)
32#include <mach-o/dyld.h>
33#elif BOS(UNIX)
34#include <dlfcn.h>
35#endif
36
37#if BUSE(CHECK_NANO_MALLOC)
38extern "C" {
39#if __has_include(<malloc_private.h>)
40#include <malloc_private.h>
41#endif
42int malloc_engaged_nano(void);
43}
44#endif
45
46namespace bmalloc {
47
48static bool isMallocEnvironmentVariableSet()
49{
50 const char* list[] = {
51 "Malloc",
52 "MallocLogFile",
53 "MallocGuardEdges",
54 "MallocDoNotProtectPrelude",
55 "MallocDoNotProtectPostlude",
56 "MallocStackLogging",
57 "MallocStackLoggingNoCompact",
58 "MallocStackLoggingDirectory",
59 "MallocScribble",
60 "MallocCheckHeapStart",
61 "MallocCheckHeapEach",
62 "MallocCheckHeapSleep",
63 "MallocCheckHeapAbort",
64 "MallocErrorAbort",
65 "MallocCorruptionAbort",
66 "MallocHelp"
67 };
68 size_t size = sizeof(list) / sizeof(const char*);
69
70 for (size_t i = 0; i < size; ++i) {
71 if (getenv(list[i]))
72 return true;
73 }
74
75 return false;
76}
77
78static bool isLibgmallocEnabled()
79{
80 char* variable = getenv("DYLD_INSERT_LIBRARIES");
81 if (!variable)
82 return false;
83 if (!strstr(variable, "libgmalloc"))
84 return false;
85 return true;
86}
87
88static bool isSanitizerEnabled()
89{
90#if BOS(DARWIN)
91 static const char sanitizerPrefix[] = "/libclang_rt.";
92 static const char asanName[] = "asan_";
93 static const char tsanName[] = "tsan_";
94 uint32_t imageCount = _dyld_image_count();
95 for (uint32_t i = 0; i < imageCount; ++i) {
96 const char* imageName = _dyld_get_image_name(i);
97 if (!imageName)
98 continue;
99 if (const char* s = strstr(imageName, sanitizerPrefix)) {
100 const char* sanitizerName = s + sizeof(sanitizerPrefix) - 1;
101 if (!strncmp(sanitizerName, asanName, sizeof(asanName) - 1))
102 return true;
103 if (!strncmp(sanitizerName, tsanName, sizeof(tsanName) - 1))
104 return true;
105 }
106 }
107 return false;
108#elif BOS(UNIX)
109 void* handle = dlopen(nullptr, RTLD_NOW);
110 if (!handle)
111 return false;
112 bool result = !!dlsym(handle, "__asan_init") || !!dlsym(handle, "__tsan_init");
113 dlclose(handle);
114 return result;
115#else
116 return false;
117#endif
118}
119
120#if BUSE(CHECK_NANO_MALLOC)
121static bool isNanoMallocEnabled()
122{
123 int result = !!malloc_engaged_nano();
124 return result;
125}
126#endif
127
128DEFINE_STATIC_PER_PROCESS_STORAGE(Environment);
129
130Environment::Environment(std::lock_guard<Mutex>&)
131 : m_isDebugHeapEnabled(computeIsDebugHeapEnabled())
132{
133}
134
135bool Environment::computeIsDebugHeapEnabled()
136{
137 if (isMallocEnvironmentVariableSet())
138 return true;
139 if (isLibgmallocEnabled())
140 return true;
141 if (isSanitizerEnabled())
142 return true;
143#if BUSE(CHECK_NANO_MALLOC)
144 if (!isNanoMallocEnabled() && !shouldProcessUnconditionallyUseBmalloc())
145 return true;
146#endif
147 return false;
148}
149
150} // namespace bmalloc
151