diff options
| -rw-r--r-- | compiler/elf_writer_test.cc | 12 | ||||
| -rw-r--r-- | compiler/linker/arm64/relative_patcher_arm64_test.cc | 22 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_arm.cc | 4 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_arm64.cc | 4 | ||||
| -rw-r--r-- | compiler/utils/intrusive_forward_list_test.cc | 12 | ||||
| -rw-r--r-- | runtime/Android.bp | 1 | ||||
| -rw-r--r-- | runtime/entrypoints/quick/quick_entrypoints_enum.cc | 69 | ||||
| -rw-r--r-- | runtime/entrypoints/quick/quick_entrypoints_enum.h | 2 | ||||
| -rw-r--r-- | runtime/entrypoints_order_test.cc | 7 | ||||
| -rw-r--r-- | runtime/gc/space/space_test.h | 2 | ||||
| -rw-r--r-- | runtime/instrumentation_test.cc | 2 | ||||
| -rw-r--r-- | runtime/jni_internal_test.cc | 7 | ||||
| -rw-r--r-- | runtime/mirror/class.h | 2 | ||||
| -rw-r--r-- | runtime/oat_file_assistant_test.cc | 8 | ||||
| -rw-r--r-- | runtime/runtime.cc | 41 | ||||
| -rw-r--r-- | runtime/runtime.h | 20 | ||||
| -rw-r--r-- | runtime/utils.cc | 11 | ||||
| -rw-r--r-- | runtime/utils.h | 3 | ||||
| -rw-r--r-- | runtime/utils_test.cc | 53 | ||||
| -rw-r--r-- | test/901-hello-ti-agent/basics.cc | 2 |
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; \ } \ |