summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMathieu Chartier <mathieuc@google.com>2014-01-09 11:23:53 -0800
committerMathieu Chartier <mathieuc@google.com>2014-03-05 12:44:22 -0800
commit661974a5561e5ccdfbac8cb5d8df8b7e6f3483b8 (patch)
tree02e428694277d85a98505f8e814aba378fc7651c
parent3cd52df3d740f8a656233b199dfcaab165f415ff (diff)
downloadart-661974a5561e5ccdfbac8cb5d8df8b7e6f3483b8.zip
art-661974a5561e5ccdfbac8cb5d8df8b7e6f3483b8.tar.gz
art-661974a5561e5ccdfbac8cb5d8df8b7e6f3483b8.tar.bz2
Fix valgrind gtests and memory leaks.
All tests pass other than image_test which passes if some bad reads are disabled (buzbee working on this). Change-Id: Ifd6b6e3aed0bc867703b6e818353a9f296609422
-rw-r--r--compiler/oat_writer.cc1
-rw-r--r--compiler/utils/arena_allocator.cc4
-rw-r--r--runtime/gc/allocator/rosalloc.cc6
-rw-r--r--runtime/gc/allocator/rosalloc.h1
-rw-r--r--runtime/gc/heap.cc2
-rw-r--r--runtime/gc/space/dlmalloc_space.cc13
-rw-r--r--runtime/gc/space/malloc_space.h2
-rw-r--r--runtime/gc/space/rosalloc_space-inl.h2
-rw-r--r--runtime/gc/space/rosalloc_space.cc11
-rw-r--r--runtime/gc/space/rosalloc_space.h6
-rw-r--r--runtime/gc/space/valgrind_malloc_space-inl.h21
-rw-r--r--runtime/gc/space/valgrind_malloc_space.h3
-rw-r--r--runtime/instrumentation.cc35
-rw-r--r--runtime/instrumentation.h4
-rw-r--r--runtime/runtime.h3
-rw-r--r--runtime/transaction_test.cc8
-rw-r--r--runtime/utils_test.cc14
-rw-r--r--runtime/zip_archive.cc3
-rw-r--r--runtime/zip_archive.h1
19 files changed, 82 insertions, 58 deletions
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index 186ab38..5394bbc 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -1014,6 +1014,7 @@ OatWriter::OatClass::OatClass(size_t offset,
}
OatWriter::OatClass::~OatClass() {
+ delete method_bitmap_;
delete compiled_methods_;
}
diff --git a/compiler/utils/arena_allocator.cc b/compiler/utils/arena_allocator.cc
index ec41293..00c3c57 100644
--- a/compiler/utils/arena_allocator.cc
+++ b/compiler/utils/arena_allocator.cc
@@ -112,7 +112,7 @@ Arena* ArenaPool::AllocArena(size_t size) {
void ArenaPool::FreeArena(Arena* arena) {
Thread* self = Thread::Current();
- if (UNLIKELY(RUNNING_ON_VALGRIND)) {
+ if (UNLIKELY(RUNNING_ON_VALGRIND > 0)) {
VALGRIND_MAKE_MEM_UNDEFINED(arena->memory_, arena->bytes_allocated_);
}
{
@@ -137,7 +137,7 @@ ArenaAllocator::ArenaAllocator(ArenaPool* pool)
ptr_(nullptr),
arena_head_(nullptr),
num_allocations_(0),
- running_on_valgrind_(RUNNING_ON_VALGRIND) {
+ running_on_valgrind_(RUNNING_ON_VALGRIND > 0) {
memset(&alloc_stats_[0], 0, sizeof(alloc_stats_));
}
diff --git a/runtime/gc/allocator/rosalloc.cc b/runtime/gc/allocator/rosalloc.cc
index e86bee6..e13bd71 100644
--- a/runtime/gc/allocator/rosalloc.cc
+++ b/runtime/gc/allocator/rosalloc.cc
@@ -93,6 +93,12 @@ RosAlloc::RosAlloc(void* base, size_t capacity, size_t max_capacity,
}
}
+RosAlloc::~RosAlloc() {
+ for (size_t i = 0; i < kNumOfSizeBrackets; i++) {
+ delete size_bracket_locks_[i];
+ }
+}
+
void* RosAlloc::AllocPages(Thread* self, size_t num_pages, byte page_map_type) {
lock_.AssertHeld(self);
DCHECK(page_map_type == kPageMapRun || page_map_type == kPageMapLargeObject);
diff --git a/runtime/gc/allocator/rosalloc.h b/runtime/gc/allocator/rosalloc.h
index 4b0dd79..738d917 100644
--- a/runtime/gc/allocator/rosalloc.h
+++ b/runtime/gc/allocator/rosalloc.h
@@ -515,6 +515,7 @@ class RosAlloc {
RosAlloc(void* base, size_t capacity, size_t max_capacity,
PageReleaseMode page_release_mode,
size_t page_release_size_threshold = kDefaultPageReleaseSizeThreshold);
+ ~RosAlloc();
void* Alloc(Thread* self, size_t size, size_t* bytes_allocated)
LOCKS_EXCLUDED(lock_);
void Free(Thread* self, void* ptr)
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index b97b9ec..87ee21b 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -152,7 +152,7 @@ Heap::Heap(size_t initial_size, size_t growth_limit, size_t min_free, size_t max
total_allocation_time_(0),
verify_object_mode_(kVerifyObjectModeDisabled),
disable_moving_gc_count_(0),
- running_on_valgrind_(RUNNING_ON_VALGRIND),
+ running_on_valgrind_(RUNNING_ON_VALGRIND > 0),
use_tlab_(use_tlab) {
if (VLOG_IS_ON(heap) || VLOG_IS_ON(startup)) {
LOG(INFO) << "Heap() entering";
diff --git a/runtime/gc/space/dlmalloc_space.cc b/runtime/gc/space/dlmalloc_space.cc
index b591486..0597422 100644
--- a/runtime/gc/space/dlmalloc_space.cc
+++ b/runtime/gc/space/dlmalloc_space.cc
@@ -43,9 +43,8 @@ DlMallocSpace::DlMallocSpace(const std::string& name, MemMap* mem_map, void* msp
}
DlMallocSpace* DlMallocSpace::CreateFromMemMap(MemMap* mem_map, const std::string& name,
- size_t starting_size,
- size_t initial_size, size_t growth_limit,
- size_t capacity) {
+ size_t starting_size, size_t initial_size,
+ size_t growth_limit, size_t capacity) {
DCHECK(mem_map != nullptr);
void* mspace = CreateMspace(mem_map->Begin(), starting_size, initial_size);
if (mspace == nullptr) {
@@ -133,12 +132,12 @@ mirror::Object* DlMallocSpace::AllocWithGrowth(Thread* self, size_t num_bytes,
size_t footprint = mspace_footprint(mspace_);
mspace_set_footprint_limit(mspace_, footprint);
}
- if (result != NULL) {
+ if (result != nullptr) {
// Zero freshly allocated memory, done while not holding the space's lock.
memset(result, 0, num_bytes);
+ // Check that the result is contained in the space.
+ CHECK(!kDebugSpaces || Contains(result));
}
- // Return the new allocation or NULL.
- CHECK(!kDebugSpaces || result == NULL || Contains(result));
return result;
}
@@ -151,7 +150,7 @@ MallocSpace* DlMallocSpace::CreateInstance(const std::string& name, MemMap* mem_
size_t DlMallocSpace::Free(Thread* self, mirror::Object* ptr) {
MutexLock mu(self, lock_);
if (kDebugSpaces) {
- CHECK(ptr != NULL);
+ CHECK(ptr != nullptr);
CHECK(Contains(ptr)) << "Free (" << ptr << ") not in bounds of heap " << *this;
}
const size_t bytes_freed = AllocationSizeNonvirtual(ptr, nullptr);
diff --git a/runtime/gc/space/malloc_space.h b/runtime/gc/space/malloc_space.h
index 30c7c45..fbcee5f 100644
--- a/runtime/gc/space/malloc_space.h
+++ b/runtime/gc/space/malloc_space.h
@@ -139,7 +139,7 @@ class MallocSpace : public ContinuousMemMapAllocSpace {
virtual void* CreateAllocator(void* base, size_t morecore_start, size_t initial_size,
size_t maximum_size, bool low_memory_mode) = 0;
- void RegisterRecentFree(mirror::Object* ptr)
+ virtual void RegisterRecentFree(mirror::Object* ptr)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
EXCLUSIVE_LOCKS_REQUIRED(lock_);
diff --git a/runtime/gc/space/rosalloc_space-inl.h b/runtime/gc/space/rosalloc_space-inl.h
index 2627c85..d270885 100644
--- a/runtime/gc/space/rosalloc_space-inl.h
+++ b/runtime/gc/space/rosalloc_space-inl.h
@@ -50,7 +50,7 @@ inline mirror::Object* RosAllocSpace::AllocCommon(Thread* self, size_t num_bytes
size_t* bytes_allocated, size_t* usable_size) {
size_t rosalloc_size = 0;
mirror::Object* result = reinterpret_cast<mirror::Object*>(
- rosalloc_for_alloc_->Alloc(self, num_bytes, &rosalloc_size));
+ rosalloc_->Alloc(self, num_bytes, &rosalloc_size));
if (LIKELY(result != NULL)) {
if (kDebugSpaces) {
CHECK(Contains(result)) << "Allocation (" << reinterpret_cast<void*>(result)
diff --git a/runtime/gc/space/rosalloc_space.cc b/runtime/gc/space/rosalloc_space.cc
index b13ac3d..c4ce94d 100644
--- a/runtime/gc/space/rosalloc_space.cc
+++ b/runtime/gc/space/rosalloc_space.cc
@@ -39,8 +39,7 @@ template class ValgrindMallocSpace<RosAllocSpace, allocator::RosAlloc*>;
RosAllocSpace::RosAllocSpace(const std::string& name, MemMap* mem_map,
art::gc::allocator::RosAlloc* rosalloc, byte* begin, byte* end,
byte* limit, size_t growth_limit)
- : MallocSpace(name, mem_map, begin, end, limit, growth_limit), rosalloc_(rosalloc),
- rosalloc_for_alloc_(rosalloc) {
+ : MallocSpace(name, mem_map, begin, end, limit, growth_limit), rosalloc_(rosalloc) {
CHECK(rosalloc != NULL);
}
@@ -64,7 +63,9 @@ RosAllocSpace* RosAllocSpace::CreateFromMemMap(MemMap* mem_map, const std::strin
// Everything is set so record in immutable structure and leave
byte* begin = mem_map->Begin();
- if (RUNNING_ON_VALGRIND > 0) {
+ // TODO: Fix RosAllocSpace to support valgrind. There is currently some issues with
+ // AllocationSize caused by redzones. b/12944686
+ if (false && RUNNING_ON_VALGRIND > 0) {
return new ValgrindMallocSpace<RosAllocSpace, allocator::RosAlloc*>(
name, mem_map, rosalloc, begin, end, begin + capacity, growth_limit, initial_size);
} else {
@@ -72,6 +73,10 @@ RosAllocSpace* RosAllocSpace::CreateFromMemMap(MemMap* mem_map, const std::strin
}
}
+RosAllocSpace::~RosAllocSpace() {
+ delete rosalloc_;
+}
+
RosAllocSpace* RosAllocSpace::Create(const std::string& name, size_t initial_size,
size_t growth_limit, size_t capacity, byte* requested_begin,
bool low_memory_mode) {
diff --git a/runtime/gc/space/rosalloc_space.h b/runtime/gc/space/rosalloc_space.h
index 9f756aa..9b9adf8 100644
--- a/runtime/gc/space/rosalloc_space.h
+++ b/runtime/gc/space/rosalloc_space.h
@@ -105,6 +105,8 @@ class RosAllocSpace : public MallocSpace {
rosalloc_->Verify();
}
+ virtual ~RosAllocSpace();
+
protected:
RosAllocSpace(const std::string& name, MemMap* mem_map, allocator::RosAlloc* rosalloc,
byte* begin, byte* end, byte* limit, size_t growth_limit);
@@ -127,10 +129,6 @@ class RosAllocSpace : public MallocSpace {
// Underlying rosalloc.
allocator::RosAlloc* const rosalloc_;
- // The rosalloc pointer used for allocation. Equal to rosalloc_ or nullptr after
- // InvalidateAllocator() is called.
- allocator::RosAlloc* rosalloc_for_alloc_;
-
friend class collector::MarkSweep;
DISALLOW_COPY_AND_ASSIGN(RosAllocSpace);
diff --git a/runtime/gc/space/valgrind_malloc_space-inl.h b/runtime/gc/space/valgrind_malloc_space-inl.h
index 4b0c8e3..ed97e60 100644
--- a/runtime/gc/space/valgrind_malloc_space-inl.h
+++ b/runtime/gc/space/valgrind_malloc_space-inl.h
@@ -38,9 +38,6 @@ mirror::Object* ValgrindMallocSpace<S, A>::AllocWithGrowth(Thread* self, size_t
if (obj_with_rdz == nullptr) {
return nullptr;
}
- if (usable_size != nullptr) {
- *usable_size -= 2 * kValgrindRedZoneBytes;
- }
mirror::Object* result = reinterpret_cast<mirror::Object*>(
reinterpret_cast<byte*>(obj_with_rdz) + kValgrindRedZoneBytes);
// Make redzones as no access.
@@ -58,9 +55,6 @@ mirror::Object* ValgrindMallocSpace<S, A>::Alloc(Thread* self, size_t num_bytes,
if (obj_with_rdz == nullptr) {
return nullptr;
}
- if (usable_size != nullptr) {
- *usable_size -= 2 * kValgrindRedZoneBytes;
- }
mirror::Object* result = reinterpret_cast<mirror::Object*>(
reinterpret_cast<byte*>(obj_with_rdz) + kValgrindRedZoneBytes);
// Make redzones as no access.
@@ -73,10 +67,7 @@ template <typename S, typename A>
size_t ValgrindMallocSpace<S, A>::AllocationSize(mirror::Object* obj, size_t* usable_size) {
size_t result = S::AllocationSize(reinterpret_cast<mirror::Object*>(
reinterpret_cast<byte*>(obj) - kValgrindRedZoneBytes), usable_size);
- if (usable_size != nullptr) {
- *usable_size -= 2 * kValgrindRedZoneBytes;
- }
- return result - 2 * kValgrindRedZoneBytes;
+ return result;
}
template <typename S, typename A>
@@ -84,11 +75,10 @@ size_t ValgrindMallocSpace<S, A>::Free(Thread* self, mirror::Object* ptr) {
void* obj_after_rdz = reinterpret_cast<void*>(ptr);
void* obj_with_rdz = reinterpret_cast<byte*>(obj_after_rdz) - kValgrindRedZoneBytes;
// Make redzones undefined.
- size_t allocation_size =
- AllocationSize(reinterpret_cast<mirror::Object*>(obj_with_rdz), nullptr);
- VALGRIND_MAKE_MEM_UNDEFINED(obj_with_rdz, allocation_size);
- size_t freed = S::Free(self, reinterpret_cast<mirror::Object*>(obj_with_rdz));
- return freed - 2 * kValgrindRedZoneBytes;
+ size_t usable_size = 0;
+ AllocationSize(ptr, &usable_size);
+ VALGRIND_MAKE_MEM_UNDEFINED(obj_with_rdz, usable_size);
+ return S::Free(self, reinterpret_cast<mirror::Object*>(obj_with_rdz));
}
template <typename S, typename A>
@@ -96,6 +86,7 @@ size_t ValgrindMallocSpace<S, A>::FreeList(Thread* self, size_t num_ptrs, mirror
size_t freed = 0;
for (size_t i = 0; i < num_ptrs; i++) {
freed += Free(self, ptrs[i]);
+ ptrs[i] = nullptr;
}
return freed;
}
diff --git a/runtime/gc/space/valgrind_malloc_space.h b/runtime/gc/space/valgrind_malloc_space.h
index 8d00b30..6b755c4 100644
--- a/runtime/gc/space/valgrind_malloc_space.h
+++ b/runtime/gc/space/valgrind_malloc_space.h
@@ -43,6 +43,9 @@ class ValgrindMallocSpace FINAL : public BaseMallocSpaceType {
size_t FreeList(Thread* self, size_t num_ptrs, mirror::Object** ptrs) OVERRIDE
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ void RegisterRecentFree(mirror::Object* ptr) OVERRIDE {
+ }
+
ValgrindMallocSpace(const std::string& name, MemMap* mem_map, AllocatorType allocator,
byte* begin, byte* end, byte* limit, size_t growth_limit,
size_t initial_size);
diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc
index e10d881..89a63ac 100644
--- a/runtime/instrumentation.cc
+++ b/runtime/instrumentation.cc
@@ -457,6 +457,22 @@ static void ResetQuickAllocEntryPointsForThread(Thread* thread, void* arg) {
thread->ResetQuickAllocEntryPointsForThread();
}
+void Instrumentation::SetEntrypointsInstrumented(bool instrumented) {
+ Runtime* runtime = Runtime::Current();
+ ThreadList* tl = runtime->GetThreadList();
+ if (runtime->IsStarted()) {
+ tl->SuspendAll();
+ }
+ {
+ MutexLock mu(Thread::Current(), *Locks::runtime_shutdown_lock_);
+ SetQuickAllocEntryPointsInstrumented(instrumented);
+ ResetQuickAllocEntryPoints();
+ }
+ if (runtime->IsStarted()) {
+ tl->ResumeAll();
+ }
+}
+
void Instrumentation::InstrumentQuickAllocEntryPoints() {
// TODO: the read of quick_alloc_entry_points_instrumentation_counter_ is racey and this code
// should be guarded by a lock.
@@ -464,15 +480,7 @@ void Instrumentation::InstrumentQuickAllocEntryPoints() {
const bool enable_instrumentation =
quick_alloc_entry_points_instrumentation_counter_.FetchAndAdd(1) == 0;
if (enable_instrumentation) {
- // Instrumentation wasn't enabled so enable it.
- ThreadList* tl = Runtime::Current()->GetThreadList();
- tl->SuspendAll();
- {
- MutexLock mu(Thread::Current(), *Locks::runtime_shutdown_lock_);
- SetQuickAllocEntryPointsInstrumented(true);
- ResetQuickAllocEntryPoints();
- }
- tl->ResumeAll();
+ SetEntrypointsInstrumented(true);
}
}
@@ -483,14 +491,7 @@ void Instrumentation::UninstrumentQuickAllocEntryPoints() {
const bool disable_instrumentation =
quick_alloc_entry_points_instrumentation_counter_.FetchAndSub(1) == 1;
if (disable_instrumentation) {
- ThreadList* tl = Runtime::Current()->GetThreadList();
- tl->SuspendAll();
- {
- MutexLock mu(Thread::Current(), *Locks::runtime_shutdown_lock_);
- SetQuickAllocEntryPointsInstrumented(false);
- ResetQuickAllocEntryPoints();
- }
- tl->ResumeAll();
+ SetEntrypointsInstrumented(false);
}
}
diff --git a/runtime/instrumentation.h b/runtime/instrumentation.h
index d7a0b4d..e04d7b2 100644
--- a/runtime/instrumentation.h
+++ b/runtime/instrumentation.h
@@ -296,6 +296,10 @@ class Instrumentation {
interpreter_handler_table_ = IsActive() ? kAlternativeHandlerTable : kMainHandlerTable;
}
+ // No thread safety analysis to get around SetQuickAllocEntryPointsInstrumented requiring
+ // exclusive access to mutator lock which you can't get if the runtime isn't started.
+ void SetEntrypointsInstrumented(bool instrumented) NO_THREAD_SAFETY_ANALYSIS;
+
void MethodEnterEventImpl(Thread* thread, mirror::Object* this_object,
mirror::ArtMethod* method, uint32_t dex_pc) const
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/runtime/runtime.h b/runtime/runtime.h
index f12c3d8..87307ae 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -68,6 +68,9 @@ class ThreadList;
class Trace;
class Transaction;
+// Not all combinations of flags are valid. You may not visit all roots as well as the new roots
+// (no logical reason to do this). You also may not start logging new roots and stop logging new
+// roots (also no logical reason to do this).
enum VisitRootFlags : uint8_t {
kVisitRootFlagAllRoots = 0x1,
kVisitRootFlagNewRoots = 0x2,
diff --git a/runtime/transaction_test.cc b/runtime/transaction_test.cc
index 7242b81..2e6ce4f 100644
--- a/runtime/transaction_test.cc
+++ b/runtime/transaction_test.cc
@@ -86,10 +86,10 @@ TEST_F(TransactionTest, Array_length) {
// Allocate an array during transaction.
SirtRef<mirror::Array> sirt_obj(soa.Self(),
- mirror::Array::Alloc<false>(soa.Self(), sirt_klass.get(),
- kArraySize,
- sirt_klass->GetComponentSize(),
- Runtime::Current()->GetHeap()->GetCurrentAllocator()));
+ mirror::Array::Alloc<true>(soa.Self(), sirt_klass.get(),
+ kArraySize,
+ sirt_klass->GetComponentSize(),
+ Runtime::Current()->GetHeap()->GetCurrentAllocator()));
ASSERT_TRUE(sirt_obj.get() != nullptr);
ASSERT_EQ(sirt_obj->GetClass(), sirt_klass.get());
Runtime::Current()->ExitTransactionMode();
diff --git a/runtime/utils_test.cc b/runtime/utils_test.cc
index d804f6a..2c1aae8 100644
--- a/runtime/utils_test.cc
+++ b/runtime/utils_test.cc
@@ -25,6 +25,8 @@
#include "scoped_thread_state_change.h"
#include "sirt_ref.h"
+#include <valgrind.h>
+
namespace art {
std::string PrettyArguments(const char* signature);
@@ -358,7 +360,10 @@ TEST_F(UtilsTest, ExecSuccess) {
command.push_back("/usr/bin/id");
}
std::string error_msg;
- EXPECT_TRUE(Exec(command, &error_msg));
+ if (RUNNING_ON_VALGRIND == 0) {
+ // 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;
}
@@ -366,8 +371,11 @@ TEST_F(UtilsTest, ExecError) {
std::vector<std::string> command;
command.push_back("bogus");
std::string error_msg;
- EXPECT_FALSE(Exec(command, &error_msg));
- EXPECT_NE(0U, error_msg.size());
+ if (RUNNING_ON_VALGRIND == 0) {
+ // 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());
+ }
}
} // namespace art
diff --git a/runtime/zip_archive.cc b/runtime/zip_archive.cc
index ba0b91e..ddac7d4 100644
--- a/runtime/zip_archive.cc
+++ b/runtime/zip_archive.cc
@@ -38,6 +38,9 @@ uint32_t ZipEntry::GetCrc32() {
return zip_entry_->crc32;
}
+ZipEntry::~ZipEntry() {
+ delete zip_entry_;
+}
bool ZipEntry::ExtractToFile(File& file, std::string* error_msg) {
const int32_t error = ExtractEntryToFile(handle_, zip_entry_, file.Fd());
diff --git a/runtime/zip_archive.h b/runtime/zip_archive.h
index 2169fe0..3ef0e6b 100644
--- a/runtime/zip_archive.h
+++ b/runtime/zip_archive.h
@@ -38,6 +38,7 @@ class ZipEntry {
public:
bool ExtractToFile(File& file, std::string* error_msg);
MemMap* ExtractToMemMap(const char* entry_filename, std::string* error_msg);
+ virtual ~ZipEntry();
uint32_t GetUncompressedLength();
uint32_t GetCrc32();