mirror of
https://github.com/php/php-src.git
synced 2025-08-16 14:08:47 +02:00
Fix imagecreatefromavif() memory leak
This has been reported as https://github.com/libgd/libgd/issues/831. We port the respective fix to our bundled libgd. Closes GH-8812.
This commit is contained in:
parent
3fed226e62
commit
036bed01ce
2 changed files with 36 additions and 17 deletions
3
NEWS
3
NEWS
|
@ -19,6 +19,9 @@ PHP NEWS
|
||||||
. Fixed bug #78139 (timezone_open accepts invalid timezone string argument).
|
. Fixed bug #78139 (timezone_open accepts invalid timezone string argument).
|
||||||
(Derick)
|
(Derick)
|
||||||
|
|
||||||
|
GD:
|
||||||
|
. Fixed imagecreatefromavif() memory leak. (cmb)
|
||||||
|
|
||||||
- MBString:
|
- MBString:
|
||||||
. mb_detect_encoding recognizes all letters in Czech alphabet (alexdowad)
|
. mb_detect_encoding recognizes all letters in Czech alphabet (alexdowad)
|
||||||
. mb_detect_encoding recognizes all letters in Hungarian alphabet (alexdowad)
|
. mb_detect_encoding recognizes all letters in Hungarian alphabet (alexdowad)
|
||||||
|
|
|
@ -150,6 +150,11 @@ static avifBool isAvifError(avifResult result, const char *msg) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct avifIOCtxReader {
|
||||||
|
avifIO io; // this must be the first member for easy casting to avifIO*
|
||||||
|
avifROData rodata;
|
||||||
|
} avifIOCtxReader;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
<readfromCtx> implements the avifIOReadFunc interface by calling the relevant functions
|
<readfromCtx> implements the avifIOReadFunc interface by calling the relevant functions
|
||||||
in the gdIOCtx. Our logic is inspired by avifIOMemoryReaderRead() and avifIOFileReaderRead().
|
in the gdIOCtx. Our logic is inspired by avifIOMemoryReaderRead() and avifIOFileReaderRead().
|
||||||
|
@ -165,8 +170,8 @@ static avifBool isAvifError(avifResult result, const char *msg) {
|
||||||
*/
|
*/
|
||||||
static avifResult readFromCtx(avifIO *io, uint32_t readFlags, uint64_t offset, size_t size, avifROData *out)
|
static avifResult readFromCtx(avifIO *io, uint32_t readFlags, uint64_t offset, size_t size, avifROData *out)
|
||||||
{
|
{
|
||||||
void *dataBuf = NULL;
|
|
||||||
gdIOCtx *ctx = (gdIOCtx *) io->data;
|
gdIOCtx *ctx = (gdIOCtx *) io->data;
|
||||||
|
avifIOCtxReader *reader = (avifIOCtxReader *) io;
|
||||||
|
|
||||||
// readFlags is unsupported
|
// readFlags is unsupported
|
||||||
if (readFlags != 0) {
|
if (readFlags != 0) {
|
||||||
|
@ -182,28 +187,34 @@ static avifResult readFromCtx(avifIO *io, uint32_t readFlags, uint64_t offset, s
|
||||||
if (!ctx->seek(ctx, (int) offset))
|
if (!ctx->seek(ctx, (int) offset))
|
||||||
return AVIF_RESULT_IO_ERROR;
|
return AVIF_RESULT_IO_ERROR;
|
||||||
|
|
||||||
dataBuf = avifAlloc(size);
|
if (size > reader->rodata.size) {
|
||||||
if (!dataBuf) {
|
reader->rodata.data = gdRealloc((void *) reader->rodata.data, size);
|
||||||
|
reader->rodata.size = size;
|
||||||
|
}
|
||||||
|
if (!reader->rodata.data) {
|
||||||
gd_error("avif error - couldn't allocate memory");
|
gd_error("avif error - couldn't allocate memory");
|
||||||
return AVIF_RESULT_UNKNOWN_ERROR;
|
return AVIF_RESULT_UNKNOWN_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the number of bytes requested.
|
// Read the number of bytes requested.
|
||||||
// If getBuf() returns a negative value, that means there was an error.
|
// If getBuf() returns a negative value, that means there was an error.
|
||||||
int charsRead = ctx->getBuf(ctx, dataBuf, (int) size);
|
int charsRead = ctx->getBuf(ctx, (void *) reader->rodata.data, (int) size);
|
||||||
if (charsRead < 0) {
|
if (charsRead < 0) {
|
||||||
avifFree(dataBuf);
|
|
||||||
return AVIF_RESULT_IO_ERROR;
|
return AVIF_RESULT_IO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
out->data = dataBuf;
|
out->data = reader->rodata.data;
|
||||||
out->size = charsRead;
|
out->size = charsRead;
|
||||||
return AVIF_RESULT_OK;
|
return AVIF_RESULT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
// avif.h says this is optional, but it seemed easy to implement.
|
// avif.h says this is optional, but it seemed easy to implement.
|
||||||
static void destroyAvifIO(struct avifIO *io) {
|
static void destroyAvifIO(struct avifIO *io) {
|
||||||
gdFree(io);
|
avifIOCtxReader *reader = (avifIOCtxReader *) io;
|
||||||
|
if (reader->rodata.data != NULL) {
|
||||||
|
gdFree((void *) reader->rodata.data);
|
||||||
|
}
|
||||||
|
gdFree(reader);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set up an avifIO object.
|
/* Set up an avifIO object.
|
||||||
|
@ -217,21 +228,23 @@ static void destroyAvifIO(struct avifIO *io) {
|
||||||
|
|
||||||
// TODO: can we get sizeHint somehow?
|
// TODO: can we get sizeHint somehow?
|
||||||
static avifIO *createAvifIOFromCtx(gdIOCtx *ctx) {
|
static avifIO *createAvifIOFromCtx(gdIOCtx *ctx) {
|
||||||
avifIO *io;
|
struct avifIOCtxReader *reader;
|
||||||
|
|
||||||
io = gdMalloc(sizeof(*io));
|
reader = gdMalloc(sizeof(*reader));
|
||||||
if (io == NULL)
|
if (reader == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
// TODO: setting persistent=FALSE is safe, but it's less efficient. Is it necessary?
|
// TODO: setting persistent=FALSE is safe, but it's less efficient. Is it necessary?
|
||||||
io->persistent = AVIF_FALSE;
|
reader->io.persistent = AVIF_FALSE;
|
||||||
io->read = readFromCtx;
|
reader->io.read = readFromCtx;
|
||||||
io->write = NULL; // this function is currently unused; see avif.h
|
reader->io.write = NULL; // this function is currently unused; see avif.h
|
||||||
io->destroy = destroyAvifIO;
|
reader->io.destroy = destroyAvifIO;
|
||||||
io->sizeHint = 0; // sadly, we don't get this information from the gdIOCtx.
|
reader->io.sizeHint = 0; // sadly, we don't get this information from the gdIOCtx.
|
||||||
io->data = ctx;
|
reader->io.data = ctx;
|
||||||
|
reader->rodata.data = NULL;
|
||||||
|
reader->rodata.size = 0;
|
||||||
|
|
||||||
return io;
|
return (avifIO *) reader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -576,6 +589,9 @@ cleanup:
|
||||||
|
|
||||||
if (avifOutput.data)
|
if (avifOutput.data)
|
||||||
avifRWDataFree(&avifOutput);
|
avifRWDataFree(&avifOutput);
|
||||||
|
|
||||||
|
if (avifIm)
|
||||||
|
avifImageDestroy(avifIm);
|
||||||
}
|
}
|
||||||
|
|
||||||
void gdImageAvifEx(gdImagePtr im, FILE *outFile, int quality, int speed)
|
void gdImageAvifEx(gdImagePtr im, FILE *outFile, int quality, int speed)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue