Fix memleak with exceptions (#713)
This commit is contained in:
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user