dlopen: on x/lib search x/bin if exe is in x/bin

On 09/02/2016 11:03 AM, Corinna Vinschen wrote:
> On Sep  2 10:46, Michael Haubenwallner wrote:
>> On 09/01/2016 03:32 PM, Corinna Vinschen wrote:
>>> You could just use the global variable program_invocation_name.  If in
>>> doubt, use the Windows path global_progname and convert it to full POSIX
>>> via cygwin_conv_path.
>>
>> Patch updated, using global_progname now.
>
> Looks good and you're right to do it this way since I just noticed
> that program_invocation_name may return a relative pathname.

Yep.

> Btw., in other calls which require the full POSIX path we use
> mount_table->conv_to_posix_path instead of cygwin_conv_path (see
> e. g. fillout_pinfo()).  It's a bit faster.  Maybe something for a
> followup patch.

No problem - attached.
This renders the original patch 4/4 valid again.

> Note for some later improvement:  I really wonder why we don't store
> the absolute POSIX path of the current executable globally yet...

Same here.

Thanks!
/haubi/

>From f7255edd33cb4abe34f27188aab8dccdfa5dd2a0 Mon Sep 17 00:00:00 2001
From: Michael Haubenwallner <michael.haubenwallner@ssi-schaefer.com>
Date: Wed, 31 Aug 2016 18:05:11 +0200
Subject: [PATCH 3/4] dlopen: on x/lib search x/bin if exe is in x/bin

citing https://cygwin.com/ml/cygwin-developers/2016-08/msg00020.html
> Consider the file /usr/bin/cygz.dll:
> - dlopen (libz.so)            success
> - dlopen (/usr/bin/libz.so)   success
> - dlopen (/usr/lib/libz.so)   fails

* dlfcn.c (dlopen): For dlopen("x/lib/N"), when the application
executable is in "x/bin/", search for "x/bin/N" before "x/lib/N".
This commit is contained in:
Michael Haubenwallner 2016-09-02 13:57:20 +02:00 committed by Corinna Vinschen
parent b37c3ed5e5
commit f763e2dc88

View file

@ -20,6 +20,7 @@ details. */
#include "cygtls.h"
#include "tls_pbuf.h"
#include "ntdll.h"
#include "shared_info.h"
#include "pathfinder.h"
/* Dumb allocator using memory from tmp_pathbuf.w_get ().
@ -153,6 +154,31 @@ collect_basenames (pathfinder::basenamelist & basenames,
basenames.appendv (basename, baselen, ext, extlen, NULL);
}
/* Identify dir of current executable into exedirbuf using wpathbuf buffer.
Return length of exedirbuf on success, or zero on error. */
static int
get_exedir (char * exedirbuf, wchar_t * wpathbuf)
{
/* Unless we have a special cygwin loader, there is no such thing like
DT_RUNPATH on Windows we can use to search for dlls, except for the
directory of the main executable. */
*exedirbuf = '\0';
wchar_t * wlastsep = wcpcpy (wpathbuf, global_progname);
/* like wcsrchr(L'\\'), but we know the wcslen already */
while (--wlastsep > wpathbuf)
if (*wlastsep == L'\\')
break;
if (wlastsep <= wpathbuf)
return 0;
*wlastsep = L'\0';
if (mount_table->conv_to_posix_path (wpathbuf, exedirbuf, 0))
return 0;
return strlen (exedirbuf);
}
extern "C" void *
dlopen (const char *name, int flags)
{
@ -184,13 +210,28 @@ dlopen (const char *name, int flags)
/* handle for the named library */
path_conv real_filename;
wchar_t *wpath = tp.w_get ();
char *cpath = tp.c_get ();
pathfinder finder (allocator, basenames); /* eats basenames */
if (have_dir)
{
int dirlen = basename - 1 - name;
/* if the specified dir is x/lib, and the current executable
dir is x/bin, do the /lib -> /bin mapping, which is the
same actually as adding the executable dir */
if (dirlen >= 4 && !strncmp (name + dirlen - 4, "/lib", 4))
{
int exedirlen = get_exedir (cpath, wpath);
if (exedirlen == dirlen &&
!strncmp (cpath, name, dirlen - 4) &&
!strcmp (cpath + dirlen - 4, "/bin"))
finder.add_searchdir (cpath, exedirlen);
}
/* search the specified dir */
finder.add_searchdir (name, basename - 1 - name);
finder.add_searchdir (name, dirlen);
}
else
{