diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.cpp --- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.cpp @@ -14,10 +14,6 @@ #include "sanitizer_platform.h" #if SANITIZER_MAC -#include "sanitizer_allocator_internal.h" -#include "sanitizer_mac.h" -#include "sanitizer_symbolizer_mac.h" - #include #include #include @@ -25,6 +21,10 @@ #include #include +#include "sanitizer_allocator_internal.h" +#include "sanitizer_mac.h" +#include "sanitizer_symbolizer_mac.h" + namespace __sanitizer { bool DlAddrSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) { @@ -50,11 +50,13 @@ return true; } + class AtosSymbolizerProcess : public SymbolizerProcess { public: explicit AtosSymbolizerProcess(const char *path) : SymbolizerProcess(path, /*use_posix_spawn*/ true) { pid_str_[0] = '\0'; + internal_memset(custom_env_, 0, sizeof(custom_env_)); } private: @@ -65,6 +67,10 @@ // the call to GetArgV. internal_snprintf(pid_str_, sizeof(pid_str_), "%d", internal_getpid()); + // Prepare the copy of the environment. + char **current_env = GetEnviron(); + CopyEnv(current_env); + return SymbolizerProcess::StartSymbolizerSubprocess(); } @@ -72,6 +78,37 @@ return (length >= 1 && buffer[length - 1] == '\n'); } + void CopyEnv(char **current_env) { + // Count number of elements (excluding nullptr entry). + uptr count = 0; + for (; current_env[count] != nullptr; ++count) { + } + + // +1 for nullptr terminator. + uptr custom_env_required_entries = count + 1; + uptr entries_to_copy = count; + + if (custom_env_required_entries > kMaxNumEnvPEntries) { + // Will have to truncate the copy of the environment. + Report( + "WARNING: Truncating symbolizer environment. Needed %llu entries but " + "only %llu are available.\n", + custom_env_required_entries, kMaxNumEnvPEntries); + entries_to_copy = kMaxNumEnvPEntries - 1; + custom_env_required_entries = kMaxNumEnvPEntries; + } + + // Copy over existing entries + CHECK_LE(entries_to_copy, kMaxNumEnvPEntries); + internal_memcpy(custom_env_, current_env, entries_to_copy * sizeof(uptr)); + // Null terminate the array. + custom_env_[custom_env_required_entries - 1] = nullptr; + } + + char **GetEnvP() override { + return custom_env_; + } + void GetArgV(const char *path_to_binary, const char *(&argv)[kArgVMax]) const override { int i = 0; @@ -88,6 +125,9 @@ } char pid_str_[16]; + // Use statically allocated array to avoid allocation at symbolization time. + static const uptr kMaxNumEnvPEntries = 512; + char *custom_env_[kMaxNumEnvPEntries]; }; static bool ParseCommandOutput(const char *str, uptr addr, char **out_name, diff --git a/compiler-rt/test/sanitizer_common/TestCases/Darwin/symbolizer-large-env.cpp b/compiler-rt/test/sanitizer_common/TestCases/Darwin/symbolizer-large-env.cpp new file mode 100644 --- /dev/null +++ b/compiler-rt/test/sanitizer_common/TestCases/Darwin/symbolizer-large-env.cpp @@ -0,0 +1,48 @@ +// RUN: %clangxx %s -g -O0 -o %t +// RUN: %run %t 2>&1 | FileCheck %s +#include +#include +#include +#include +#include + +extern "C" char ***_NSGetEnviron(void); + +size_t get_num_env_entries() { + char **envp = *_NSGetEnviron(); + size_t count = 0; + for (; envp[count]; ++count) { + } + return count; +} + +const size_t kMaxNumEnvPEntries = 512; + +int main() { + size_t current_entries = get_num_env_entries(); + fprintf(stderr, "current_entries: %lu\n", current_entries); + size_t entries_to_add = (kMaxNumEnvPEntries - current_entries); + fprintf(stderr, "Adding %lu entries\n", entries_to_add); + + // Add a large number of entries. In particular more than the sanitizer + // run time allows for. + char buffer[256]; + for (int count = 0; count < entries_to_add; ++count) { + int chars_written = snprintf(buffer, sizeof(buffer), "__UNLIKELY_ENV_VAR__%d", count); + assert(chars_written); + if (setenv(buffer, "some_value", /*overwrite*/ 1)) { + fprintf(stderr, "Failed to write \"%s\" to env\n", buffer); + return 1; + } + } + current_entries = get_num_env_entries(); + assert(current_entries >= kMaxNumEnvPEntries); + + // Trigger symbolization. + // CHECK: WARNING: Truncating symbolizer environment. Needed 513 entries but only 512 are available. + // CHECK: #0{{( *0x.* *in *)?}} __sanitizer_print_stack_trace + // CHECK: #1{{( *0x.* *in *)?}} main {{.*}}symbolizer-large-env.cpp:[[@LINE+1]] + __sanitizer_print_stack_trace(); + + return 0; +}