8000 Fix HEIF image handling with uninitialized library by YakoYakoYokuYoku · Pull Request #895 · libgd/libgd · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Fix HEIF image handling with uninitialized library #895

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

YakoYakoYokuYoku
Copy link
Contributor

From version 1.13.0 of libheif the library needs to be initialized to load its plugins and it has to be done by any consumer of the library, including libgd, I've forgot to add such thing. This PR adds two function for it, gdHeifInit and gdHeifDeinit, the former gets called by any method that handles HEIF images and the latter is used for cleanup. Fixes #889.

Copy link
Member
@vapier vapier left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can't expose format-specific init functions like this. no one will call them, and we don't want multiple inits. I'm not sure there's no point in calling deinit at all? in which case, can't we have the heif backend call the init function itself on demand and that's it?

src/gd_heif.c Outdated
@@ -23,13 +23,52 @@
#define GD_HEIF_ALLOC_STEP (4*1024)
#define GD_HEIF_HEADER 12

static int heifInit = 0;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bools should be bool, not int

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe more importantly, that won't work for multi-threading, I think.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

neither type works for multithreading. they'd need to be atomic and/or grab pthread locks.

that said, I don't think we've ever thought about MT, so I wouldn't be surprised if there were already issues in the codebase.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not aware 8000 of any multi-threading issues in libgd when used with PHP. :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

gdkanji.c is not MT safe. none of the error handler APIs are MT safe (which is to say, the handlers are per-process, not per-thread). I guess most MT issues after that would be library-specific and not really on gd's plate.

maybe along those lines, should we punt these problems completely onto the user ? if the only thing gdHeifInit does is call heif_init, and the only reason people would call gdHeifInit is because they want to explicitly use the HEIF format, then why not force them to call heif_init themselves ? that would also let them call heif_deinit if they really wanted to.

if we can't handle it automatically in a format/library agnostic way, i don't think we're bringing any value-add here.

@cmb69
Copy link
Member
cmb69 commented Oct 27, 2024

First, thank you for the PR @YakoYakoYokuYoku!

I'm not sure there's no point in calling deinit at all?

Well, they may release resources there, so it would be nice to call the function.

src/gd_heif.c Outdated
@@ -23,13 +23,52 @@
#define GD_HEIF_ALLOC_STEP (4*1024)
#define GD_HEIF_HEADER 12

static int heifInit = 0;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe more importantly, that won't work for multi-threading, I think.

src/gd_heif.c Outdated
Comment on lines 177 to 180
if (gdHeifInit()) {
gd_error("gd-heif failure to initialize library");
return GD_FALSE;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indentation seems to be off here (and below).

@vapier
Copy link
Member
vapier commented Oct 28, 2024

Well, they may release resources there, so it would be nice to call the function.

i grok the hypothetical, but i question the realistic/practical aspects. i still don't think people will (or reasonably can) call format-specific init/deinit functions. the user of gd (e.g. php code) can be disconnected from the builder of gd (e.g. the server/distro), and the code can be written in a way that is format agnostic so users could upload arbitrary content.

calling format-specific init automatically is fairly easy for us in gd since it'd be a one-time event, but calling deinit & re-init could easily be difficult to get right. if it's a loop processing multiple images, do we deinit when the image is written out or destroyed ? do we do some refcounting in case multiple images are loaded at once ? do we do some basic GC to delay ?

unless the deinit releases a significant amount of resources, I argue that we should never do it, nor expose an API for it.

@cmb69
Copy link
Member
cmb69 commented Dec 21, 2024

unless the deinit releases a significant amount of resources, I argue that we should never do it, nor expose an API for it.

From https://github.com/strukturag/libheif/blob/33ec3d63470944906dbccffa085970083969de3a/libheif/api/libheif/heif.h#L544-L545:

For backwards compatibility, it is not really necessary to call heif_init(), but some library memory objects will never be freed if you do not call heif_init()/heif_deinit().

I haven't checked the amount of resources which would not be freed, but given that heif_init() and heif_deinit() are only available as of libheif 1.13.0, we cannot call the functions unconditionally anyway, unless we raise the libheif requirements (so far we require libheif >= 1.7.0).

Given that there are more urgent issues regarding libgd than some memory leak at the end of the process (well, usually only there), I think we should postpone calling these functions. And the cleaner solution would likely be to introduce some gdInit()/gdFinalize() first, but these may have their own issues (and wouldn't be available with older libgd).

@vapier
Copy link
Member
vapier commented Dec 28, 2024

I haven't checked the amount of resources which would not be freed

Looking at the implementation, it unloads any loaded external plugins, and clears a colorspace LUT. It doesn't seem like those alone are a big enough deal for us to care about.

Really the only concerning thing is what @YakoYakoYokuYoku noted at the top: if you don't call init, then no external plugins will be loaded.

but given that heif_init() and heif_deinit() are only available as of libheif 1.13.0, we cannot call the functions unconditionally anyway, unless we raise the libheif requirements (so far we require libheif >= 1.7.0).

If the libheif version is available at compile time, we can check that. Or we can add configure-time checks for the functions and use them if available. I won't seriously suggest probing via dlopen and related APIs.

And the cleaner solution would likely be to introduce some gdInit()/gdFinalize() first.

I'm still on the side of doing nothing here. This only affects people using libheif with external plugins, and those people are free to call init themselves. Otherwise it's extra boilerplate that is a nop, and decades of existing GD code prob won't update to use it.

The libheif API says its init/deinit calls are refcounted, so we could call init safely everytime HEIF APIs are used, but we wouldn't call deinit, so we'd be leaking that logic. Which, practically speaking, is what we already do with older versions, so arguably that's maintaining status quo.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Test heif/heif_read fails with libheif 1.18.0+
3 participants
0