Enable malloc debug using environment variables

Previously malloc debug can be enabled only using global settings
accessible to the root user only. This CL adds a new option to enable
it using environment variables making it possible to use it with pure
native (shell) applications on production builds (from shell user) and
prepares it for using it from logwrapper on production devices.

Remove the old environment variable and property since they are not
necessary.

Test: Enable malloc debug using environment variable and verify
Test: that it only affects the commands launched from the shell.
Test: Enable malloc debug using the property variable and verify
Test: that it affects all commands.
Test: Run all unit tests in 32 bit and 64 bit.
Change-Id: Iecb75a3471552f619f196ad550c5f41fcd9ce8e5
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);
-}