diff --git a/runtime/platform/address_sanitizer.h b/runtime/platform/address_sanitizer.h new file mode 100644 index 00000000000..37346fcc1ea --- /dev/null +++ b/runtime/platform/address_sanitizer.h @@ -0,0 +1,23 @@ +// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +#ifndef PLATFORM_ADDRESS_SANITIZER_H_ +#define PLATFORM_ADDRESS_SANITIZER_H_ + +#include "platform/globals.h" + +// Allow the use of ASan (AddressSanitizer). This is needed as ASan needs to be +// told about areas where the VM does the equivalent of a long-jump. +#if defined(__has_feature) +#if __has_feature(address_sanitizer) +extern "C" void __asan_unpoison_memory_region(void *, size_t); +#define ASAN_UNPOISON(ptr, len) __asan_unpoison_memory_region(ptr, len) +#else // __has_feature(address_sanitizer) +#define ASAN_UNPOISON(ptr, len) do {} while (false && (ptr) == 0 && (len) == 0) +#endif // __has_feature(address_sanitizer) +#else // defined(__has_feature) +#define ASAN_UNPOISON(ptr, len) do {} while (false && (ptr) == 0 && (len) == 0) +#endif // defined(__has_feature) + +#endif // PLATFORM_ADDRESS_SANITIZER_H_ diff --git a/runtime/platform/memory_sanitizer.h b/runtime/platform/memory_sanitizer.h new file mode 100644 index 00000000000..b9bd0590bad --- /dev/null +++ b/runtime/platform/memory_sanitizer.h @@ -0,0 +1,23 @@ +// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +#ifndef PLATFORM_MEMORY_SANITIZER_H_ +#define PLATFORM_MEMORY_SANITIZER_H_ + +#include "platform/globals.h" + +// Allow the use of Msan (MemorySanitizer). This is needed as Msan needs to be +// told about areas that are initialized by generated code. +#if defined(__has_feature) +#if __has_feature(memory_sanitizer) +extern "C" void __msan_unpoison(void *, size_t); +#define MSAN_UNPOISON(ptr, len) __msan_unpoison(ptr, len) +#else // __has_feature(memory_sanitizer) +#define MSAN_UNPOISON(ptr, len) do {} while (false && (ptr) == 0 && (len) == 0) +#endif // __has_feature(memory_sanitizer) +#else // defined(__has_feature) +#define MSAN_UNPOISON(ptr, len) do {} while (false && (ptr) == 0 && (len) == 0) +#endif // defined(__has_feature) + +#endif // PLATFORM_MEMORY_SANITIZER_H_ diff --git a/runtime/platform/platform_headers.gypi b/runtime/platform/platform_headers.gypi index f760fd083b8..bf999850c8f 100644 --- a/runtime/platform/platform_headers.gypi +++ b/runtime/platform/platform_headers.gypi @@ -5,14 +5,16 @@ # This file contains headers shared between the vm and bin components. { 'sources': [ + 'address_sanitizer.h', 'assert.h', 'c99_support_win.h', + 'floating_point.h', + 'floating_point_win.h', 'globals.h', 'hashmap.h', 'inttypes_support_win.h', 'json.h', - 'floating_point.h', - 'floating_point_win.h', + 'memory_sanitizer.h', 'utils.h', ], } diff --git a/runtime/vm/exceptions.cc b/runtime/vm/exceptions.cc index 88b73750945..0a5ed8fdcb3 100644 --- a/runtime/vm/exceptions.cc +++ b/runtime/vm/exceptions.cc @@ -4,6 +4,8 @@ #include "vm/exceptions.h" +#include "platform/address_sanitizer.h" + #include "vm/dart_api_impl.h" #include "vm/dart_entry.h" #include "vm/debugger.h" @@ -15,19 +17,6 @@ #include "vm/symbols.h" #include "vm/tags.h" -// Allow the use of ASan (AddressSanitizer). This is needed as ASan needs to be -// told about areas where the VM does the equivalent of a long-jump. -#if defined(__has_feature) -#if __has_feature(address_sanitizer) -extern "C" void __asan_unpoison_memory_region(void *, size_t); -#else // __has_feature(address_sanitizer) -void __asan_unpoison_memory_region(void* ignore1, size_t ignore2) {} -#endif // __has_feature(address_sanitizer) -#else // defined(__has_feature) -void __asan_unpoison_memory_region(void* ignore1, size_t ignore2) {} -#endif // defined(__has_feature) - - namespace dart { DEFINE_FLAG(bool, print_stacktrace_at_throw, false, @@ -310,8 +299,8 @@ static void JumpToExceptionHandler(Isolate* isolate, // Unpoison the stack before we tear it down in the generated stub code. uword current_sp = reinterpret_cast(&program_counter) - 1024; - __asan_unpoison_memory_region(reinterpret_cast(current_sp), - stack_pointer - current_sp); + ASAN_UNPOISON(reinterpret_cast(current_sp), + stack_pointer - current_sp); func(program_counter, stack_pointer, frame_pointer, raw_exception, raw_stacktrace, isolate); diff --git a/runtime/vm/native_arguments.h b/runtime/vm/native_arguments.h index 197f9ab7e13..3f4aac38399 100644 --- a/runtime/vm/native_arguments.h +++ b/runtime/vm/native_arguments.h @@ -6,6 +6,7 @@ #define VM_NATIVE_ARGUMENTS_H_ #include "platform/assert.h" +#include "platform/memory_sanitizer.h" #include "vm/globals.h" #include "vm/handles_impl.h" #include "vm/simulator.h" @@ -89,7 +90,10 @@ class NativeArguments { RawObject* ArgAt(int index) const { ASSERT((index >= 0) && (index < ArgCount())); - return (*argv_)[-index]; + RawObject** arg_ptr = &((*argv_)[-index]); + // Tell MemorySanitizer the RawObject* was initialized (by generated code). + MSAN_UNPOISON(arg_ptr, kWordSize); + return *arg_ptr; } int NativeArgCount() const { diff --git a/runtime/vm/native_entry.cc b/runtime/vm/native_entry.cc index a121d71df20..dcceccea9a8 100644 --- a/runtime/vm/native_entry.cc +++ b/runtime/vm/native_entry.cc @@ -86,6 +86,8 @@ void NativeEntry::NativeCallWrapper(Dart_NativeArguments args, CHECK_STACK_ALIGNMENT; VERIFY_ON_TRANSITION; NativeArguments* arguments = reinterpret_cast(args); + /* Tell MemorySanitizer 'arguments' is initialized by generated code. */ + MSAN_UNPOISON(arguments, sizeof(*arguments)); Isolate* isolate = arguments->isolate(); ApiState* state = isolate->api_state(); diff --git a/runtime/vm/native_entry.h b/runtime/vm/native_entry.h index 53fbb03d9ab..b445008bb5a 100644 --- a/runtime/vm/native_entry.h +++ b/runtime/vm/native_entry.h @@ -5,6 +5,8 @@ #ifndef VM_NATIVE_ENTRY_H_ #define VM_NATIVE_ENTRY_H_ +#include "platform/memory_sanitizer.h" + #include "vm/allocation.h" #include "vm/assembler.h" #include "vm/code_generator.h" @@ -42,6 +44,8 @@ typedef void (*NativeFunction)(NativeArguments* arguments); CHECK_STACK_ALIGNMENT; \ VERIFY_ON_TRANSITION; \ NativeArguments* arguments = reinterpret_cast(args); \ + /* Tell MemorySanitizer 'arguments' is initialized by generated code. */ \ + MSAN_UNPOISON(arguments, sizeof(*arguments)); \ ASSERT(arguments->NativeArgCount() == argument_count); \ TRACE_NATIVE_CALL("%s", ""#name); \ { \ diff --git a/runtime/vm/profiler.cc b/runtime/vm/profiler.cc index 1a2709be079..5ee53d47cf9 100644 --- a/runtime/vm/profiler.cc +++ b/runtime/vm/profiler.cc @@ -2,6 +2,7 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +#include "platform/memory_sanitizer.h" #include "platform/utils.h" #include "vm/allocation.h" @@ -1934,7 +1935,10 @@ class ProfilerNativeStackWalker : public ValueObject { uword* CallerFP(uword* fp) const { ASSERT(fp != NULL); - return reinterpret_cast(*(fp + kSavedCallerFpSlotFromFp)); + uword* caller_fp_ptr = fp + kSavedCallerFpSlotFromFp; + // This may actually be uninitialized, by design (see class comment above). + MSAN_UNPOISON(caller_fp_ptr, kWordSize); + return reinterpret_cast(*caller_fp_ptr); } bool ValidFramePointer(uword* fp) const { diff --git a/runtime/vm/scavenger.cc b/runtime/vm/scavenger.cc index c02d6de514b..56f9f996f8f 100644 --- a/runtime/vm/scavenger.cc +++ b/runtime/vm/scavenger.cc @@ -524,6 +524,8 @@ void Scavenger::IterateStoreBuffers(Isolate* isolate, StoreBufferBlock* pending = isolate->store_buffer()->Blocks(); while (pending != NULL) { StoreBufferBlock* next = pending->next(); + // Generated code appends to store buffers; tell MemorySanitizer. + MSAN_UNPOISON(pending, sizeof(*pending)); intptr_t count = pending->Count(); for (intptr_t i = 0; i < count; i++) { RawObject* raw_object = pending->At(i); diff --git a/runtime/vm/stack_frame.cc b/runtime/vm/stack_frame.cc index e37bf116dc4..0eb9bb9d3f2 100644 --- a/runtime/vm/stack_frame.cc +++ b/runtime/vm/stack_frame.cc @@ -4,6 +4,7 @@ #include "vm/stack_frame.h" +#include "platform/memory_sanitizer.h" #include "vm/assembler.h" #include "vm/deopt_instructions.h" #include "vm/isolate.h" @@ -278,6 +279,15 @@ void StackFrameIterator::SetupNextExitFrameData() { } +// Tell MemorySanitizer that generated code initializes part of the stack. +// TODO(koda): Limit to frames that are actually written by generated code. +static void UnpoisonStack(Isolate* isolate, uword fp) { + ASSERT(fp != 0); + uword size = isolate->GetSpecifiedStackSize(); + MSAN_UNPOISON(reinterpret_cast(fp - size), 2 * size); +} + + StackFrameIterator::StackFrameIterator(bool validate, Isolate* isolate) : validate_(validate), entry_(isolate), @@ -340,6 +350,7 @@ StackFrame* StackFrameIterator::NextFrame() { if (!HasNextFrame()) { return NULL; } + UnpoisonStack(isolate_, frames_.fp_); if (frames_.pc_ == 0) { // Iteration starts from an exit frame given by its fp. current_frame_ = NextExitFrame();