summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/elf_writer_test.cc12
-rw-r--r--compiler/linker/arm64/relative_patcher_arm64_test.cc22
-rw-r--r--compiler/optimizing/code_generator_arm.cc4
-rw-r--r--compiler/optimizing/code_generator_arm64.cc4
-rw-r--r--compiler/utils/intrusive_forward_list_test.cc12
-rw-r--r--runtime/Android.bp1
-rw-r--r--runtime/entrypoints/quick/quick_entrypoints_enum.cc69
-rw-r--r--runtime/entrypoints/quick/quick_entrypoints_enum.h2
-rw-r--r--runtime/entrypoints_order_test.cc7
-rw-r--r--runtime/gc/space/space_test.h2
-rw-r--r--runtime/instrumentation_test.cc2
-rw-r--r--runtime/jni_internal_test.cc7
-rw-r--r--runtime/mirror/class.h2
-rw-r--r--runtime/oat_file_assistant_test.cc8
-rw-r--r--runtime/runtime.cc41
-rw-r--r--runtime/runtime.h20
-rw-r--r--runtime/utils.cc11
-rw-r--r--runtime/utils.h3
-rw-r--r--runtime/utils_test.cc53
-rw-r--r--test/901-hello-ti-agent/basics.cc2
20 files changed, 243 insertions, 41 deletions
diff --git a/compiler/elf_writer_test.cc b/compiler/elf_writer_test.cc
index 449f514184..d5f16637be 100644
--- a/compiler/elf_writer_test.cc
+++ b/compiler/elf_writer_test.cc
@@ -38,16 +38,16 @@ class ElfWriterTest : public CommonCompilerTest {
#define EXPECT_ELF_FILE_ADDRESS(ef, expected_value, symbol_name, build_map) \
do { \
- void* addr = reinterpret_cast<void*>(ef->FindSymbolAddress(SHT_DYNSYM, \
- symbol_name, \
- build_map)); \
+ void* addr = reinterpret_cast<void*>((ef)->FindSymbolAddress(SHT_DYNSYM, \
+ symbol_name, \
+ build_map)); \
EXPECT_NE(nullptr, addr); \
EXPECT_LT(static_cast<uintptr_t>(ART_BASE_ADDRESS), reinterpret_cast<uintptr_t>(addr)); \
- if (expected_value == nullptr) { \
- expected_value = addr; \
+ if ((expected_value) == nullptr) { \
+ (expected_value) = addr; \
} \
EXPECT_EQ(expected_value, addr); \
- EXPECT_EQ(expected_value, ef->FindDynamicSymbolAddress(symbol_name)); \
+ EXPECT_EQ(expected_value, (ef)->FindDynamicSymbolAddress(symbol_name)); \
} while (false)
TEST_F(ElfWriterTest, dlsym) {
diff --git a/compiler/linker/arm64/relative_patcher_arm64_test.cc b/compiler/linker/arm64/relative_patcher_arm64_test.cc
index 573de736c4..9932c79a96 100644
--- a/compiler/linker/arm64/relative_patcher_arm64_test.cc
+++ b/compiler/linker/arm64/relative_patcher_arm64_test.cc
@@ -701,7 +701,7 @@ TEST_F(Arm64RelativePatcherTestDefault, StringReference4) {
#define DEFAULT_LDUR_LDR_TEST(adrp_offset, disp) \
TEST_F(Arm64RelativePatcherTestDefault, DexCacheReference ## adrp_offset ## Ldur ## disp) { \
- bool has_thunk = (adrp_offset == 0xff8u || adrp_offset == 0xffcu); \
+ bool has_thunk = ((adrp_offset) == 0xff8u || (adrp_offset) == 0xffcu); \
TestAdrpLdurLdr(adrp_offset, has_thunk, 0x12345678u, disp); \
}
@@ -725,8 +725,8 @@ TEST_FOR_OFFSETS(LDRW_PCREL_LDR_TEST, 0x1234, 0x1238)
// LDR <Xt>, <label> is aligned when offset + displacement is a multiple of 8.
#define LDRX_PCREL_LDR_TEST(adrp_offset, disp) \
TEST_F(Arm64RelativePatcherTestDefault, DexCacheReference ## adrp_offset ## XPcRel ## disp) { \
- bool unaligned = !IsAligned<8u>(adrp_offset + 4u + static_cast<uint32_t>(disp)); \
- bool has_thunk = (adrp_offset == 0xff8u || adrp_offset == 0xffcu) && unaligned; \
+ bool unaligned = !IsAligned<8u>((adrp_offset) + 4u + static_cast<uint32_t>(disp)); \
+ bool has_thunk = ((adrp_offset) == 0xff8u || (adrp_offset) == 0xffcu) && unaligned; \
TestAdrpLdrPcRelLdr(kLdrXPcRelInsn, disp, adrp_offset, has_thunk, 0x12345678u, 0x1234u); \
}
@@ -735,21 +735,21 @@ TEST_FOR_OFFSETS(LDRX_PCREL_LDR_TEST, 0x1234, 0x1238)
// LDR <Wt>, [SP, #<pimm>] and LDR <Xt>, [SP, #<pimm>] are always aligned. No fixup needed.
#define LDRW_SPREL_LDR_TEST(adrp_offset, disp) \
TEST_F(Arm64RelativePatcherTestDefault, DexCacheReference ## adrp_offset ## WSpRel ## disp) { \
- TestAdrpLdrSpRelLdr(kLdrWSpRelInsn, disp >> 2, adrp_offset, false, 0x12345678u, 0x1234u); \
+ TestAdrpLdrSpRelLdr(kLdrWSpRelInsn, (disp) >> 2, adrp_offset, false, 0x12345678u, 0x1234u); \
}
TEST_FOR_OFFSETS(LDRW_SPREL_LDR_TEST, 0, 4)
#define LDRX_SPREL_LDR_TEST(adrp_offset, disp) \
TEST_F(Arm64RelativePatcherTestDefault, DexCacheReference ## adrp_offset ## XSpRel ## disp) { \
- TestAdrpLdrSpRelLdr(kLdrXSpRelInsn, disp >> 3, adrp_offset, false, 0x12345678u, 0x1234u); \
+ TestAdrpLdrSpRelLdr(kLdrXSpRelInsn, (disp) >> 3, adrp_offset, false, 0x12345678u, 0x1234u); \
}
TEST_FOR_OFFSETS(LDRX_SPREL_LDR_TEST, 0, 8)
#define DEFAULT_LDUR_ADD_TEST(adrp_offset, disp) \
TEST_F(Arm64RelativePatcherTestDefault, StringReference ## adrp_offset ## Ldur ## disp) { \
- bool has_thunk = (adrp_offset == 0xff8u || adrp_offset == 0xffcu); \
+ bool has_thunk = ((adrp_offset) == 0xff8u || (adrp_offset) == 0xffcu); \
TestAdrpLdurAdd(adrp_offset, has_thunk, disp); \
}
@@ -793,7 +793,7 @@ TEST_FOR_OFFSETS(DEFAULT_ADDX0X0_ADD_TEST, 0x12345678, 0xffffc840)
TEST_F(Arm64RelativePatcherTestDefault, StringReference ## adrp_offset ## AddsX0X2 ## disp) { \
/* ADDS that does not use the result of "ADRP x0, addr" but overwrites that register. */ \
uint32_t adds = kAddsXInsn | (100 << 10) | (2u << 5) | 0u; /* ADDS x0, x2, #100 */ \
- bool has_thunk = (adrp_offset == 0xff8u || adrp_offset == 0xffcu); \
+ bool has_thunk = ((adrp_offset) == 0xff8u || (adrp_offset) == 0xffcu); \
TestAdrpInsn2Add(adds, adrp_offset, has_thunk, disp); \
}
@@ -810,8 +810,8 @@ TEST_FOR_OFFSETS(LDRW_PCREL_ADD_TEST, 0x1234, 0x1238)
// LDR <Xt>, <label> is aligned when offset + displacement is a multiple of 8.
#define LDRX_PCREL_ADD_TEST(adrp_offset, disp) \
TEST_F(Arm64RelativePatcherTestDefault, StringReference ## adrp_offset ## XPcRel ## disp) { \
- bool unaligned = !IsAligned<8u>(adrp_offset + 4u + static_cast<uint32_t>(disp)); \
- bool has_thunk = (adrp_offset == 0xff8u || adrp_offset == 0xffcu) && unaligned; \
+ bool unaligned = !IsAligned<8u>((adrp_offset) + 4u + static_cast<uint32_t>(disp)); \
+ bool has_thunk = ((adrp_offset) == 0xff8u || (adrp_offset) == 0xffcu) && unaligned; \
TestAdrpLdrPcRelAdd(kLdrXPcRelInsn, disp, adrp_offset, has_thunk, 0x12345678u); \
}
@@ -820,14 +820,14 @@ TEST_FOR_OFFSETS(LDRX_PCREL_ADD_TEST, 0x1234, 0x1238)
// LDR <Wt>, [SP, #<pimm>] and LDR <Xt>, [SP, #<pimm>] are always aligned. No fixup needed.
#define LDRW_SPREL_ADD_TEST(adrp_offset, disp) \
TEST_F(Arm64RelativePatcherTestDefault, StringReference ## adrp_offset ## WSpRel ## disp) { \
- TestAdrpLdrSpRelAdd(kLdrWSpRelInsn, disp >> 2, adrp_offset, false, 0x12345678u); \
+ TestAdrpLdrSpRelAdd(kLdrWSpRelInsn, (disp) >> 2, adrp_offset, false, 0x12345678u); \
}
TEST_FOR_OFFSETS(LDRW_SPREL_ADD_TEST, 0, 4)
#define LDRX_SPREL_ADD_TEST(adrp_offset, disp) \
TEST_F(Arm64RelativePatcherTestDefault, StringReference ## adrp_offset ## XSpRel ## disp) { \
- TestAdrpLdrSpRelAdd(kLdrXSpRelInsn, disp >> 3, adrp_offset, false, 0x12345678u); \
+ TestAdrpLdrSpRelAdd(kLdrXSpRelInsn, (disp) >> 3, adrp_offset, false, 0x12345678u); \
}
TEST_FOR_OFFSETS(LDRX_SPREL_ADD_TEST, 0, 8)
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index d8866a92c1..16072d9c25 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -1209,7 +1209,9 @@ void CodeGeneratorARM::InvokeRuntime(QuickEntrypointEnum entrypoint,
SlowPathCode* slow_path) {
ValidateInvokeRuntime(instruction, slow_path);
GenerateInvokeRuntime(GetThreadOffset<kArmPointerSize>(entrypoint).Int32Value());
- RecordPcInfo(instruction, dex_pc, slow_path);
+ if (EntrypointRequiresStackMap(entrypoint)) {
+ RecordPcInfo(instruction, dex_pc, slow_path);
+ }
}
void CodeGeneratorARM::InvokeRuntimeWithoutRecordingPcInfo(int32_t entry_point_offset,
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index 17fc13cf65..933f3e6883 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -1485,7 +1485,9 @@ void CodeGeneratorARM64::InvokeRuntime(QuickEntrypointEnum entrypoint,
SlowPathCode* slow_path) {
ValidateInvokeRuntime(instruction, slow_path);
GenerateInvokeRuntime(GetThreadOffset<kArm64PointerSize>(entrypoint).Int32Value());
- RecordPcInfo(instruction, dex_pc, slow_path);
+ if (EntrypointRequiresStackMap(entrypoint)) {
+ RecordPcInfo(instruction, dex_pc, slow_path);
+ }
}
void CodeGeneratorARM64::InvokeRuntimeWithoutRecordingPcInfo(int32_t entry_point_offset,
diff --git a/compiler/utils/intrusive_forward_list_test.cc b/compiler/utils/intrusive_forward_list_test.cc
index 517142e1b5..f2efa4dd15 100644
--- a/compiler/utils/intrusive_forward_list_test.cc
+++ b/compiler/utils/intrusive_forward_list_test.cc
@@ -39,12 +39,12 @@ bool operator<(const IFLTestValue& lhs, const IFLTestValue& rhs) {
return lhs.value < rhs.value;
}
-#define ASSERT_LISTS_EQUAL(expected, value) \
- do { \
- ASSERT_EQ(expected.empty(), value.empty()); \
- ASSERT_EQ(std::distance(expected.begin(), expected.end()), \
- std::distance(value.begin(), value.end())); \
- ASSERT_TRUE(std::equal(expected.begin(), expected.end(), value.begin())); \
+#define ASSERT_LISTS_EQUAL(expected, value) \
+ do { \
+ ASSERT_EQ((expected).empty(), (value).empty()); \
+ ASSERT_EQ(std::distance((expected).begin(), (expected).end()), \
+ std::distance((value).begin(), (value).end())); \
+ ASSERT_TRUE(std::equal((expected).begin(), (expected).end(), (value).begin())); \
} while (false)
TEST(IntrusiveForwardList, IteratorToConstIterator) {
diff --git a/runtime/Android.bp b/runtime/Android.bp
index c92df4e298..04aacfc50d 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -220,6 +220,7 @@ cc_defaults {
"entrypoints/quick/quick_cast_entrypoints.cc",
"entrypoints/quick/quick_deoptimization_entrypoints.cc",
"entrypoints/quick/quick_dexcache_entrypoints.cc",
+ "entrypoints/quick/quick_entrypoints_enum.cc",
"entrypoints/quick/quick_field_entrypoints.cc",
"entrypoints/quick/quick_fillarray_entrypoints.cc",
"entrypoints/quick/quick_instrumentation_entrypoints.cc",
diff --git a/runtime/entrypoints/quick/quick_entrypoints_enum.cc b/runtime/entrypoints/quick/quick_entrypoints_enum.cc
new file mode 100644
index 0000000000..5153f0f48e
--- /dev/null
+++ b/runtime/entrypoints/quick/quick_entrypoints_enum.cc
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2016 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 "quick_entrypoints_enum.h"
+
+namespace art {
+
+bool EntrypointRequiresStackMap(QuickEntrypointEnum trampoline) {
+ // Entrypoints that do not require a stackmap. In general leaf methods
+ // outside of the VM that are not safepoints.
+ switch (trampoline) {
+ // Listed in the same order as in quick_entrypoints_list.h.
+ case kQuickCmpgDouble:
+ case kQuickCmpgFloat:
+ case kQuickCmplDouble:
+ case kQuickCmplFloat:
+ case kQuickCos:
+ case kQuickSin:
+ case kQuickAcos:
+ case kQuickAsin:
+ case kQuickAtan:
+ case kQuickAtan2:
+ case kQuickCbrt:
+ case kQuickCosh:
+ case kQuickExp:
+ case kQuickExpm1:
+ case kQuickHypot:
+ case kQuickLog:
+ case kQuickLog10:
+ case kQuickNextAfter:
+ case kQuickSinh:
+ case kQuickTan:
+ case kQuickTanh:
+ case kQuickFmod:
+ case kQuickL2d:
+ case kQuickFmodf:
+ case kQuickL2f:
+ case kQuickD2iz:
+ case kQuickF2iz:
+ case kQuickIdivmod:
+ case kQuickD2l:
+ case kQuickF2l:
+ case kQuickLdiv:
+ case kQuickLmod:
+ case kQuickLmul:
+ case kQuickShlLong:
+ case kQuickShrLong:
+ case kQuickUshrLong:
+ return false;
+
+ default:
+ return true;
+ }
+}
+
+} // namespace art
diff --git a/runtime/entrypoints/quick/quick_entrypoints_enum.h b/runtime/entrypoints/quick/quick_entrypoints_enum.h
index 8de1137feb..7674873731 100644
--- a/runtime/entrypoints/quick/quick_entrypoints_enum.h
+++ b/runtime/entrypoints/quick/quick_entrypoints_enum.h
@@ -62,6 +62,8 @@ template <> inline void CheckEntrypointTypes<kQuick ## name, __VA_ARGS__>() {};
#undef QUICK_ENTRYPOINT_LIST
#undef ENTRYPOINT_ENUM
+bool EntrypointRequiresStackMap(QuickEntrypointEnum trampoline);
+
} // namespace art
#endif // ART_RUNTIME_ENTRYPOINTS_QUICK_QUICK_ENTRYPOINTS_ENUM_H_
diff --git a/runtime/entrypoints_order_test.cc b/runtime/entrypoints_order_test.cc
index 004cdc47b9..b102334418 100644
--- a/runtime/entrypoints_order_test.cc
+++ b/runtime/entrypoints_order_test.cc
@@ -37,7 +37,7 @@ namespace art {
// name.
#define EXPECT_OFFSET_DIFF(first_type, first_field, second_type, second_field, diff, name) \
CHECKED(OFFSETOF_MEMBER(second_type, second_field) \
- - OFFSETOF_MEMBER(first_type, first_field) == diff, name)
+ - OFFSETOF_MEMBER(first_type, first_field) == (diff), name)
// Helper macro for when the fields are from the same type.
#define EXPECT_OFFSET_DIFFNP(type, first_field, second_field, diff) \
@@ -45,15 +45,16 @@ namespace art {
type ## _ ## first_field ## _ ## second_field)
// Helper macro for when the fields are from the same type and in the same member of said type.
+// NOLINT, do not add parentheses around 'prefix'.
#define EXPECT_OFFSET_DIFFP(type, prefix, first_field, second_field, diff) \
- EXPECT_OFFSET_DIFF(type, prefix . first_field, type, prefix . second_field, diff, \
+ EXPECT_OFFSET_DIFF(type, prefix . first_field, type, prefix . second_field, diff, /* NOLINT */ \
type ## _ ## prefix ## _ ## first_field ## _ ## second_field)
// Macro to check whether two fields have at least an expected difference in offsets. The error is
// named name.
#define EXPECT_OFFSET_DIFF_GT(first_type, first_field, second_type, second_field, diff, name) \
CHECKED(OFFSETOF_MEMBER(second_type, second_field) \
- - OFFSETOF_MEMBER(first_type, first_field) >= diff, name)
+ - OFFSETOF_MEMBER(first_type, first_field) >= (diff), name)
// Helper macro for when the fields are from the same type.
#define EXPECT_OFFSET_DIFF_GT3(type, first_field, second_field, diff, name) \
diff --git a/runtime/gc/space/space_test.h b/runtime/gc/space/space_test.h
index 20ef44a77d..23e937d34a 100644
--- a/runtime/gc/space/space_test.h
+++ b/runtime/gc/space/space_test.h
@@ -354,7 +354,7 @@ void SpaceTest<Super>::SizeFootPrintGrowthLimitAndTrimDriver(size_t object_size,
#define TEST_SizeFootPrintGrowthLimitAndTrimRandom(name, spaceName, spaceFn, size) \
TEST_F(spaceName##RandomTest, SizeFootPrintGrowthLimitAndTrim_RandomAllocationsWithMax_##name) { \
- SizeFootPrintGrowthLimitAndTrimDriver(-size, spaceFn); \
+ SizeFootPrintGrowthLimitAndTrimDriver(-(size), spaceFn); \
}
#define TEST_SPACE_CREATE_FN_STATIC(spaceName, spaceFn) \
diff --git a/runtime/instrumentation_test.cc b/runtime/instrumentation_test.cc
index 684c471727..2cc35cfdce 100644
--- a/runtime/instrumentation_test.cc
+++ b/runtime/instrumentation_test.cc
@@ -588,7 +588,7 @@ TEST_F(InstrumentationTest, MethodTracing_InstrumentationEntryExitStubs) {
do { \
Instrumentation* const instr = Runtime::Current()->GetInstrumentation(); \
bool interpreter = \
- (_level == Instrumentation::InstrumentationLevel::kInstrumentWithInterpreter); \
+ ((_level) == Instrumentation::InstrumentationLevel::kInstrumentWithInterpreter); \
EXPECT_EQ(_level, GetCurrentInstrumentationLevel()); \
EXPECT_EQ(_user_count, GetInstrumentationUserCount()); \
if (instr->IsForcedInterpretOnly()) { \
diff --git a/runtime/jni_internal_test.cc b/runtime/jni_internal_test.cc
index 64954743d4..fe0081c2d4 100644
--- a/runtime/jni_internal_test.cc
+++ b/runtime/jni_internal_test.cc
@@ -1105,8 +1105,9 @@ TEST_F(JniInternalTest, RegisterAndUnregisterNatives) {
ExpectException(aioobe_); \
\
/* Prepare a couple of buffers. */ \
- std::unique_ptr<scalar_type[]> src_buf(new scalar_type[size]); \
- std::unique_ptr<scalar_type[]> dst_buf(new scalar_type[size]); \
+ /* NOLINT, no parentheses around scalar_type. */ \
+ std::unique_ptr<scalar_type[]> src_buf(new scalar_type[size]); /* NOLINT */ \
+ std::unique_ptr<scalar_type[]> dst_buf(new scalar_type[size]); /* NOLINT */ \
for (jsize i = 0; i < size; ++i) { src_buf[i] = scalar_type(i); } \
for (jsize i = 0; i < size; ++i) { dst_buf[i] = scalar_type(-1); } \
\
@@ -1131,7 +1132,7 @@ TEST_F(JniInternalTest, RegisterAndUnregisterNatives) {
<< "GetPrimitiveArrayCritical not equal"; \
env_->ReleasePrimitiveArrayCritical(a, v, 0); \
/* GetXArrayElements */ \
- scalar_type* xs = env_->get_elements_fn(a, nullptr); \
+ scalar_type* xs = env_->get_elements_fn(a, nullptr); /* NOLINT, scalar_type */ \
EXPECT_EQ(memcmp(&src_buf[0], xs, size * sizeof(scalar_type)), 0) \
<< # get_elements_fn " not equal"; \
env_->release_elements_fn(a, xs, 0); \
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index 21af15ed33..1fed190256 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -571,7 +571,7 @@ class MANAGED Class FINAL : public Object {
// The size of java.lang.Class.class.
static uint32_t ClassClassSize(PointerSize pointer_size) {
// The number of vtable entries in java.lang.Class.
- uint32_t vtable_entries = Object::kVTableLength + 71;
+ uint32_t vtable_entries = Object::kVTableLength + 72;
return ComputeClassSize(true, vtable_entries, 0, 0, 4, 1, 0, pointer_size);
}
diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc
index 05c5a22452..6ec5e55745 100644
--- a/runtime/oat_file_assistant_test.cc
+++ b/runtime/oat_file_assistant_test.cc
@@ -87,8 +87,10 @@ class OatFileAssistantTest : public Dex2oatEnvironmentTest {
bool with_patch_info = true) {
// Temporarily redirect the dalvik cache so dex2oat doesn't find the
// relocated image file.
- std::string android_data_tmp = GetScratchDir() + "AndroidDataTmp";
- setenv("ANDROID_DATA", android_data_tmp.c_str(), 1);
+ std::string dalvik_cache = GetDalvikCache(GetInstructionSetString(kRuntimeISA));
+ std::string dalvik_cache_tmp = dalvik_cache + ".redirected";
+ ASSERT_EQ(0, rename(dalvik_cache.c_str(), dalvik_cache_tmp.c_str())) << strerror(errno);
+
std::vector<std::string> args;
args.push_back("--dex-file=" + dex_location);
args.push_back("--oat-file=" + odex_location);
@@ -106,7 +108,7 @@ class OatFileAssistantTest : public Dex2oatEnvironmentTest {
std::string error_msg;
ASSERT_TRUE(OatFileAssistant::Dex2Oat(args, &error_msg)) << error_msg;
- setenv("ANDROID_DATA", android_data_.c_str(), 1);
+ ASSERT_EQ(0, rename(dalvik_cache_tmp.c_str(), dalvik_cache.c_str())) << strerror(errno);
// Verify the odex file was generated as expected and really is
// unrelocated.
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index ddcfb6d5aa..f3fcd34de9 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -26,6 +26,9 @@
#include <signal.h>
#include <sys/syscall.h>
#include "base/memory_tool.h"
+#if defined(__APPLE__)
+#include <crt_externs.h> // for _NSGetEnviron
+#endif
#include <cstdio>
#include <cstdlib>
@@ -156,6 +159,22 @@ struct TraceConfig {
size_t trace_file_size;
};
+namespace {
+#ifdef __APPLE__
+inline char** GetEnviron() {
+ // When Google Test is built as a framework on MacOS X, the environ variable
+ // is unavailable. Apple's documentation (man environ) recommends using
+ // _NSGetEnviron() instead.
+ return *_NSGetEnviron();
+}
+#else
+// Some POSIX platforms expect you to declare environ. extern "C" makes
+// it reside in the global namespace.
+extern "C" char** environ;
+inline char** GetEnviron() { return environ; }
+#endif
+} // namespace
+
Runtime::Runtime()
: resolution_method_(nullptr),
imt_conflict_method_(nullptr),
@@ -904,6 +923,10 @@ void Runtime::SetSentinel(mirror::Object* sentinel) {
}
bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) {
+ // (b/30160149): protect subprocesses from modifications to LD_LIBRARY_PATH, etc.
+ // Take a snapshot of the environment at the time the runtime was created, for use by Exec, etc.
+ env_snapshot_.TakeSnapshot();
+
RuntimeArgumentMap runtime_options(std::move(runtime_options_in));
ScopedTrace trace(__FUNCTION__);
CHECK_EQ(sysconf(_SC_PAGE_SIZE), kPageSize);
@@ -2021,4 +2044,22 @@ bool Runtime::UseJitCompilation() const {
return (jit_ != nullptr) && jit_->UseJitCompilation();
}
+void Runtime::EnvSnapshot::TakeSnapshot() {
+ char** env = GetEnviron();
+ for (size_t i = 0; env[i] != nullptr; ++i) {
+ name_value_pairs_.emplace_back(new std::string(env[i]));
+ }
+ // The strings in name_value_pairs_ retain ownership of the c_str, but we assign pointers
+ // for quick use by GetSnapshot. This avoids allocation and copying cost at Exec.
+ c_env_vector_.reset(new char*[name_value_pairs_.size() + 1]);
+ for (size_t i = 0; env[i] != nullptr; ++i) {
+ c_env_vector_[i] = const_cast<char*>(name_value_pairs_[i]->c_str());
+ }
+ c_env_vector_[name_value_pairs_.size()] = nullptr;
+}
+
+char** Runtime::EnvSnapshot::GetSnapshot() const {
+ return c_env_vector_.get();
+}
+
} // namespace art
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 6da60f27a3..5f89d6adca 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -642,6 +642,12 @@ class Runtime {
// optimization that makes it impossible to deoptimize.
bool IsDeoptimizeable(uintptr_t code) const SHARED_REQUIRES(Locks::mutator_lock_);
+ // Returns a saved copy of the environment (getenv/setenv values).
+ // Used by Fork to protect against overwriting LD_LIBRARY_PATH, etc.
+ char** GetEnvSnapshot() const {
+ return env_snapshot_.GetSnapshot();
+ }
+
private:
static void InitPlatformSignalHandlers();
@@ -864,6 +870,20 @@ class Runtime {
// Whether zygote code is in a section that should not start threads.
bool zygote_no_threads_;
+ // Saved environment.
+ class EnvSnapshot {
+ public:
+ EnvSnapshot() = default;
+ void TakeSnapshot();
+ char** GetSnapshot() const;
+
+ private:
+ std::unique_ptr<char*[]> c_env_vector_;
+ std::vector<std::unique_ptr<std::string>> name_value_pairs_;
+
+ DISALLOW_COPY_AND_ASSIGN(EnvSnapshot);
+ } env_snapshot_;
+
DISALLOW_COPY_AND_ASSIGN(Runtime);
};
std::ostream& operator<<(std::ostream& os, const Runtime::CalleeSaveType& rhs);
diff --git a/runtime/utils.cc b/runtime/utils.cc
index b676ae5ae5..313190c84d 100644
--- a/runtime/utils.cc
+++ b/runtime/utils.cc
@@ -1155,8 +1155,15 @@ int ExecAndReturnCode(std::vector<std::string>& arg_vector, std::string* error_m
// change process groups, so we don't get reaped by ProcessManager
setpgid(0, 0);
- execv(program, &args[0]);
- PLOG(ERROR) << "Failed to execv(" << command_line << ")";
+ // (b/30160149): protect subprocesses from modifications to LD_LIBRARY_PATH, etc.
+ // Use the snapshot of the environment from the time the runtime was created.
+ char** envp = (Runtime::Current() == nullptr) ? nullptr : Runtime::Current()->GetEnvSnapshot();
+ if (envp == nullptr) {
+ execv(program, &args[0]);
+ } else {
+ execve(program, &args[0], envp);
+ }
+ PLOG(ERROR) << "Failed to execve(" << command_line << ")";
// _exit to avoid atexit handlers in child.
_exit(1);
} else {
diff --git a/runtime/utils.h b/runtime/utils.h
index 693e0b87ee..843349277d 100644
--- a/runtime/utils.h
+++ b/runtime/utils.h
@@ -269,6 +269,9 @@ bool GetDalvikCacheFilename(const char* file_location, const char* cache_locatio
std::string GetSystemImageFilename(const char* location, InstructionSet isa);
// Wrapper on fork/execv to run a command in a subprocess.
+// Both of these spawn child processes using the environment as it was set when the single instance
+// of the runtime (Runtime::Current()) was started. If no instance of the runtime was started, it
+// will use the current environment settings.
bool Exec(std::vector<std::string>& arg_vector, std::string* error_msg);
int ExecAndReturnCode(std::vector<std::string>& arg_vector, std::string* error_msg);
diff --git a/runtime/utils_test.cc b/runtime/utils_test.cc
index 0a01cdb4ec..3ba20a4f02 100644
--- a/runtime/utils_test.cc
+++ b/runtime/utils_test.cc
@@ -16,6 +16,8 @@
#include "utils.h"
+#include <stdlib.h>
+
#include "base/enums.h"
#include "class_linker-inl.h"
#include "common_runtime_test.h"
@@ -380,8 +382,57 @@ TEST_F(UtilsTest, ExecError) {
if (!(RUNNING_ON_MEMORY_TOOL && kMemoryToolDetectsLeaks)) {
// Running on valgrind fails due to some memory that leaks in thread alternate signal stacks.
EXPECT_FALSE(Exec(command, &error_msg));
- EXPECT_NE(0U, error_msg.size());
+ EXPECT_FALSE(error_msg.empty());
+ }
+}
+
+TEST_F(UtilsTest, EnvSnapshotAdditionsAreNotVisible) {
+ static constexpr const char* kModifiedVariable = "EXEC_SHOULD_NOT_EXPORT_THIS";
+ static constexpr int kOverwrite = 1;
+ // Set an variable in the current environment.
+ EXPECT_EQ(setenv(kModifiedVariable, "NEVER", kOverwrite), 0);
+ // Test that it is not exported.
+ std::vector<std::string> command;
+ if (kIsTargetBuild) {
+ std::string android_root(GetAndroidRoot());
+ command.push_back(android_root + "/bin/printenv");
+ } else {
+ command.push_back("/usr/bin/printenv");
+ }
+ command.push_back(kModifiedVariable);
+ std::string error_msg;
+ if (!(RUNNING_ON_MEMORY_TOOL && kMemoryToolDetectsLeaks)) {
+ // Running on valgrind fails due to some memory that leaks in thread alternate signal stacks.
+ EXPECT_FALSE(Exec(command, &error_msg));
+ EXPECT_NE(0U, error_msg.size()) << error_msg;
+ }
+}
+
+TEST_F(UtilsTest, EnvSnapshotDeletionsAreNotVisible) {
+ static constexpr const char* kDeletedVariable = "PATH";
+ static constexpr int kOverwrite = 1;
+ // Save the variable's value.
+ const char* save_value = getenv(kDeletedVariable);
+ EXPECT_NE(save_value, nullptr);
+ // Delete the variable.
+ EXPECT_EQ(unsetenv(kDeletedVariable), 0);
+ // Test that it is not exported.
+ std::vector<std::string> command;
+ if (kIsTargetBuild) {
+ std::string android_root(GetAndroidRoot());
+ command.push_back(android_root + "/bin/printenv");
+ } else {
+ command.push_back("/usr/bin/printenv");
+ }
+ command.push_back(kDeletedVariable);
+ std::string error_msg;
+ if (!(RUNNING_ON_MEMORY_TOOL && kMemoryToolDetectsLeaks)) {
+ // Running on valgrind fails due to some memory that leaks in thread alternate signal stacks.
+ EXPECT_TRUE(Exec(command, &error_msg));
+ EXPECT_EQ(0U, error_msg.size()) << error_msg;
}
+ // Restore the variable's value.
+ EXPECT_EQ(setenv(kDeletedVariable, save_value, kOverwrite), 0);
}
TEST_F(UtilsTest, IsValidDescriptor) {
diff --git a/test/901-hello-ti-agent/basics.cc b/test/901-hello-ti-agent/basics.cc
index 81a1b66683..3a475c6fef 100644
--- a/test/901-hello-ti-agent/basics.cc
+++ b/test/901-hello-ti-agent/basics.cc
@@ -35,7 +35,7 @@ jint OnLoad(JavaVM* vm,
#define CHECK_CALL_SUCCESS(c) \
do { \
- if (c != JNI_OK) { \
+ if ((c) != JNI_OK) { \
printf("call " #c " did not succeed\n"); \
return -1; \
} \