From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 126630 invoked by alias); 19 Aug 2016 16:39:28 -0000 Mailing-List: contact cygwin-developers-help@cygwin.com; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: cygwin-developers-owner@cygwin.com Mail-Followup-To: cygwin-developers@cygwin.com Received: (qmail 126610 invoked by uid 89); 19 Aug 2016 16:39:27 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-0.0 required=5.0 tests=AWL,BAYES_40,RCVD_IN_DNSWL_NONE,SPF_PASS autolearn=ham version=3.3.2 spammy=H*r:UNKNOWN, HTo:U*cygwin-developers, H*r:4.77, 2829 X-HELO: smtp.salomon.at Received: from smtp.salomon.at (HELO smtp.salomon.at) (193.186.16.13) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 19 Aug 2016 16:39:17 +0000 Received: from samail03.wamas.com ([172.28.33.235] helo=mailhost.salomon.at) by smtp.salomon.at with esmtps (UNKNOWN:DHE-RSA-AES256-SHA:256) (Exim 4.80.1) (envelope-from ) id 1bamp4-00064K-S0; Fri, 19 Aug 2016 18:39:13 +0200 Received: from [172.28.53.67] by mailhost.salomon.at with esmtps (UNKNOWN:AES128-SHA:128) (Exim 4.77) (envelope-from ) id 1bamp3-0003dx-O9; Fri, 19 Aug 2016 18:39:10 +0200 Subject: Re: About the dll search algorithm of dlopen To: cygwin-developers@cygwin.com References: <574E835E.7090109@ssi-schaefer.com> <20160601110947.GE11431@calimero.vinschen.de> <574EF07B.1060806@ssi-schaefer.com> <20160601201748.GI11431@calimero.vinschen.de> <57B735D5.4070401@ssi-schaefer.com> From: Michael Haubenwallner Message-ID: <57B7362D.8060707@ssi-schaefer.com> Date: Fri, 19 Aug 2016 16:39:00 -0000 User-Agent: Mozilla/5.0 (X11; Linux i686; rv:38.0) Gecko/20100101 Thunderbird/38.7.0 MIME-Version: 1.0 In-Reply-To: <57B735D5.4070401@ssi-schaefer.com> Content-Type: multipart/mixed; boundary="------------040402030003050404030805" X-SW-Source: 2016-08/txt/msg00001.txt.bz2 This is a multi-part message in MIME format. --------------040402030003050404030805 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 7bit Content-length: 3423 (and now with patches attached) On 08/19/2016 06:37 PM, Michael Haubenwallner wrote: > On 06/01/2016 10:17 PM, Corinna Vinschen wrote: >> On Jun 1 16:26, Michael Haubenwallner wrote: >>> On 06/01/2016 01:09 PM, Corinna Vinschen wrote: >>>> On Jun 1 08:40, Michael Haubenwallner wrote: >>>>> Hi, >>>>> >>>>> two issues with dlopen here (I'm about to prepare patches): >>>>> >>>>> *) The algorithm to combine dll file name variants with the search path >>>>> entries needs to be reordered, as in: >>>>> - for each dll file name variant: >>>>> - for each search path: >>>>> + for each search path entry: >>>>> + for each dll file name variant: >>>>> check if useable > >>>> However, if you can speed up the search process ignore the >>>> question... > > Not sure if there's a speedup actually, ... > >>> >>> This also depends on whether find_exec really is necessary here. >> >> Not as such necessary, it's just the function used to search in a >> search path. If you want to change that you have to rewrite the >> same logic again, just reversed. >> >> One way around YA code duplication could be some kind of path iterator >> class which could be used from find_exec as well as from >> get_full_path_of_dll. > > ... but: > 0001.patch is a draft for some new cygwin::pathfinder class, with > 0002.patch adding the executable's directory as searchpath, and > 0003.patch to search the PATH environment as well. > > Thoughts? > Any idea about different template nesting to be useful somewhere else? > >>>>> *) The directory of the current main executable should be searched >>>>> after LD_LIBRARY_PATH and before /usr/bin:/usr/lib. >>>>> And PATH should be searched before /usr/bin:/usr/lib as well. >>>> >>>> Checking the executable path and $PATH are Windows concepts. dlopen >>>> doesn't do that on POSIX systems and we're not doing that either. >>> >>> Agreed, but POSIX also does have the concept of embedded RUNPATH, >>> which is completely missing in Cygwin as far as I can see. >> >> RPATH and RUNPATH are ELF dynamic loader features, not supported by >> PE/COFF. > > In any case, to me it does feel quite important to have the (almost) same > dll search algorithm with dlopen() as with CreateProcess(). > >>> However, when dlopen is about to search some path list, I can imagine to >>> search the list of already loaded dlls first as well, but I'd prefer to >>> leave this up to LoadLibrary... >> >> This problem would only occur if dlopen is not called with a path. If >> the given pathname is a plain filename, we could simply add a call to >> GetModuleHandle and if it succeeds, return the handle (after checking >> for RTLD_NODELETE). > > But indeed this might lower the need for same search algorithms... > >>> Side note: >>> We also use some cl.exe/link.exe wrapper that supports LD_PRELOAD, >>> LD_LIBRARY_PATH, embedded RUNPATH, as well as lazy loading for both >>> LoadLibrary and CreateProcess: https://github.com/haubi/parity >>> Basically I'm wondering why Cygwin doesn't provide that (yet?)... >> >> We discussed implementing our own dynamic loader once, but gave up due >> to workload. Parity is LGPLed and thus can't be included into Cygwin >> itself. > > 've mentioned Parity more as proof-of-concept than for inclusion, > and accepting workload as reasoning. > > Let's see if I can live without the ELF dynloader features. > > Thanks! > /haubi/ > --------------040402030003050404030805 Content-Type: text/x-patch; name="0001-dlopen-search-each-name-within-one-single-search-dir.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename*0="0001-dlopen-search-each-name-within-one-single-search-dir.pa"; filename*1="tch" Content-length: 28707 >From fd7ed0d5cf2f255792e368bba3bc91c834d44896 Mon Sep 17 00:00:00 2001 From: Michael Haubenwallner Date: Tue, 31 May 2016 13:09:11 +0000 Subject: [PATCH 1/3] dlopen: search each name within one single search dir Search x/bin:x/lib if searching in x/lib. Introduces and uses new pathfinder template, which introduces and uses new samlist templates. --- winsup/cygwin/cygheap_malloc.h | 15 ++ winsup/cygwin/dlfcn.cc | 71 +++--- winsup/cygwin/pathfinder.h | 116 ++++++++++ winsup/cygwin/samlist.h | 253 +++++++++++++++++++++ winsup/cygwin/vstring.h | 503 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 918 insertions(+), 40 deletions(-) create mode 100644 winsup/cygwin/pathfinder.h create mode 100644 winsup/cygwin/samlist.h create mode 100644 winsup/cygwin/vstring.h diff --git a/winsup/cygwin/cygheap_malloc.h b/winsup/cygwin/cygheap_malloc.h index 74f0bb6..dfed929 100644 --- a/winsup/cygwin/cygheap_malloc.h +++ b/winsup/cygwin/cygheap_malloc.h @@ -52,4 +52,19 @@ char *__reg1 cstrdup1 (const char *); void __reg2 cfree_and_set (char *&, char * = NULL); } +#ifdef __cplusplus + +namespace cygwin { + + template + struct allocator + { + static void * alloc (size_t s) { return cmalloc_abort (HeapType, s); } + static void free (void *p) { cfree (p); } + }; + +} + +#endif + #endif /*_CYGHEAP_MALLOC_H*/ diff --git a/winsup/cygwin/dlfcn.cc b/winsup/cygwin/dlfcn.cc index 255a6d5..e2093ab 100644 --- a/winsup/cygwin/dlfcn.cc +++ b/winsup/cygwin/dlfcn.cc @@ -20,6 +20,7 @@ details. */ #include "cygtls.h" #include "tls_pbuf.h" #include "ntdll.h" +#include "pathfinder.h" static void set_dl_error (const char *str) @@ -28,29 +29,6 @@ set_dl_error (const char *str) _my_tls.locals.dl_error = 1; } -/* Look for an executable file given the name and the environment - variable to use for searching (eg., PATH); returns the full - pathname (static buffer) if found or NULL if not. */ -inline const char * -check_path_access (const char *mywinenv, const char *name, path_conv& buf) -{ - return find_exec (name, buf, mywinenv, FE_NNF | FE_DLL); -} - -/* Search LD_LIBRARY_PATH for dll, if it exists. Search /usr/bin and /usr/lib - by default. Return valid full path in path_conv real_filename. */ -static inline bool -gfpod_helper (const char *name, path_conv &real_filename) -{ - if (strchr (name, '/')) - real_filename.check (name, PC_SYM_FOLLOW | PC_NULLEMPTY); - else if (!check_path_access ("LD_LIBRARY_PATH", name, real_filename)) - check_path_access ("/usr/bin:/usr/lib", name, real_filename); - if (!real_filename.exists ()) - real_filename.error = ENOENT; - return !real_filename.error; -} - static bool get_full_path_of_dll (const char* str, path_conv &real_filename) { @@ -63,38 +41,50 @@ get_full_path_of_dll (const char* str, path_conv &real_filename) return false; /* Yes. Let caller deal with it. */ } - tmp_pathbuf tp; - char *name = tp.c_get (); + cygwin::samlist basenames; - strcpy (name, str); /* Put it somewhere where we can manipulate it. */ + const char *basename = strrchr (str, '/'); + basename = basename ? basename + 1 : str; - char *basename = strrchr (name, '/'); - basename = basename ? basename + 1 : name; - char *suffix = strrchr (name, '.'); - if (suffix && suffix < basename) - suffix = NULL; + int baselen = str + len - basename; + const char *suffix = strrchr (basename, '.'); + char const * ext = ""; + int extlen = 0; /* Is suffix ".so"? */ if (suffix && !strcmp (suffix, ".so")) { /* Does the file exist? */ - if (gfpod_helper (name, real_filename)) - return true; + basenames.append (cygwin::vstring::constructor_args (basename, baselen, NULL)); /* No, replace ".so" with ".dll". */ - strcpy (suffix, ".dll"); + baselen -= 3; + ext = ".dll"; + extlen = 4; } /* Does the filename start with "lib"? */ if (!strncmp (basename, "lib", 3)) { /* Yes, replace "lib" with "cyg". */ - strncpy (basename, "cyg", 3); - /* Does the file exist? */ - if (gfpod_helper (name, real_filename)) - return true; + basenames.append (cygwin::vstring::constructor_args ("cyg", 3, basename+3, baselen-3, ext, extlen, NULL)); /* No, revert back to "lib". */ - strncpy (basename, "lib", 3); } - if (gfpod_helper (name, real_filename)) + basenames.append (cygwin::vstring::constructor_args (basename, baselen, ext, extlen, NULL)); + + cygwin::pathfinder finder (basenames); + + if (basename > str) + finder.add_searchdir (str, basename - 1 - str); + else + { + /* NOTE: The Windows loader (for linked dlls) does + not use the LD_LIBRARY_PATH environment variable. */ + finder.add_envsearchpath ("LD_LIBRARY_PATH"); + + /* Finally we better have some fallback. */ + finder.add_searchdir ("/usr/lib", -1); + } + + if (finder.check_path_access (real_filename)) return true; /* If nothing worked, create a relative path from the original incoming @@ -113,6 +103,7 @@ dlopen (const char *name, int flags) { void *ret = NULL; + debug_printf ("flags %d for %s", flags, name); if (name == NULL) { ret = (void *) GetModuleHandle (NULL); /* handle for the current module */ diff --git a/winsup/cygwin/pathfinder.h b/winsup/cygwin/pathfinder.h new file mode 100644 index 0000000..6845903 --- /dev/null +++ b/winsup/cygwin/pathfinder.h @@ -0,0 +1,116 @@ +/* pathfinder.h: find one of multiple file names in path + + Copyright 2016 Red Hat, Inc. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include "samlist.h" +#include "vstring.h" + +#ifdef __cplusplus + +namespace cygwin { + +class pathfinder +{ +public: + typedef cygwin::samlist basenamelist; + +private: + pathfinder (); + pathfinder (pathfinder const &); + pathfinder & operator = (pathfinder const &); + + basenamelist basenames_; + size_t basenames_maxlen_; + + typedef cygwin::samlist searchbufferlist; + searchbufferlist searchbuffers_; + +public: + ~pathfinder () {} + + /* We need the basenames to search for first, to allow for optimized + memory allocation of each searchpath + basename combination. */ + pathfinder (cygwin::samlist & basenames) + : basenames_ () + , basenames_maxlen_ () + , searchbuffers_() + { + basenames.swap(basenames_); + + for (basenamelist::iterator basename = basenames_.begin (); + basename != basenames_.end (); + ++ basename) + { + if (basenames_maxlen_ < basename->stringlength ()) + basenames_maxlen_ = basename->stringlength (); + } + } + + void add_searchdir (const char *dir, int dirlen) + { + if (dirlen < 0) + dirlen = strlen (dir); + + if (!dirlen) + return; + + /* Search "x/bin:x/lib" for "x/lib" */ + if (dirlen >=4 && !strncmp (dir + dirlen - 4, "/lib", 4)) + searchbuffers_.append (cygwin::vbuffer::constructor_args (dir, dirlen - 4, "/bin", 4, "/", 1 + basenames_maxlen_, NULL)); +// searchbuffers_.appendv (dir, dirlen - 4, "/bin", 4, "/", 1 + basenames_maxlen_, NULL); + + /* prealloc buffer in searchdir for any basename we will search for */ + searchbuffers_.append (cygwin::vbuffer::constructor_args (dir, dirlen, "/", 1 + basenames_maxlen_, NULL)); + } + + void add_searchpath (const char *path) + { + while (path && *path) + { + const char *next = strchr (path, ':'); + add_searchdir (path, next ? next - path : -1); + path = next ? next + 1 : next; + } + } + + void add_envsearchpath (const char *envpath) + { + add_searchpath (getenv (envpath)); + } + + /* Within each searchdir registered, try each registered basename to + find as executable. Returns found dir/basename in real_filename. + Returns true when found. */ + bool check_path_access (path_conv& real_filename) + { + for (searchbufferlist::iterator dir = searchbuffers_.begin (); + dir != searchbuffers_.end (); + ++dir) + for (cygwin::samlist::iterator name = basenames_.begin (); + name != basenames_.end (); + ++name) + { + /* complete the filename path to search for */ + memcpy (dir->buffer () + dir->stringlength (), name->string (), name->stringlength () + 1); + debug_printf ("trying %s", dir->buffer ()); + real_filename.check (dir->string (), PC_SYM_FOLLOW | PC_POSIX); + if (real_filename.exists () && !real_filename.isdir ()) + { + debug_printf (" found %s", dir->buffer ()); + return true; + } + } + real_filename.error = ENOENT; + return !real_filename.error; + } +}; + +} + +#endif /* __cplusplus */ diff --git a/winsup/cygwin/samlist.h b/winsup/cygwin/samlist.h new file mode 100644 index 0000000..aec30ae --- /dev/null +++ b/winsup/cygwin/samlist.h @@ -0,0 +1,253 @@ +/* samlist.h: cygwin::samlist + + Copyright 2016 Red Hat, Inc. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#ifdef __cplusplus + +namespace cygwin +{ + /* basic member for SinglyAllocatedMembers list */ + class samlist_member + { + samlist_member * prev_; + samlist_member * next_; + + /* no copy */ + samlist_member (samlist_member const &); + samlist_member & operator = (samlist_member const &); + + public: + samlist_member () + : prev_ (this) + , next_ (this) + {} + + class constructor_args + { + friend class samlist_member; + + template + friend class samlist; + + samlist_member * before; + + public: + constructor_args () /* list anchor */ + : before (NULL) + {} + + constructor_args (samlist_member * b) /* list anchor */ + : before (b) + {} + }; + + samlist_member (constructor_args & ca) + { + if (!ca.before) /* default constructor */ + { + /* anchor */ + prev_ = this; + next_ = this; + return; + } + /* instantly insert into list */ + prev_ = ca.before->prev_; + next_ = ca.before; + prev_->next_ = this; + next_->prev_ = this; + } + + ~samlist_member () + { + /* remove from list */ + samlist_member * next = next_; + samlist_member * prev = prev_; + next->prev_ = prev; + prev->next_ = next; + prev_ = NULL; + next_ = NULL; + } + + samlist_member * next () + { + return next_; + } + + samlist_member * prev () + { + return next_; + } + }; + + /* Double-linked list with SinglyAllocatedMember storage, that is, + double-linkage pointers are allocated alongside the member data. */ + template + class samlist + { + public: + struct member_type + : public samlist_member + , public MemberType + { + struct constructor_args + : public samlist_member::constructor_args + , public MemberType::constructor_args + { + constructor_args (samlist_member::constructor_args lca, + typename MemberType::constructor_args mca) + : samlist_member::constructor_args (lca) + , MemberType::constructor_args (mca) + {} + }; + + member_type (constructor_args & ca) + : samlist_member (ca) + , MemberType (ca) + {} + + void * operator new (size_t classSize, constructor_args & ca) + { + return MemberType::operator new (classSize, ca); + } + }; + + class iterator + { + samlist_member * current_; + + iterator (); + + friend class samlist; + iterator (samlist_member * current) + : current_ (current) + {} + + public: + iterator (iterator const & rhs) + : current_ (rhs.current_) + {} + + iterator & operator = (iterator const & rhs) + { + current_ = rhs.current_; + return *this; + } + + iterator & operator ++ () + { + current_ = current_->next (); + return *this; + } + + iterator operator ++ (int) + { + iterator ret (*this); + current_ = current_->next (); + return ret; + } + + iterator & operator -- () + { + current_ = current_->prev (); + return *this; + } + + iterator operator -- (int) + { + iterator ret (*this); + current_ = current_->prev (); + return ret; + } + + bool operator == (iterator const & rhs) const + { + return current_ == rhs.current_; + } + + bool operator != (iterator const & rhs) const + { + return !(*this == rhs); + } + + member_type const & operator * () const { return *ptr (); } + member_type & operator * () { return *ptr (); } + member_type const * operator -> () const { return ptr (); } + member_type * operator -> () { return ptr (); } + + operator member_type const * () const { return ptr (); } + operator member_type * () { return ptr (); } + + member_type const * ptr () const { return static_cast(current_); } + member_type * ptr () { return static_cast(current_); } + + void remove () + { + member_type * old = ptr (); + ++ *this; + delete old; + } + }; + + private: + samlist_member * anchor_; + + /* no copy */ + samlist (samlist const &); + samlist & operator = (samlist const &); + + public: + iterator begin () { return iterator (anchor_->next ()); } + iterator end () { return iterator (anchor_ ); } + iterator rbegin () { return iterator (anchor_->prev ()); } + iterator rend () { return iterator (anchor_ ); } + + samlist () + : anchor_ (new samlist_member ()) + {} + + ~samlist () + { + for (iterator it = begin (); it != end (); it.remove ()); + delete anchor_; + } + + void swap (samlist & that) + { + samlist_member * old = anchor_; + anchor_ = that.anchor_; + that.anchor_ = old; + } + + member_type * append (typename MemberType::constructor_args ca) + { + typename member_type::constructor_args mca (samlist_member::constructor_args (anchor_), ca); + return new (mca) member_type (mca); + } + + template + member_type * appendv (FirstType & firstArg, va_list const & moreArgs) + { + typename member_type::constructor_args ca (firstArg, moreArgs); + return append (ca); + } + + template + member_type * appendv(FirstType & firstArg, ...) + { + va_list moreArgs; + va_start (moreArgs, firstArg); + member_type * ret = appendv (firstArg, moreArgs); + va_end (moreArgs); + return ret; + } + }; + +} + +#endif /* __cplusplus */ diff --git a/winsup/cygwin/vstring.h b/winsup/cygwin/vstring.h new file mode 100644 index 0000000..0658699 --- /dev/null +++ b/winsup/cygwin/vstring.h @@ -0,0 +1,503 @@ +/* vstring.h: cygwin::vstring, cygwin::vbuffe + + Copyright 2016 Red Hat, Inc. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include +#include "cygheap_malloc.h" + +#ifdef __cplusplus + +namespace cygwin { + + struct constructible { + struct constructor_args {}; + constructible (constructor_args &) {} + }; + + namespace string { + + template + struct char_traits + { + typedef CharType char_type; + typedef size_t size_type; + + /* see strlen */ + static size_type length (char_type const *); + + /* see stpcpy */ + static char_type * copy (char_type *, char_type const *); + + /* see stpncpy */ + static char_type * copy (char_type *, char_type const *, size_type); + }; + + template<> + struct char_traits + { + typedef char char_type; + typedef size_t size_type; + + static size_type length(char_type const * s) + { + return strlen (s); + } + static char_type * copy(char_type * d, char_type const * s) + { + return stpcpy (d, s); + } + static char_type * copy(char_type * d, char_type const * s, size_type n) + { + return stpncpy (d, s, n); + } + }; + + template<> + struct char_traits + { + typedef wchar_t char_type; + typedef size_t size_type; + + static size_type length(char_type const *s) + { + return wcslen (s); + } + static char_type * copy(char_type *d, char_type const *s) + { + return wcpcpy (d, s); + } + static char_type * copy(char_type *d, char_type const *s, size_type n) + { + return wcpncpy (d, s, n); + } + }; + + namespace storage { + + template + class varying_length /* must be last data member wherever used */ + { + protected: + typedef CharTraits char_traits; + typedef AllocatorType allocator_type; + typedef typename CharTraits::char_type char_type; + typedef typename CharTraits::size_type size_type; + + private: + union { + struct { + size_type bufferlength_; /* initialized by operator new */ + size_type stringlength_; /* abused to check for operator new */ + /* must be last data member even in derived class */ + char_type buffer_[1]; /* we always have space for trailing zero */ + }; + double alignment_; + }; + + /* variable length disallows placement new */ + void * operator new (size_t classSize, void * p); + + protected: + varying_length () + : stringlength_ () + , buffer_ () + {} + + struct constructor_args + { + size_type bufferlength; + + constructor_args () + : bufferlength (0) + {} + + constructor_args (size_type l) + : bufferlength (l) + {} + + void set (size_type l) + { + bufferlength = l; + } + }; + + varying_length (constructor_args & ca) + { + /* check if our operator new was used as expected */ + assert (bufferlength_ == ca.bufferlength); + assert (stringlength_ == (size_type) this); + stringlength_ = (size_type) 0; + buffer_[0] = (char_type) 0; + } + + size_type bufferlength () const { return bufferlength_; } + size_type stringlength () const { return stringlength_; } + char_type const * buffer () const { return buffer_; } + char_type * buffer () { return buffer_; } + + void stringlength (size_type stringLength) + { + assert (stringLength <= bufferlength_); + stringlength_ = stringLength; + } + + void * operator new (size_t classSize, constructor_args & ca) + { + void *ret = allocator_type::alloc (classSize + ca.bufferlength); + /* we are last data member, aligned to the end of real struct: + find self to initialize bufferlength_ */ + union { void *v; char *b; varying_length *p; } self; + self.v = ret; + self.b += classSize - sizeof (varying_length); + /* tell constructor about our allocation */ + self.p->bufferlength_ = ca.bufferlength; + self.p->stringlength_ = (size_type) self.p; + return ret; + } + + void operator delete (void * p) + { + allocator_type::free (p); + } + }; + + } + + namespace access { + + template + class readonly + : protected AllocatorType /* hide AllocatorType::buffer () */ + { + public: + typedef AllocatorType storage_type; + using typename storage_type::char_type; + using typename storage_type::size_type; + + using typename AllocatorType::constructor_args; + + readonly (constructor_args & c) + : AllocatorType (c) + {} + + char_type const * string () const { return AllocatorType::buffer (); } + size_type stringlength () const { return AllocatorType::stringlength (); } + }; + + template + class writeable + : public readonly + { + public: + using typename readonly::storage_type; + using typename readonly::char_type; + using typename readonly::size_type; + + using typename readonly::constructor_args; + + writeable (constructor_args & c) + : readonly (c) + {} + + char_type * buffer () { return storage_type::buffer (); } + size_type bufferlength () { return storage_type::bufferlength (); } + }; + + } + + /* Extend some ConstructibleBaseType by one string with length unknown before + construction. + The ConstructibleBaseType is required to provide the contructor_args type + to support polymorphic constructor arguments; + Provides + The new operator needs to get the (varying) constructor + arguments for determining required memory size, while the constructor + itself assumes enough memory being allocated to copy the varying + string arguments. */ + template + class varying_extension + : public ConstructibleBaseType + , public AccessType /* must be last data member */ + { + public: + using typename AccessType::storage_type; + + using typename AccessType::char_traits; + using typename AccessType::char_type; + using typename AccessType::size_type; + + struct constructor_args + : public ConstructibleBaseType::constructor_args + , public AccessType::constructor_args + { + char_type const * part0; + va_list parts; + + constructor_args () + : ConstructibleBaseType::constructor_args () + , AccessType::constructor_args () + , part0 (NULL) + , parts () + {} + + constructor_args (char_type const * p0, va_list const & pn) + : ConstructibleBaseType::constructor_args () + , AccessType::constructor_args () + , part0 (p0) + , parts () + { + if (part0) + va_copy (parts, pn); + } + + constructor_args (char_type const * p0, ...) + : ConstructibleBaseType::constructor_args () + , AccessType::constructor_args () + , part0 (p0) + , parts () + { + if (part0) + va_start (parts, p0); + } + + void set (char_type const * p0, va_list const & pn) + { + if (part0) + va_end (parts); + part0 = p0; + if (part0) + va_copy (parts, pn); + } + + void set (char_type const * p0, ...) + { + if (part0) + va_end (parts); + part0 = p0; + if (part0) + va_start (parts, p0); + } + + ~constructor_args () + { + if (part0) + va_end (parts); + } + }; + + + void operator delete (void * p) + { + AccessType::operator delete (p); + } + + void * operator new (size_t classSize) + { + constructor_args ca; + return AccessType::operator new (classSize, ca); + } + + void * operator new (size_t classSize, constructor_args & ca) + { + char_type const * part0 = ca.part0; + va_list parts; + va_copy (parts, ca.parts); + ca.bufferlength = 0; + while (part0) + { + int part0len = va_arg (parts, int); + if (part0len < 0) + part0len = char_traits::length (part0); + ca.bufferlength += part0len; + part0 = va_arg (parts, const char_type *); + } + va_end (parts); + + /* allocate member- and string-buffer at once */ + return AccessType::operator new (classSize, ca); + } + + varying_extension (constructor_args & ca) + : ConstructibleBaseType (ca) + , AccessType (ca) + { + char_type * dest = storage_type::buffer (); + size_type bufferLength = 0; + char_type const * part0 = ca.part0; + va_list parts; + va_copy (parts, ca.parts); + while (part0) + { + int part0len = va_arg (parts, int); + if (part0len < 0) + { + char_type * old = dest; + dest = char_traits::copy (old, part0); + part0len = dest - old; + } + else + dest = char_traits::copy (dest, part0, part0len); + bufferLength += part0len; + part0 = va_arg (parts, const char_type *); + } + va_end (parts); + *dest = (char_type)0; + storage_type::stringlength (dest - storage_type::buffer ()); + assert (bufferLength == storage_type::bufferlength ()); + } + + template + static FinalType * create (typename FinalType::constructor_args & ca) + { + return new (ca) FinalType (ca); + } + + template + static FinalType * create (typename FinalType::constructor_args & c, const char_type * part0, va_list const & parts) + { + c.set (part0, parts); + return create (c); + } + + template + static FinalType * create (typename FinalType::constructor_args & c, const char_type * part0, ...) + { + va_list parts; + va_start (parts, part0); + c.set (part0, parts); + va_end (parts); + return create (c); + } + + template + static FinalType * create (const char_type * part0, va_list const & parts) + { + typename FinalType::constructor_args c; + c.set (part0, parts); + return create (c); + } + + template + static FinalType * create (const char_type * part0, ...) + { + typename FinalType::constructor_args c; + va_list parts; + va_start (parts, part0); + c.set (part0, parts); + va_end (parts); + return create (c); + } + }; + } + + template + struct basic_vstring_extension + : public string::varying_extension + < string::access::readonly + < string::storage::varying_length + < string::char_traits + , Allocator + > > + , ConstructibleBaseType + > + { + using typename string::varying_extension + < string::access::readonly + < string::storage::varying_length + < string::char_traits + , Allocator + > > + , ConstructibleBaseType + >::constructor_args; + basic_vstring_extension (constructor_args & ca) + : string::varying_extension + < string::access::readonly + < string::storage::varying_length + < string::char_traits + , Allocator + > > + , ConstructibleBaseType + > (ca) + {} + }; + + template + struct basic_vbuffer_extension + : public string::varying_extension + < string::access::writeable + < string::storage::varying_length + < string::char_traits + , Allocator + > > + , ConstructibleBaseType + > + { + using typename string::varying_extension + < string::access::writeable + < string::storage::varying_length + < string::char_traits + , Allocator + > > + , ConstructibleBaseType + >::constructor_args; + + basic_vbuffer_extension (constructor_args & ca) + : string::varying_extension + < string::access::writeable + < string::storage::varying_length + < string::char_traits + , Allocator + > > + , ConstructibleBaseType + > (ca) + {} + }; + + template + struct vstring_extension + : public basic_vstring_extension + { + using typename basic_vstring_extension::constructor_args; + vstring_extension (constructor_args & ca) + : basic_vstring_extension (ca) + {} + }; + + template + struct wvstring_extension + : public basic_vstring_extension + { + using typename basic_vstring_extension::constructor_args; + }; + + template + struct vbuffer_extension + : public basic_vbuffer_extension + { + using typename basic_vbuffer_extension::constructor_args; + vbuffer_extension (constructor_args & ca) + : basic_vbuffer_extension (ca) + {} + }; + + template + struct wvbuffer_extension + : public basic_vbuffer_extension + { + using typename basic_vbuffer_extension::constructor_args; + }; + + typedef vstring_extension > vstring; + typedef vbuffer_extension > vbuffer; + + typedef wvstring_extension > wvstring; + typedef wvbuffer_extension > wvbuffer; +} + +#endif /* __cplusplus */ -- 2.8.3 --------------040402030003050404030805 Content-Type: text/x-patch; name="0002-dlopen-search-main-executable-s-directory.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="0002-dlopen-search-main-executable-s-directory.patch" Content-length: 1348 >From 6e2739deccb06a4d739d2a41fa32355f21c151a1 Mon Sep 17 00:00:00 2001 From: Michael Haubenwallner Date: Tue, 19 Jul 2016 14:56:48 +0200 Subject: [PATCH 2/3] dlopen: search main executable's directory --- winsup/cygwin/dlfcn.cc | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/winsup/cygwin/dlfcn.cc b/winsup/cygwin/dlfcn.cc index e2093ab..4ea9984 100644 --- a/winsup/cygwin/dlfcn.cc +++ b/winsup/cygwin/dlfcn.cc @@ -80,6 +80,19 @@ get_full_path_of_dll (const char* str, path_conv &real_filename) not use the LD_LIBRARY_PATH environment variable. */ finder.add_envsearchpath ("LD_LIBRARY_PATH"); + /* 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. */ + tmp_pathbuf tp; + PWCHAR exewname = tp.w_get (); + GetModuleFileNameW (NULL, exewname, NT_MAX_PATH); + char * exedir = tp.c_get (); + *exedir = '\0'; + cygwin_conv_path (CCP_WIN_W_TO_POSIX, exewname, exedir, NT_MAX_PATH); + char * lastsep = strrchr (exedir, '/'); + if (lastsep) + finder.add_searchdir (exedir, lastsep - exedir); + /* Finally we better have some fallback. */ finder.add_searchdir ("/usr/lib", -1); } -- 2.8.3 --------------040402030003050404030805 Content-Type: text/x-patch; name="0003-dlopen-search-PATH-environment-variable.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="0003-dlopen-search-PATH-environment-variable.patch" Content-length: 852 >From efe31198bf5747253a9c0d588c354a6b86234525 Mon Sep 17 00:00:00 2001 From: Michael Haubenwallner Date: Tue, 19 Jul 2016 14:57:10 +0200 Subject: [PATCH 3/3] dlopen: search PATH environment variable --- winsup/cygwin/dlfcn.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/winsup/cygwin/dlfcn.cc b/winsup/cygwin/dlfcn.cc index 4ea9984..302869d 100644 --- a/winsup/cygwin/dlfcn.cc +++ b/winsup/cygwin/dlfcn.cc @@ -93,6 +93,9 @@ get_full_path_of_dll (const char* str, path_conv &real_filename) if (lastsep) finder.add_searchdir (exedir, lastsep - exedir); + /* Windows uses the PATH environment variable to search for dlls. */ + finder.add_envsearchpath ("PATH"); + /* Finally we better have some fallback. */ finder.add_searchdir ("/usr/lib", -1); } -- 2.8.3 --------------040402030003050404030805--