Fix memleak with exceptions (#713)

This commit is contained in:
Nikolay Igotti
2017-06-27 15:08:42 +03:00
committed by GitHub
parent 96d9f734c0
commit 399f4bd0ff
+24 -29
View File
@@ -22,7 +22,7 @@
// GCC unwinder for backtrace. // GCC unwinder for backtrace.
#include <unwind.h> #include <unwind.h>
#else #else
// Glibc backtrace function. // Glibc backtrace() function.
#include <execinfo.h> #include <execinfo.h>
#endif #endif
#endif // OMIT_BACKTRACE #endif // OMIT_BACKTRACE
@@ -37,20 +37,6 @@
namespace { namespace {
class KotlinException {
public:
KRef exception_;
KotlinException(KRef exception) : exception_(exception) {
::AddRef(exception_->container());
};
~KotlinException() {
::Release(exception_->container());
};
};
// TODO: it seems to be very common case; does C++ std library provide something like this? // TODO: it seems to be very common case; does C++ std library provide something like this?
class AutoFree { class AutoFree {
private: private:
@@ -66,20 +52,25 @@ class AutoFree {
#if USE_GCC_UNWIND #if USE_GCC_UNWIND
struct Backtrace { struct Backtrace {
Backtrace(int count, int skip) : index(0), skipCount(skip), array(nullptr) { Backtrace(int count, int skip) : index(0), skipCount(skip) {
auto result = AllocArrayInstance( auto result = AllocArrayInstance(
theArrayTypeInfo, count - skipCount, &array); theArrayTypeInfo, count - skipCount, arrayHolder.slot());
// TODO: throw cached OOME?
RuntimeAssert(result != nullptr, "Cannot create backtrace array"); RuntimeAssert(result != nullptr, "Cannot create backtrace array");
} }
void setNextElement(const char* element) { void setNextElement(const char* element) {
CreateStringFromCString( auto result = CreateStringFromCString(
element, ArrayAddressOfElementAt(array->array(), index++)); element, ArrayAddressOfElementAt(obj()->array(), index++));
// TODO: throw cached OOME?
RuntimeAssert(result != nullptr, "Cannot create backtrace array element");
} }
ObjHeader* obj() { return arrayHolder.obj(); }
int index; int index;
int skipCount; int skipCount;
ObjHeader* array; ObjHolder arrayHolder;
}; };
_Unwind_Reason_Code depthCountCallback( _Unwind_Reason_Code depthCountCallback(
@@ -132,13 +123,15 @@ OBJ_GETTER0(GetCurrentStackTrace) {
CreateStringFromCString("<UNIMPLEMENTED>", ArrayAddressOfElementAt(array, 0)); CreateStringFromCString("<UNIMPLEMENTED>", ArrayAddressOfElementAt(array, 0));
return result; return result;
#else #else
// Skips first 3 elements as irrelevant.
constexpr int kSkipFrames = 3;
#if USE_GCC_UNWIND #if USE_GCC_UNWIND
int depth = 0; int depth = 0;
_Unwind_Backtrace(depthCountCallback, &depth); _Unwind_Backtrace(depthCountCallback, &depth);
// Skips first 3 elements as irrelevant. if (depth < kSkipFrames) RETURN_OBJ(nullptr);
Backtrace result(depth, 3); Backtrace result(depth, kSkipFrames);
_Unwind_Backtrace(unwindCallback, &result); _Unwind_Backtrace(unwindCallback, &result);
RETURN_OBJ(result.array); RETURN_OBJ(result.obj());
#else #else
const int maxSize = 32; const int maxSize = 32;
void* buffer[maxSize]; void* buffer[maxSize];
@@ -146,15 +139,17 @@ OBJ_GETTER0(GetCurrentStackTrace) {
int size = backtrace(buffer, maxSize); int size = backtrace(buffer, maxSize);
char** symbols = backtrace_symbols(buffer, size); char** symbols = backtrace_symbols(buffer, size);
RuntimeAssert(symbols != nullptr, "Not enough memory to retrieve the stacktrace"); RuntimeAssert(symbols != nullptr, "Not enough memory to retrieve the stacktrace");
if (size < kSkipFrames) RETURN_OBJ(nullptr);
AutoFree autoFree(symbols); AutoFree autoFree(symbols);
ObjHeader* result = AllocArrayInstance(theArrayTypeInfo, size, OBJ_RESULT); ObjHolder resultHolder;
ObjHeader* result = AllocArrayInstance(
theArrayTypeInfo, size - kSkipFrames, resultHolder.slot());
ArrayHeader* array = result->array(); ArrayHeader* array = result->array();
for (int index = 0; index < size; ++index) { for (int index = kSkipFrames; index < size; ++index) {
CreateStringFromCString( CreateStringFromCString(
symbols[index], ArrayAddressOfElementAt(array, index)); symbols[index], ArrayAddressOfElementAt(array, index - kSkipFrames));
} }
return result; RETURN_OBJ(result);
#endif #endif
#endif // !OMIT_BACKTRACE #endif // !OMIT_BACKTRACE
} }
@@ -162,7 +157,7 @@ OBJ_GETTER0(GetCurrentStackTrace) {
void ThrowException(KRef exception) { void ThrowException(KRef exception) {
RuntimeAssert(exception != nullptr && IsInstance(exception, theThrowableTypeInfo), RuntimeAssert(exception != nullptr && IsInstance(exception, theThrowableTypeInfo),
"Throwing something non-throwable"); "Throwing something non-throwable");
throw KotlinException(exception); throw ObjHolder(exception);
} }