Merge "Fix memory leak where we close the descriptor instead of the file."

This commit is contained in:
Elliott Hughes
2014-11-10 16:46:43 +00:00
committed by Gerrit Code Review

View File

@@ -478,7 +478,7 @@ static jobject nativeDecodeFileDescriptor(JNIEnv* env, jobject clazz, jobject fi
NPE_CHECK_RETURN_ZERO(env, fileDescriptor); NPE_CHECK_RETURN_ZERO(env, fileDescriptor);
jint descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor); int descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor);
struct stat fdStat; struct stat fdStat;
if (fstat(descriptor, &fdStat) == -1) { if (fstat(descriptor, &fdStat) == -1) {
@@ -486,16 +486,27 @@ static jobject nativeDecodeFileDescriptor(JNIEnv* env, jobject clazz, jobject fi
return nullObjectReturn("fstat return -1"); return nullObjectReturn("fstat return -1");
} }
// Restore the descriptor's offset on exiting this function. // Restore the descriptor's offset on exiting this function. Even though
// we dup the descriptor, both the original and dup refer to the same open
// file description and changes to the file offset in one impact the other.
AutoFDSeek autoRestore(descriptor); AutoFDSeek autoRestore(descriptor);
FILE* file = fdopen(descriptor, "r"); // Duplicate the descriptor here to prevent leaking memory. A leak occurs
// if we only close the file descriptor and not the file object it is used to
// create. If we don't explicitly clean up the file (which in turn closes the
// descriptor) the buffers allocated internally by fseek will be leaked.
int dupDescriptor = dup(descriptor);
FILE* file = fdopen(dupDescriptor, "r");
if (file == NULL) { if (file == NULL) {
// cleanup the duplicated descriptor since it will not be closed when the
// file is cleaned up (fclose).
close(dupDescriptor);
return nullObjectReturn("Could not open file"); return nullObjectReturn("Could not open file");
} }
SkAutoTUnref<SkFILEStream> fileStream(new SkFILEStream(file, SkAutoTUnref<SkFILEStream> fileStream(new SkFILEStream(file,
SkFILEStream::kCallerRetains_Ownership)); SkFILEStream::kCallerPasses_Ownership));
// Use a buffered stream. Although an SkFILEStream can be rewound, this // Use a buffered stream. Although an SkFILEStream can be rewound, this
// ensures that SkImageDecoder::Factory never rewinds beyond the // ensures that SkImageDecoder::Factory never rewinds beyond the