After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 739835 - g_win32_get_package_installation_directory_of_module() incorrectly handles bin and lib folders
g_win32_get_package_installation_directory_of_module() incorrectly handles bi...
Status: RESOLVED OBSOLETE
Product: glib
Classification: Platform
Component: win32
unspecified
Other Windows
: Normal normal
: ---
Assigned To: gtk-win32 maintainers
gtk-win32 maintainers
: 737341 784337 (view as bug list)
Depends on:
Blocks:
 
 
Reported: 2014-11-09 04:37 UTC by Patrick Griffis (tingping)
Modified: 2018-05-24 17:12 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
Fix handling some paths with bin/lib (1.49 KB, patch)
2014-11-09 05:13 UTC, Patrick Griffis (tingping)
none Details | Review

Description Patrick Griffis (tingping) 2014-11-09 04:37:39 UTC
The documentation says that "If that directory's last component is "bin" or "lib", its parent directory is returned, otherwise the directory itself." but the actual behavior is that it cuts the directory at any occurrence of bin or lib.

For example "C:\bin\MyProgram\bin\program.exe" will return "C:\" instead of "C:\bin\MyProgram".

The issue in code is pretty obvious that it just loops over checking each dir for bin/lib and breaks.
Comment 1 Patrick Griffis (tingping) 2014-11-09 04:56:52 UTC
Slight correction in the example actually. The one given works fine the one that does not work is if there is no bin at the end.

"C:\bin\MyProgram\program.exe" will return "C:\" instead of
"C:\bin\MyProgram".
Comment 2 Patrick Griffis (tingping) 2014-11-09 05:13:56 UTC
Created attachment 290255 [details] [review]
Fix handling some paths with bin/lib
Comment 3 LRN 2014-11-22 05:53:55 UTC
What about
"C:/Progs/lib/myprogram/libmyprogram.dll"?
Should it return
"C:/Progs"
or
"C:/Progs/lib/myprogram"?
Comment 4 Patrick Griffis (tingping) 2014-11-22 06:34:35 UTC
It should only cut off *trailing* bin or lib. So in that case it should return "C:\Progs\lib\myprogram".
Comment 5 LRN 2014-11-22 06:43:55 UTC
This means that this function won't work on plugins and other libraries that live in lib/*/. Is that acceptable?
Comment 6 Patrick Griffis (tingping) 2014-11-22 07:43:41 UTC
I am not entirely certain about that use case, I don't use it for that at least. It is possible "bin" and "lib" should behave differently for this but the current documentation suggests that lib folders like that would not work.
Comment 7 Patrick Griffis (tingping) 2014-11-22 07:48:00 UTC
Actually reading it again the docs are very explicit that your example should not work:

"DLLs that are of the dynamically loaded module or plugin variety are often located in more private locations deeper down in the tree, from which it is impossible for GLib to deduce the root of the package installation.
Comment 8 LRN 2014-11-22 08:55:33 UTC
In that case, i guess, it should be applied.

I'm a bit worried about the effect this change my have on applications that rely on its current behaviour, but i have no means to test this.
Comment 9 Patrick Griffis (tingping) 2014-12-21 00:30:30 UTC
Any update on merging this?
Comment 10 Patrick Griffis (tingping) 2014-12-21 05:57:00 UTC
Actually it would appear that bug 73394[1] added this bug on purpose. Maybe we could settle in the middle and only do his lookup method for lib, or maybe we could just update the docs that are now wrong to say when this behavior is and isn't broken.


[1] https://bugzilla.gnome.org/show_bug.cgi?id=733934
Comment 11 Ignacio Casal Quinteiro (nacho) 2014-12-21 09:03:41 UTC
I guess we could have 2 methods, one with the old behavior to not break Tinping's use case and another new one that handles the case of the private library as in gedit's use case. Thought's?
Comment 12 LRN 2014-12-21 09:30:06 UTC
That's equiexcrementous for me. My main grip with this API (not covered by this bugreport or the previous one) is that the glib module handle is not available to the application (meaning that g_win32_get_package_installation_directory_of_module() can't be used to determine the root directory for glib package itself, only for your application/module/whatever).
Comment 13 LRN 2014-12-22 03:57:47 UTC
Actually, that could be the compromise. If you have a module handle for glib itself, you don't need to use g_win32_get_package_installation_directory_of_module() on plugins, you use it on glib DLL, which is, hopefully, in bin subdir of the root directory.

H-m-m-m...no, but if glib and gedit are installed into different subtrees (dunno why anyone would do that, but it's doable), then that wouldn't work, obviously.

OK, i'm out of ideas.
Comment 14 Ignacio Casal Quinteiro (nacho) 2015-02-22 09:49:23 UTC
maybe what we should do in win32 is to actually install the private library in bin instead of whatever hidden place we put it now.
Comment 15 LRN 2015-02-22 10:11:55 UTC
That would work, but the whole point of a "private" library will be kind of lost. Also, it might take a bit more makefile mojo to install it into bin subdirectory on w32 and to install it into lib/<something> subdirectory everywhere else.

What are the valid FHS locations for DLLs?

<root>/bin/
<root>/lib/<something>/

Is that all? Libexec, maybe?
Also, is <something> allowed to contain '/'?
Can <root> be empty (i.e. C:/bin/libnacho-0.dll and C:/lib/nacho/private.dll)?

If we can strictly define this, then coding the function such as that it works in a FHSish way for these (and only for these) cases and falls back to non-FHS is only a matter of time.
Comment 16 George Kiagiadakis 2015-08-29 18:04:02 UTC
*** Bug 737341 has been marked as a duplicate of this bug. ***
Comment 17 Eduard Braun 2017-09-16 12:55:44 UTC
This is still an issue:
In the current scenario [1] it's obvious that this bug breaks relocation features of GTK+ which eventually caused undefined behavior and a crash of the application in question (Inkscape).

I'd say simply fixing the documentation is not enough as software already depends on the documented functionality (which makes sense for the /bin folder) which is now broken.
If some modules in /lib need special treatment I suggest to either provide a special function for them or make the current function work differently for bin and lib (although I really don't like the idea of such "magic" behavior).

As it stands it seems like plugins need to do a better job at finding their package installation directory themselves as (like properly documented) this is beyond the scope of glib and the changes introduced in bug #733934 should be considered as a regression which broke the desired (and documented) functionality of g_win32_get_package_installation_directory_of_module.


[1] https://bugs.launchpad.net/inkscape/+bug/1716212
Comment 18 Eduard Braun 2017-09-16 13:09:24 UTC
Another issue I found (while searching for this one) affecting gstreamer: bug 784337.

While the location in question actually is of the /lib/module/ variety (that's supposed to be fixed by the changes introduced bug 733934) the result is pretty much the opposite: Lookup of /lib/gstreamer-1.0 fails because of the flawed behavior.
Comment 19 Sebastian Dröge (slomo) 2017-09-16 13:32:40 UTC
*** Bug 784337 has been marked as a duplicate of this bug. ***
Comment 20 LRN 2017-09-16 14:06:22 UTC
We could fix this for bin directories only, i.e. make the code only recognize <root>/bin/<executable>, and not <root>/bin/<any number of subdirectories>/<executable>. Does anyone know packages that have executables (or libraries) in subdirectories of /bin?

For /lib it's different - i ran a search for .so files on a debian machine, and it returned very varied results. Packages put .so (and .so.*) files into any number of subdirectories of /usr/lib. There's no limit on the depth or the names of these subdirectories. So if we want plugins to be able to find the root directory (was that even a good decision, i wonder...), we have to keep current behaviour for /lib
Comment 21 Bakhtiar Hasmanan 2017-09-16 14:29:47 UTC
I maintain pygobject for windows and been reverting *all* patches since I reported https://bugzilla.gnome.org/show_bug.cgi?id=739835

sigh, seriously
Comment 22 Eduard Braun 2017-09-17 13:39:54 UTC
I think we've lost sight of what this function should actually do, so let me clarify that part again, so maybe we can agree that the documented functionality is the *intended* functionality:

Scenario 1: We have a Unix-like directory structure
This means binaries go into $INSTALL_DIR/bin, public libraries go into $INSTALL_DIR/lib (or maybe subfolders thereof). In this scenario this function would not be needed at all (it's a Windows compatibility function)! Programs can easily construct paths as all relative locations are perfectly known.

The function becomes necessary when we take into account the peculiarities of some software when packaged for windows.

Scenario 2a: We still have a Unix-like directory structure
It's possible software packaged for Windows keeps the Unix-like directory structure so in principle still nothing needs to be done, we basically have Scenario 1 again.

Scenario 2b: We have a "typical" Windows package structure
Most binaries and public libraries are now moved directly into $INSTALL_DIR/. And this (and only this!) is the case where we actually need g_win32_get_package_installation_directory_of_module() as we can not simply assume our module is in the /bin or /lib subfolder of $INSTALL_DIR but we actually have to check if our module was copied directly into $INSTALL_DIR.


In other words: The function has to check if our executable or library is still in /bin or /lib (and return the parent directory in that case) or if it was copied directly into installation directory (in which case this directory has to be returned unchanged).


Now for the (in my eyes invalid) scenario that Ignacio tried to address in bug 733934: Consider a module in $INSTALL_DIR/lib/gedit. Now there are only two possibilities
a) The module is still in $INSTALL_DIR/lib/gedit and that means the developer of the software knows at all times how to find it! Also they know exactly where the $INSTALL_DIR is (namely in $INSTALL_DIR/lib/gedit/../..) and consequently g_win32_get_package_installation_directory_of_module() is not required.
b) Some "idiot" copied it to $INSTALL_DIR and we're f*cked anyway. There is no possibility to tell where the $INSTALL_DIR is in this case without putting in additional assumptions (which we can not safely do within the scope of glib).

If the developer decides to put additional path components after /bin or /lib that is something glib can not now, and it should consequently not assume it would be OK to cut path components from the directory at will until it finds any /bin or /lib. So the only reasonable (convenience) solution I can think of would be to require the developer to tell glib "my module is not directly in /lib but *should* be in "lib/gedit", please check if you can derive the installation directory with that scheme (i.e. by cutting /lib/gedit from the end of the path). Everything beyond that breaks the intended functionality!
Comment 23 LRN 2017-09-17 15:21:41 UTC
(In reply to Eduard Braun from comment #22)
> Scenario 1: We have a Unix-like directory structure
> This means binaries go into $INSTALL_DIR/bin, public libraries go into
> $INSTALL_DIR/lib (or maybe subfolders thereof). In this scenario this
> function would not be needed at all (it's a Windows compatibility function)!
> Programs can easily construct paths as all relative locations are perfectly
> known.

That's not how i view this (and i suspect that app developers don't view it that way either). There's a function that will get you the root directory, and anyone using glib is encouraged to use it, for portability and convenience. Even in simple cases like this. Because this is C, and mucking around with strings is no fun; also, on Windows you have to go the extra mile to get the path to a binary, from which you infer the root directory - again, glib handles all that for you.


> Now for the (in my eyes invalid) scenario that Ignacio tried to address in
> bug 733934: Consider a module in $INSTALL_DIR/lib/gedit. Now there are only
> two possibilities
> a) The module is still in $INSTALL_DIR/lib/gedit and that means the
> developer of the software knows at all times how to find it!

The decision where to install plugins is not always in the hands of their developer, sometimes package maintainers decide that (for example, GStreamer has an environment variable which tells it where to look for plugins - they can be literally anywhere). You can't assume that your gedit plugin is in $INSTALL_DIR/lib/gedit, even if that is what you intended originally. The only reasonable expectation is that plugin is somewhere within the directory tree rooted in $INSTALL_DIR (although even that can be invalid sometimes)

That said, there can be a good argument that plugins *shouldn't* be aware of their location much (other than their own directory subtree; i.e. the files they carry with their own binary, if any), and if they need to access resources from the parent application, the parent application should supply them with the path to the root directory. Plugins that are *still* somewhere under $INSTALL_DIR could try to infer $INSTALL_DIR from their own path, but plugins that are outside of $INSTALL_DIR have absolutely no way to know where $INSTALL_DIR is, unless their parent application tells them. Specifically, glib does not expose a function that reports installation directory of glib itself (if it is even possible to assume that glib is installed in the same directory as the application that uses it).

My offer for a quick fix still stands: revert to simple behaviour for '/bin' (cut the trailing /bin only) and keep the current behaviour for '/lib'. Thus plugins in /lib/.../ subdirectories will continue to work, plugins and subapplications in /bin/.../ subdirectories will not work (with the expectation that no one was foolish enough to put anything into /bin/.../ subdirs, thus no one will get hurt), and people who just give the 'bin' name to a subdirectory in their tree will not be screwed (unless 'bin' is the trailing directory, in which case all bets are off). In long term we should maybe encourage applications to help plugins locate the directories they need.
Comment 24 Eduard Braun 2017-09-17 16:03:33 UTC
> That's not how i view this (and i suspect that app developers don't
> view it that way either).

Well, I guess I'm an "app developer" (whatever that means) myself and the current behavior breaks my app (as it does others, see the duplicates), so statistics disagree...

> There's a function that will get you the root directory, and anyone
> using glib is encouraged to use it, for portability and convenience.

g_win32_get_package_installation_directory_of_module is win32-only... If people use that on *nix for anything different than what I wrote above I'm afraid they have more serious problems.

What I tried to point out was, that the *only* thing this function has to do (and can do) is to determine if it needs to strip a /bin or /lib from the module path and nothing else! (It should not be smart in unexpected ways like it is now which will result in breakage - especially if the function thinks it's smarter than it realistically can be).

> The decision where to install plugins is not always in the hands
> of their developer, sometimes package maintainers decide that.

That's not glib's issue though is it? And if we open that can of worms and want to make it our issue, it's out of the scope of g_win32_get_package_installation_directory_of_module as it affects applications running in *nix the exact same way (which can not use this function to begin with as already noted).

> for example, GStreamer has an environment variable which tells it
> where to look for plugins - they can be literally anywhere

And the current logic will blindly try to derive the installation directory from "anywhere" - exactly my point. It's dangerous!

> That said, there can be a good argument that plugins *shouldn't*
> be aware of their location much (other than their own directory
> subtree; i.e. the files they carry with their own binary, if any),
> and if they need to access resources from the parent application,
> the parent application should supply them with the path to the root
> directory.

I agree 100% but the current (undocumented) functionality of the function suggests something else and gives developers the impression it could do something it realistically *can not*. Even if we finally fix the documentation, developers who rely on the promise we can give them the correct installation directory even if they pass some "random" module in some "random" path will inevitable be facing breakages if our assumptions were not good enough (and they can not be in all those border cases you're mentioning). So why five a false impression insted of sticking with the documented behavior which we can guarantee?

> My offer for a quick fix still stands: [...]

Well, it's better than nothing (at least it fixes some breakage). But as mentioned above we would introduce inconsistent ("magic") behavior to cobble together an unjustified and unreliable workaround for modules in /lib/... we realistically can not and should not offer. Also it would not solve bug 737341.

What about my suggestions to have an overload with a parameter that accepts the part after "bin/" or "lib/"? This way we can *safely* offer some additional functionality without the hazards of blindly guessing.
Comment 25 LRN 2017-09-17 17:07:10 UTC
(In reply to Eduard Braun from comment #24)
> > There's a function that will get you the root directory, and anyone
> > using glib is encouraged to use it, for portability and convenience.
> 
> g_win32_get_package_installation_directory_of_module is win32-only... If
> people use that on *nix for anything different than what I wrote above I'm
> afraid they have more serious problems.

Yeah, you're right, i misspoke earlier. That said, this function is also used internally by glib to provide directories for g_get_system_data_dirs() and the like. Internal gettext glue code also uses that function to locate the /share/locale directory. However, glib is able to feed it its own dll internally, so this would break if *glib* itself is installed in crazy places (this is likely what happens with Inkscape). That function is *also* called internally with NULL argument, thus finding the root directory relative to the currently-running executable...H-m-m...So, yeah, plugins only get a shot at this if they deliberately call this function, passing their own module argument (which they have to get themselves, glib won't help in this).

nacho, what was the use-case for gedit plugins to call this function, again? If they also relied on implicit, internal calls of this function by glib, why was the change necessary at all?
Comment 26 GNOME Infrastructure Team 2018-05-24 17:12:18 UTC
-- GitLab Migration Automatic Message --

This bug has been migrated to GNOME's GitLab instance and has been closed from further activity.

You can subscribe and participate further through the new bug through this link to our GitLab instance: https://gitlab.gnome.org/GNOME/glib/issues/955.