Delete input buffer on postclose #151

Notify V8 GC of memory (de)allocation
This commit is contained in:
Lovell Fuller 2015-01-21 10:34:03 +00:00
parent 8421e3aa5f
commit 855945bef2

View File

@ -51,7 +51,7 @@ enum class Angle {
struct ResizeBaton {
std::string fileIn;
void* bufferIn;
char* bufferIn;
size_t bufferInLength;
std::string iccProfilePath;
int limitInputPixels;
@ -125,6 +125,20 @@ struct ResizeBaton {
}
};
/*
Delete input char[] buffer and notify V8 of memory deallocation
Used as the callback function for the "postclose" signal
*/
static void DeleteBuffer(VipsObject *object, std::tuple<char*, size_t> *buffer) {
char* data = std::get<0>(*buffer);
size_t length = std::get<1>(*buffer);
if (data != NULL) {
delete[] data;
}
NanAdjustExternalMemory(static_cast<int>(-length));
delete buffer;
}
class ResizeWorker : public NanAsyncWorker {
public:
@ -149,18 +163,25 @@ class ResizeWorker : public NanAsyncWorker {
// Input
ImageType inputImageType = ImageType::UNKNOWN;
VipsImage *image;
VipsImage *image = NULL;
if (baton->bufferInLength > 1) {
// From buffer
inputImageType = DetermineImageType(baton->bufferIn, baton->bufferInLength);
std::tuple<char*, size_t> *buffer = new std::tuple<char*, size_t>(baton->bufferIn, baton->bufferInLength);
if (inputImageType != ImageType::UNKNOWN) {
image = InitImage(inputImageType, baton->bufferIn, baton->bufferInLength, baton->accessMethod);
if (image == NULL) {
if (image != NULL) {
// Listen for "postclose" signal to delete input buffer
g_signal_connect(image, "postclose", G_CALLBACK(DeleteBuffer), buffer);
} else {
// Could not read header data
(baton->err).append("Input buffer has corrupt header");
inputImageType = ImageType::UNKNOWN;
DeleteBuffer(NULL, buffer);
}
} else {
(baton->err).append("Input buffer contains unsupported image format");
DeleteBuffer(NULL, buffer);
}
} else {
// From file
@ -175,7 +196,7 @@ class ResizeWorker : public NanAsyncWorker {
(baton->err).append("Input file is of an unsupported image format");
}
}
if (inputImageType == ImageType::UNKNOWN) {
if (image == NULL || inputImageType == ImageType::UNKNOWN) {
return Error(baton, hook);
}
vips_object_local(hook, image);
@ -775,11 +796,6 @@ class ResizeWorker : public NanAsyncWorker {
void HandleOKCallback () {
NanScope();
// Free input Buffer
if (baton->bufferInLength > 0) {
g_free(baton->bufferIn);
}
Handle<Value> argv[3] = { NanNull(), NanNull(), NanNull() };
if (!baton->err.empty()) {
// Error
@ -804,6 +820,7 @@ class ResizeWorker : public NanAsyncWorker {
if (baton->bufferOutLength > 0) {
// Copy data to new Buffer
argv[1] = NanNewBufferHandle(static_cast<char*>(baton->bufferOut), baton->bufferOutLength);
// bufferOut was allocated via malloc
g_free(baton->bufferOut);
// Add buffer size to info
info->Set(NanNew<String>("size"), NanNew<Uint32>(static_cast<uint32_t>(baton->bufferOutLength)));
@ -925,9 +942,11 @@ NAN_METHOD(resize) {
Local<Object> buffer = options->Get(NanNew<String>("bufferIn"))->ToObject();
// Take a copy of the input Buffer to avoid problems with V8 heap compaction
baton->bufferInLength = node::Buffer::Length(buffer);
baton->bufferIn = g_malloc(baton->bufferInLength);
baton->bufferIn = new char[baton->bufferInLength];
memcpy(baton->bufferIn, node::Buffer::Data(buffer), baton->bufferInLength);
options->Set(NanNew<String>("bufferIn"), NanNull());
// Notify V8 GC of memory allocation
NanAdjustExternalMemory(static_cast<int>(baton->bufferInLength));
}
// ICC profile to use when input CMYK image has no embedded profile
baton->iccProfilePath = *String::Utf8Value(options->Get(NanNew<String>("iccProfilePath"))->ToString());