Merge "Enable malloc debug using environment variables"
diff --git a/libc/bionic/malloc_common.cpp b/libc/bionic/malloc_common.cpp
index e050619..3fceb71 100644
--- a/libc/bionic/malloc_common.cpp
+++ b/libc/bionic/malloc_common.cpp
@@ -175,8 +175,7 @@
 static const char* DEBUG_SHARED_LIB = "libc_malloc_debug.so";
 static const char* DEBUG_MALLOC_PROPERTY_OPTIONS = "libc.debug.malloc.options";
 static const char* DEBUG_MALLOC_PROPERTY_PROGRAM = "libc.debug.malloc.program";
-static const char* DEBUG_MALLOC_PROPERTY_ENV_ENABLED = "libc.debug.malloc.env_enabled";
-static const char* DEBUG_MALLOC_ENV_ENABLE = "LIBC_DEBUG_MALLOC_ENABLE";
+static const char* DEBUG_MALLOC_ENV_OPTIONS = "LIBC_DEBUG_MALLOC_OPTIONS";
 
 static void* libc_malloc_impl_handle = nullptr;
 
@@ -309,20 +308,21 @@
 // Initializes memory allocation framework once per process.
 static void malloc_init_impl(libc_globals* globals) {
   char value[PROP_VALUE_MAX];
-  if (__system_property_get(DEBUG_MALLOC_PROPERTY_OPTIONS, value) == 0 || value[0] == '\0') {
-    return;
-  }
 
-  // Check to see if only a specific program should have debug malloc enabled.
-  if (__system_property_get(DEBUG_MALLOC_PROPERTY_PROGRAM, value) != 0 &&
-      strstr(getprogname(), value) == nullptr) {
-    return;
-  }
+  // If DEBUG_MALLOC_ENV_OPTIONS is set then it overrides the system properties.
+  const char* options = getenv(DEBUG_MALLOC_ENV_OPTIONS);
+  if (options == nullptr || options[0] == '\0') {
+    if (__system_property_get(DEBUG_MALLOC_PROPERTY_OPTIONS, value) == 0 || value[0] == '\0') {
+      return;
+    }
+    options = value;
 
-  // Check for the special environment variable instead.
-  if (__system_property_get(DEBUG_MALLOC_PROPERTY_ENV_ENABLED, value) != 0
-      && value[0] != '\0' && getenv(DEBUG_MALLOC_ENV_ENABLE) == nullptr) {
-    return;
+    // Check to see if only a specific program should have debug malloc enabled.
+    char program[PROP_VALUE_MAX];
+    if (__system_property_get(DEBUG_MALLOC_PROPERTY_PROGRAM, program) != 0 &&
+        strstr(getprogname(), program) == nullptr) {
+      return;
+    }
   }
 
   // Load the debug malloc shared library.
@@ -334,7 +334,7 @@
   }
 
   // Initialize malloc debugging in the loaded module.
-  auto init_func = reinterpret_cast<bool (*)(const MallocDispatch*, int*)>(
+  auto init_func = reinterpret_cast<bool (*)(const MallocDispatch*, int*, const char*)>(
       dlsym(malloc_impl_handle, "debug_initialize"));
   if (init_func == nullptr) {
     error_log("%s: debug_initialize routine not found in %s", getprogname(), DEBUG_SHARED_LIB);
@@ -374,7 +374,7 @@
     return;
   }
 
-  if (!init_func(&__libc_malloc_default_dispatch, &gMallocLeakZygoteChild)) {
+  if (!init_func(&__libc_malloc_default_dispatch, &gMallocLeakZygoteChild, options)) {
     dlclose(malloc_impl_handle);
     return;
   }
diff --git a/libc/malloc_debug/Android.bp b/libc/malloc_debug/Android.bp
index 8ce3ff3..708c101 100644
--- a/libc/malloc_debug/Android.bp
+++ b/libc/malloc_debug/Android.bp
@@ -111,7 +111,6 @@
         "tests/backtrace_fake.cpp",
         "tests/log_fake.cpp",
         "tests/libc_fake.cpp",
-        "tests/property_fake.cpp",
         "tests/malloc_debug_config_tests.cpp",
         "tests/malloc_debug_unit_tests.cpp",
     ],
diff --git a/libc/malloc_debug/Config.cpp b/libc/malloc_debug/Config.cpp
index c9fb850..cb75bd6 100644
--- a/libc/malloc_debug/Config.cpp
+++ b/libc/malloc_debug/Config.cpp
@@ -37,8 +37,6 @@
 #include <string>
 #include <vector>
 
-#include <sys/system_properties.h>
-
 #include <private/bionic_macros.h>
 
 #include "Config.h"
@@ -329,13 +327,7 @@
 
 // This function is designed to be called once. A second call will not
 // reset all variables.
-bool Config::SetFromProperties() {
-  char property_str[PROP_VALUE_MAX];
-  memset(property_str, 0, sizeof(property_str));
-  if (!__system_property_get("libc.debug.malloc.options", property_str)) {
-    return false;
-  }
-
+bool Config::Set(const char* options_str) {
   // Initialize a few default values.
   fill_alloc_value = DEFAULT_FILL_ALLOC_VALUE;
   fill_free_value = DEFAULT_FILL_FREE_VALUE;
@@ -426,7 +418,7 @@
   }
 
   // Process each property name we can find.
-  PropertyParser parser(property_str);
+  PropertyParser parser(options_str);
   bool valid = true;
   std::string property;
   std::string value;
diff --git a/libc/malloc_debug/Config.h b/libc/malloc_debug/Config.h
index ac620ad..ca56dc8 100644
--- a/libc/malloc_debug/Config.h
+++ b/libc/malloc_debug/Config.h
@@ -56,7 +56,7 @@
 constexpr uint64_t HEADER_OPTIONS = FRONT_GUARD | REAR_GUARD | BACKTRACE | FREE_TRACK | LEAK_TRACK;
 
 struct Config {
-  bool SetFromProperties();
+  bool Set(const char* str);
 
   size_t front_guard_bytes = 0;
   size_t rear_guard_bytes = 0;
diff --git a/libc/malloc_debug/DebugData.cpp b/libc/malloc_debug/DebugData.cpp
index fdc2810..339efdf 100644
--- a/libc/malloc_debug/DebugData.cpp
+++ b/libc/malloc_debug/DebugData.cpp
@@ -37,8 +37,8 @@
 #include "malloc_debug.h"
 #include "TrackData.h"
 
-bool DebugData::Initialize() {
-  if (!config_.SetFromProperties()) {
+bool DebugData::Initialize(const char* options) {
+  if (!config_.Set(options)) {
     return false;
   }
 
diff --git a/libc/malloc_debug/DebugData.h b/libc/malloc_debug/DebugData.h
index 7e2df0c..7228a72 100644
--- a/libc/malloc_debug/DebugData.h
+++ b/libc/malloc_debug/DebugData.h
@@ -49,7 +49,7 @@
   DebugData() = default;
   ~DebugData() = default;
 
-  bool Initialize();
+  bool Initialize(const char* options);
 
   static bool Disabled();
 
diff --git a/libc/malloc_debug/malloc_debug.cpp b/libc/malloc_debug/malloc_debug.cpp
index d2bcf99..bb16faa 100644
--- a/libc/malloc_debug/malloc_debug.cpp
+++ b/libc/malloc_debug/malloc_debug.cpp
@@ -62,7 +62,8 @@
 // ------------------------------------------------------------------------
 __BEGIN_DECLS
 
-bool debug_initialize(const MallocDispatch* malloc_dispatch, int* malloc_zygote_child);
+bool debug_initialize(const MallocDispatch* malloc_dispatch, int* malloc_zygote_child,
+    const char* options);
 void debug_finalize();
 void debug_get_malloc_leak_info(
     uint8_t** info, size_t* overall_size, size_t* info_size, size_t* total_memory,
@@ -178,8 +179,9 @@
   return g_debug->GetPointer(header);
 }
 
-bool debug_initialize(const MallocDispatch* malloc_dispatch, int* malloc_zygote_child) {
-  if (malloc_zygote_child == nullptr) {
+bool debug_initialize(const MallocDispatch* malloc_dispatch, int* malloc_zygote_child,
+    const char* options) {
+  if (malloc_zygote_child == nullptr || options == nullptr) {
     return false;
   }
 
@@ -194,7 +196,7 @@
   }
 
   DebugData* debug = new DebugData();
-  if (!debug->Initialize()) {
+  if (!debug->Initialize(options)) {
     delete debug;
     DebugDisableFinalize();
     return false;
diff --git a/libc/malloc_debug/tests/malloc_debug_config_tests.cpp b/libc/malloc_debug/tests/malloc_debug_config_tests.cpp
index 49edaba..f988124 100644
--- a/libc/malloc_debug/tests/malloc_debug_config_tests.cpp
+++ b/libc/malloc_debug/tests/malloc_debug_config_tests.cpp
@@ -25,8 +25,6 @@
 
 #include "log_fake.h"
 
-extern "C" int property_set(const char*, const char*);
-
 class MallocDebugConfigTest : public ::testing::Test {
  protected:
   void SetUp() override {
@@ -38,10 +36,9 @@
 
   std::unique_ptr<Config> config;
 
-  bool InitConfig(const char* property_value) {
+  bool InitConfig(const char* options) {
     config.reset(new Config);
-    property_set("libc.debug.malloc.options", property_value);
-    return config->SetFromProperties();
+    return config->Set(options);
   }
 };
 
diff --git a/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp b/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
index edb03f6..1b08a39 100644
--- a/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
+++ b/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
@@ -44,8 +44,7 @@
 
 __BEGIN_DECLS
 
-int property_set(const char*, const char*);
-bool debug_initialize(const MallocDispatch*, int*);
+bool debug_initialize(const MallocDispatch*, int*, const char*);
 void debug_finalize();
 
 void* debug_malloc(size_t);
@@ -98,10 +97,9 @@
     }
   }
 
-  void Init(const char* property_value) {
-    property_set("libc.debug.malloc.options", property_value);
+  void Init(const char* options) {
     zygote = 0;
-    ASSERT_TRUE(debug_initialize(&dispatch, &zygote));
+    ASSERT_TRUE(debug_initialize(&dispatch, &zygote, options));
     initialized = true;
   }
 
diff --git a/libc/malloc_debug/tests/property_fake.cpp b/libc/malloc_debug/tests/property_fake.cpp
deleted file mode 100644
index d9f0ad8..0000000
--- a/libc/malloc_debug/tests/property_fake.cpp
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <string.h>
-
-#include <string>
-#include <unordered_map>
-
-#include <sys/system_properties.h>
-
-std::unordered_map<std::string, std::string> g_properties;
-
-extern "C" int property_set(const char* name, const char* value) {
-  if (g_properties.count(name) != 0) {
-    g_properties.erase(name);
-  }
-  g_properties[name] = value;
-  return 0;
-}
-
-extern "C" int property_get(const char* key, char* value, const char* default_value) {
-  if (g_properties.count(key) == 0) {
-    if (default_value == nullptr) {
-      return 0;
-    }
-    strncpy(value, default_value, PROP_VALUE_MAX-1);
-  } else {
-    strncpy(value, g_properties[key].c_str(), PROP_VALUE_MAX-1);
-  }
-  value[PROP_VALUE_MAX-1] = '\0';
-  return strlen(value);
-}
-
-extern "C" int __system_property_get(const char* key, char* value) {
-  if (g_properties.count(key) == 0) {
-    return 0;
-  } else {
-    strncpy(value, g_properties[key].c_str(), PROP_VALUE_MAX-1);
-  }
-  value[PROP_VALUE_MAX-1] = '\0';
-  return strlen(value);
-}