From 4e8b265ea0c4d56d2e25f107d9a9cc4b975ef588 Mon Sep 17 00:00:00 2001 From: Ryan Macnak Date: Thu, 9 Feb 2017 12:34:16 -0800 Subject: [PATCH] Use zone memory for StackTrace::ToCString. Fixes memory leak of the TextBuffer's buffer. R=fschneider@google.com Review-Url: https://codereview.chromium.org/2689563003 . --- runtime/vm/object.cc | 7 ++-- runtime/vm/vm_sources.gypi | 2 ++ runtime/vm/zone_text_buffer.cc | 65 ++++++++++++++++++++++++++++++++++ runtime/vm/zone_text_buffer.h | 38 ++++++++++++++++++++ 4 files changed, 109 insertions(+), 3 deletions(-) create mode 100644 runtime/vm/zone_text_buffer.cc create mode 100644 runtime/vm/zone_text_buffer.h diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc index d48e22f0eab..f78b66ffb8d 100644 --- a/runtime/vm/object.cc +++ b/runtime/vm/object.cc @@ -47,6 +47,7 @@ #include "vm/type_table.h" #include "vm/unicode.h" #include "vm/weak_code.h" +#include "vm/zone_text_buffer.h" namespace dart { @@ -22332,7 +22333,7 @@ const char* StackTrace::ToCString() const { static void PrintStackTraceFrame(Zone* zone, - TextBuffer* buffer, + ZoneTextBuffer* buffer, const Function& function, TokenPosition token_pos, intptr_t frame_index) { @@ -22370,7 +22371,7 @@ const char* StackTrace::ToCStringInternal(intptr_t* frame_index, Code& code = Code::Handle(zone); GrowableArray inlined_functions; GrowableArray inlined_token_positions; - TextBuffer buffer(1024); + ZoneTextBuffer buffer(zone, 1024); // Iterate through the stack frames and create C string description // for each frame. @@ -22416,7 +22417,7 @@ const char* StackTrace::ToCStringInternal(intptr_t* frame_index, } } - return buffer.Steal(); + return buffer.buffer(); } diff --git a/runtime/vm/vm_sources.gypi b/runtime/vm/vm_sources.gypi index cd72fda195f..1cc10438e46 100644 --- a/runtime/vm/vm_sources.gypi +++ b/runtime/vm/vm_sources.gypi @@ -555,5 +555,7 @@ 'zone.cc', 'zone.h', 'zone_test.cc', + 'zone_text_buffer.cc', + 'zone_text_buffer.h', ], } diff --git a/runtime/vm/zone_text_buffer.cc b/runtime/vm/zone_text_buffer.cc new file mode 100644 index 00000000000..5825e2d7595 --- /dev/null +++ b/runtime/vm/zone_text_buffer.cc @@ -0,0 +1,65 @@ +// Copyright (c) 2017, 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. + +#include "vm/zone_text_buffer.h" + +#include "platform/assert.h" +#include "platform/globals.h" +#include "platform/utils.h" +#include "vm/os.h" +#include "vm/zone.h" + +namespace dart { + +ZoneTextBuffer::ZoneTextBuffer(Zone* zone, intptr_t initial_capacity) + : zone_(zone), buffer_(NULL), length_(0), capacity_(0) { + ASSERT(initial_capacity > 0); + buffer_ = reinterpret_cast(zone->Alloc(initial_capacity)); + capacity_ = initial_capacity; +} + + +intptr_t ZoneTextBuffer::Printf(const char* format, ...) { + va_list args; + va_start(args, format); + intptr_t remaining = capacity_ - length_; + ASSERT(remaining >= 0); + intptr_t len = OS::VSNPrint(buffer_ + length_, remaining, format, args); + va_end(args); + if (len >= remaining) { + EnsureCapacity(len); + remaining = capacity_ - length_; + ASSERT(remaining > len); + va_list args2; + va_start(args2, format); + intptr_t len2 = OS::VSNPrint(buffer_ + length_, remaining, format, args2); + va_end(args2); + ASSERT(len == len2); + } + length_ += len; + buffer_[length_] = '\0'; + return len; +} + + +void ZoneTextBuffer::AddString(const char* s) { + Printf("%s", s); +} + + +void ZoneTextBuffer::EnsureCapacity(intptr_t len) { + intptr_t remaining = capacity_ - length_; + if (remaining <= len) { + const int kBufferSpareCapacity = 64; // Somewhat arbitrary. + // TODO(turnidge): do we need to guard against overflow or other + // security issues here? Text buffers are used by the debugger + // to send user-controlled data (e.g. values of string variables) to + // the debugger front-end. + intptr_t new_capacity = capacity_ + len + kBufferSpareCapacity; + buffer_ = zone_->Realloc(buffer_, capacity_, new_capacity); + capacity_ = new_capacity; + } +} + +} // namespace dart diff --git a/runtime/vm/zone_text_buffer.h b/runtime/vm/zone_text_buffer.h new file mode 100644 index 00000000000..28a39eb529f --- /dev/null +++ b/runtime/vm/zone_text_buffer.h @@ -0,0 +1,38 @@ +// Copyright (c) 2012, 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 RUNTIME_VM_ZONE_TEXT_BUFFER_H_ +#define RUNTIME_VM_ZONE_TEXT_BUFFER_H_ + +#include "vm/allocation.h" +#include "vm/globals.h" + +namespace dart { + +class Zone; + +// TextBuffer maintains a dynamic character buffer with a printf-style way to +// append text. +class ZoneTextBuffer : ValueObject { + public: + ZoneTextBuffer(Zone* zone, intptr_t initial_capacity); + ~ZoneTextBuffer() {} + + intptr_t Printf(const char* format, ...) PRINTF_ATTRIBUTE(2, 3); + void AddString(const char* s); + + char* buffer() { return buffer_; } + intptr_t length() { return length_; } + + private: + void EnsureCapacity(intptr_t len); + Zone* zone_; + char* buffer_; + intptr_t length_; + intptr_t capacity_; +}; + +} // namespace dart + +#endif // RUNTIME_VM_ZONE_TEXT_BUFFER_H_