3 This software is a copyrighted work licensed under the terms of the
4 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
9 #include "perprocess.h"
11 #include "shared_info.h"
20 #include "child_info.h"
22 #include "exception.h"
24 #include <sys/reent.h>
28 extern void check_sanity_and_sync (per_process
*);
30 #define fabort fork_info->abort
34 WCHAR NO_COPY
dll_list::nt_max_path_buffer
[NT_MAX_PATH
];
36 muto
dll_list::protect
;
38 static bool dll_global_dtors_recorded
;
40 /* We need the in_load_after_fork flag so dll_dllcrt0_1 can decide at fork
41 time if this is a linked DLL or a dynamically loaded DLL. In either case,
42 both, cygwin_finished_initializing and __in_forkee are true, so they are not
43 sufficient to discern the situation. */
44 static bool NO_COPY in_load_after_fork
;
46 /* Into ntbuf with ntbufsize, prints name prefixed with "\\??\\"
47 or "\\??\\UNC" as necessary to form the native NT path name.
48 Returns the end of the resulting string in ntbuf.
49 Supports using (a substring of) ntbuf as name argument. */
50 PWCHAR
dll_list::form_ntname (PWCHAR ntbuf
, size_t ntbufsize
, PCWCHAR name
)
54 /* avoid using path_conv here: cygheap might not be
55 initialized when started from non-cygwin process,
56 or still might be frozen in_forkee */
57 if (name
[0] == L
'\0' || ntbufsize
< 8)
59 if (name
[1] == L
':') /* short Win32 drive letter path name */
61 int winlen
= min (ntbufsize
- 5, wcslen (name
));
62 if (ntbuf
+ 4 != name
)
63 memmove (ntbuf
+ 4, name
, sizeof (*ntbuf
) * winlen
);
64 wcsncpy (ntbuf
, L
"\\??\\", 4);
68 if (!wcsncmp (name
, L
"\\\\?\\", 4)) /* long Win32 path name */
70 int winlen
= min (ntbufsize
- 1, wcslen (name
));
72 memmove (ntbuf
, name
, sizeof (*ntbuf
) * winlen
);
77 if (!wcsncmp (name
, L
"\\\\", 2)) /* short Win32 UNC path name */
79 name
+= 1; /* skip first backslash */
80 int winlen
= min (ntbufsize
- 8, wcslen (name
));
81 if (ntbuf
+ 7 != name
)
82 memmove (ntbuf
+ 7, name
, sizeof (*ntbuf
) * winlen
);
83 wcsncpy (ntbuf
, L
"\\??\\UNC", 7);
87 if (!wcsncmp (name
, L
"\\??\\", 4)) /* already a long NT path name */
89 int winlen
= min (ntbufsize
- 1, wcslen (name
));
91 memmove (ntbuf
, name
, sizeof (*ntbuf
) * winlen
);
95 system_printf ("WARNING: invalid path name '%W'", name
);
103 /* Into shortbuf with shortbufsize, prints name with "\\??\\"
104 or "\\??\\UNC" prefix removed/modified as necessary to form
105 the short Win32 path name.
106 Returns the end of the resulting string in shortbuf.
107 Supports using (a substring of) shortbuf as name argument. */
109 dll_list::form_shortname (PWCHAR shortbuf
, size_t shortbufsize
, PCWCHAR name
)
113 /* avoid using path_conv here: cygheap might not be
114 initialized when started from non-cygwin process,
115 or still might be frozen in_forkee */
116 if (name
[0] == L
'\0' || shortbufsize
< 2)
118 if (name
[0] == L
'\\' &&
119 (name
[1] == L
'\\' || name
[1] == L
'?') &&
121 name
[3] == L
'\\') /* long Win32 or NT path name */
123 if (name
[1] == L
':') /* short Win32 drive letter path name */
125 int ntlen
= min (shortbufsize
- 1, wcslen (name
));
126 if (shortbuf
!= name
)
127 memmove (shortbuf
, name
, sizeof (*shortbuf
) * ntlen
);
131 if (!wcsncmp (name
, L
"UNC\\", 4)) /* UNC path name */
133 name
+= 3; /* skip "UNC" */
134 int winlen
= min (shortbufsize
- 2, wcslen (name
));
135 if (shortbuf
+ 1 != name
)
136 memmove (shortbuf
+ 1, name
, sizeof (*shortbuf
) * winlen
);
138 shortbuf
+= 1 + winlen
;
141 if (!wcsncmp (name
, L
"\\\\", 2)) /* already a short Win32 UNC path name */
143 int winlen
= min (shortbufsize
- 1, wcslen (name
));
144 if (shortbuf
!= name
)
145 memmove (shortbuf
, name
, sizeof (*shortbuf
) * winlen
);
149 system_printf ("WARNING: invalid path name '%W'", name
);
157 /* Run destructors for all DLLs on exit. */
161 /* Don't attempt to call destructors if we're still in fork processing
162 since that likely means fork is failing and everything will not have been
164 if (__in_forkee
== FORKING
)
166 int recorded
= dll_global_dtors_recorded
;
167 dll_global_dtors_recorded
= false;
168 if (recorded
&& dlls
.start
.next
)
169 for (dll
*d
= dlls
.end
; d
!= &dlls
.start
; d
= d
->prev
)
173 /* Run all constructors associated with a dll */
175 per_module::run_ctors ()
177 void (**pfunc
)() = ctors
;
179 /* Run ctors backwards, so skip the first entry and find how many
180 there are, then run them. */
185 for (i
= 1; pfunc
[i
]; i
++);
187 for (int j
= i
- 1; j
> 0; j
--)
192 /* Run all destructors associated with a dll */
194 per_module::run_dtors ()
196 void (**pfunc
)() = dtors
;
201 /* Initialize an individual DLL */
207 /* Don't run constructors or the "main" if we've forked. */
208 if (__in_forkee
!= FORKING
)
210 /* global contructors */
213 /* entry point of dll (use main of per_process with null args...) */
215 ret
= p
.main (0, 0, 0);
221 /* Look for a dll based on the full path.
223 CV, 2012-03-04: Per MSDN, If a DLL with the same module name is already
224 loaded in memory, the system uses the loaded DLL, no matter which directory
225 it is in. The system does not search for the DLL. See
226 http://msdn.microsoft.com/en-us/library/ms682586%28v=vs.85%29.aspx
228 On 2012-02-08 I interpreted "module name" as "basename". So the assumption
229 was that the Windows Loader does not load another DLL with the same basename,
230 if one such DLL is already loaded. Consequentially I changed the code so
231 that DLLs are only compared by basename.
233 This assumption was obviously wrong, as the perl dynaloader proves. It
234 loads multiple DLLs with the same basename into memory, just from different
235 locations. This mechanism is broken when only comparing basenames in the
238 However, the original problem reported on 2012-02-07 was a result of
239 a subtil difference between the paths returned by different calls to
240 GetModuleFileNameW: Sometimes the path is a plain DOS path, sometimes
241 it's preceeded by the long pathname prefix "\\?\".
243 So I reverted the original change from 2012-02-08 and only applied the
244 following fix: Check if the path is preceeded by a long pathname prefix,
245 and, if so, drop it forthwith so that subsequent full path comparisons
248 At least that was the original idea. In fact there are two case, linked
249 and runtime loaded DLLs, which have to be distinguished:
251 - Linked DLLs are loaded by only specifying the basename of the DLL and
252 searching it using the system DLL search order as given in the
253 aforementioned MSDN URL.
255 - Runtime loaded DLLs are specified with the full path since that's how
258 In effect, we have to be careful not to mix linked and loaded DLLs.
259 For more info how this gets accomplished, see the comments at the start
260 of dll_list::alloc, as well as the comment preceeding the definition of
261 the in_load_after_fork bool later in the file. */
263 dll_list::operator[] (PCWCHAR ntname
)
266 while ((d
= d
->next
) != NULL
)
267 if (!wcscasecmp (ntname
, d
->ntname
))
273 /* Look for a dll based on the basename. */
275 dll_list::find_by_modname (PCWCHAR modname
)
278 while ((d
= d
->next
) != NULL
)
279 if (!wcscasecmp (modname
, d
->modname
))
285 /* Look for a dll based on the ntname used
286 to dynamically reload in forked child. */
288 dll_list::find_by_forkedntname (PCWCHAR ntname
)
291 while ((d
= d
->next
) != NULL
)
292 if (!wcscasecmp (ntname
, d
->forkedntname ()))
300 /* Allocate space for a dll struct. */
302 dll_list::alloc (HINSTANCE h
, per_process
*p
, dll_type type
)
304 /* Called under loader lock conditions so this function can't be called
305 multiple times in parallel. The static buffer is safe. */
306 PWCHAR ntname
= nt_max_path_buf ();
307 GetModuleFileNameW (h
, ntname
, NT_MAX_PATH
);
308 PWCHAR modname
= form_ntname (ntname
, NT_MAX_PATH
, ntname
);
309 DWORD ntnamelen
= modname
- ntname
;
310 while (modname
> ntname
&& *(modname
- 1) != L
'\\')
314 /* Already loaded? For linked DLLs, only compare the basenames. Linked
315 DLLs are loaded using just the basename and the default DLL search path.
316 The Windows loader picks up the first one it finds.
317 This also applies to cygwin1.dll and the main-executable (DLL_SELF).
318 When in_load_after_fork, dynamically loaded dll's are reloaded
319 using their parent's forkable_ntname, if available. */
320 dll
*d
= (type
!= DLL_LOAD
) ? dlls
.find_by_modname (modname
) :
321 in_load_after_fork
? dlls
.find_by_forkedntname (ntname
) : dlls
[ntname
];
324 /* We only get here in the forkee. */
326 fabort ("%W: Loaded to different address: parent(%p) != child(%p)",
327 ntname
, d
->handle
, h
);
328 /* If this DLL has been linked against, and the full path differs, try
329 to sanity check if this is the same DLL, just in another path. */
330 else if (type
== DLL_LINK
&& wcscasecmp (ntname
, d
->ntname
)
331 && (d
->p
.data_start
!= p
->data_start
332 || d
->p
.data_start
!= p
->data_start
333 || d
->p
.bss_start
!= p
->bss_start
334 || d
->p
.bss_end
!= p
->bss_end
335 || d
->p
.ctors
!= p
->ctors
336 || d
->p
.dtors
!= p
->dtors
))
337 fabort ("\nLoaded different DLL with same basename in forked child,\n"
338 "parent loaded: %W\n"
339 " child loaded: %W\n"
340 "The DLLs differ, so it's not safe to run the forked child.\n"
341 "Make sure to remove the offending DLL before trying again.",
347 size_t forkntsize
= forkable_ntnamesize (type
, ntname
, modname
);
349 /* FIXME: Change this to new at some point. */
350 d
= (dll
*) cmalloc (HEAP_2_DLL
, sizeof (*d
)
351 + ((ntnamelen
+ forkntsize
) * sizeof (*ntname
)));
353 /* Now we've allocated a block of information. Fill it in with the
354 supplied info about this DLL. */
355 wcscpy (d
->ntname
, ntname
);
356 d
->modname
= d
->ntname
+ (modname
- ntname
);
358 d
->count
= 0; /* Reference counting performed in dlopen/dlclose. */
359 /* DLL_SELF dtors (main-executable, cygwin1.dll) are run elsewhere */
360 d
->has_dtors
= type
!= DLL_SELF
;
364 d
->image_size
= ((pefile
*)h
)->optional_hdr ()->SizeOfImage
;
365 d
->preferred_base
= (void*) ((pefile
*)h
)->optional_hdr()->ImageBase
;
367 d
->fii
.IndexNumber
.QuadPart
= -1LL;
369 d
->forkable_ntname
= NULL
;
372 d
->forkable_ntname
= d
->ntname
+ ntnamelen
+ 1;
373 *d
->forkable_ntname
= L
'\0';
375 if (forkables_supported ())
376 d
->stat_real_file_once ();
378 if (type
== DLL_LOAD
)
386 dll_list::append (dll
* d
)
389 end
= &start
; /* Point to "end" of dll chain. */
390 end
->next
= d
; /* Standard linked list stuff. */
396 void dll_list::populate_deps (dll
* d
)
400 PWCHAR wmodname
= tp
.w_get ();
401 pefile
* pef
= (pefile
*) d
->handle
;
402 PIMAGE_DATA_DIRECTORY dd
= pef
->idata_dir (IMAGE_DIRECTORY_ENTRY_IMPORT
);
403 /* Annoyance: calling crealloc with a NULL pointer will use the
404 wrong heap and crash, so we have to replicate some code */
409 d
->deps
= (dll
**) cmalloc (HEAP_2_DLL
, maxdeps
*sizeof (dll
*));
415 for (PIMAGE_IMPORT_DESCRIPTOR id
=
416 (PIMAGE_IMPORT_DESCRIPTOR
) pef
->rva (dd
->VirtualAddress
);
417 dd
->Size
&& id
->Name
;
420 char* modname
= pef
->rva (id
->Name
);
421 sys_mbstowcs (wmodname
, NT_MAX_PATH
, modname
);
422 if (dll
* dep
= find_by_modname (wmodname
))
424 if (d
->ndeps
>= maxdeps
)
426 maxdeps
= 2*(1+maxdeps
);
427 d
->deps
= (dll
**) crealloc (d
->deps
, maxdeps
*sizeof (dll
*));
429 d
->deps
[d
->ndeps
++] = dep
;
433 /* add one to differentiate no deps from unknown */
441 /* Anything to do? */
442 if (!end
|| end
== &start
)
445 /* make sure we have all the deps available */
447 dll
** dlopen_deps
= NULL
;
449 long dlopen_ndeps
= 0;
452 dlopen_deps
= (dll
**) cmalloc (HEAP_2_DLL
, maxdeps
*sizeof (dll
*));
454 while ((d
= d
->next
))
458 /* Ensure that all dlopen'd DLLs depend on previously dlopen'd DLLs.
459 This prevents topsort from reversing the order of dlopen'd DLLs on
461 if (d
->type
== DLL_LOAD
)
463 /* Initialise d->deps with all previously dlopen'd DLLs. */
466 d
->ndeps
= dlopen_ndeps
;
467 d
->deps
= (dll
**) cmalloc (HEAP_2_DLL
,
468 dlopen_ndeps
*sizeof (dll
*));
469 memcpy (d
->deps
, dlopen_deps
, dlopen_ndeps
*sizeof (dll
*));
471 /* Add this DLL to the list of previously dlopen'd DLLs. */
472 if (dlopen_ndeps
>= maxdeps
)
474 maxdeps
= 2*(1+maxdeps
);
475 dlopen_deps
= (dll
**) crealloc (dlopen_deps
,
476 maxdeps
*sizeof (dll
*));
478 dlopen_deps
[dlopen_ndeps
++] = d
;
487 /* unlink head and tail pointers so the sort can rebuild the list */
489 start
.next
= end
= NULL
;
490 topsort_visit (d
, true);
492 /* clear node markings made by the sort */
494 while ((d
= d
->next
))
497 paranoid_printf ("%W", d
->modname
);
498 for (int i
= 1; i
< -d
->ndeps
; i
++)
499 paranoid_printf ("-> %W", d
->deps
[i
- 1]->modname
);
502 /* It would be really nice to be able to keep this information
503 around for next time, but we don't have an easy way to
504 invalidate cached dependencies when a module unloads. */
511 /* A recursive in-place topological sort. The result is ordered so that
512 dependencies of a dll appear before it in the list.
514 NOTE: this algorithm is guaranteed to terminate with a "partial
515 order" of dlls but does not do anything smart about cycles: an
516 arbitrary dependent dll will necessarily appear first. Perhaps not
517 surprisingly, Windows ships several dlls containing dependency
518 cycles, including SspiCli/RPCRT4.dll and a lovely tangle involving
519 USP10/LPK/GDI32/USER32.dll). Fortunately, we don't care about
520 Windows DLLs here, and cygwin dlls should behave better */
522 dll_list::topsort_visit (dll
* d
, bool seek_tail
)
524 /* Recurse to the end of the dll chain, then visit nodes as we
525 unwind. We do this because once we start visiting nodes we can no
526 longer trust any _next_ pointers.
528 We "mark" visited nodes (to avoid revisiting them) by negating
529 ndeps (undone once the sort completes). */
530 if (seek_tail
&& d
->next
)
531 topsort_visit (d
->next
, true);
535 d
->ndeps
= -d
->ndeps
;
536 for (long i
= 1; i
< -d
->ndeps
; i
++)
537 topsort_visit (d
->deps
[i
- 1], false);
545 dll_list::find (void *retaddr
)
547 MEMORY_BASIC_INFORMATION m
;
548 if (!VirtualQuery (retaddr
, &m
, sizeof m
))
550 HMODULE h
= (HMODULE
) m
.AllocationBase
;
553 while ((d
= d
->next
))
554 if (d
->type
!= DLL_SELF
&& d
->handle
== h
)
559 /* Detach a DLL from the chain. */
561 dll_list::detach (void *retaddr
)
564 /* Don't attempt to call destructors if we're still in fork processing
565 since that likely means fork is failing and everything will not have been
567 if (!myself
|| __in_forkee
== FORKING
)
570 if ((d
= find (retaddr
)))
572 /* Ensure our exception handler is enabled for destructors */
574 /* Call finalize function if we are not already exiting */
576 __cxa_finalize (d
->handle
);
578 d
->prev
->next
= d
->next
;
580 d
->next
->prev
= d
->prev
;
581 if (d
->type
== DLL_LOAD
)
590 /* Initialization for all linked DLLs, called by dll_crt0_1. */
596 /* Walk the dll chain, initializing each dll */
598 dll_global_dtors_recorded
= d
->next
!= NULL
;
599 while ((d
= d
->next
))
600 if (d
->type
!= DLL_SELF
) /* linked and early loaded dlls */
605 dll_list::track_self ()
607 /* for cygwin1.dll and main-executable: maintain hardlinks only */
608 alloc (cygwin_hmodule
, user_data
, DLL_SELF
);
609 main_executable
= alloc (GetModuleHandle (NULL
), user_data
, DLL_SELF
);
612 #define A64K (64 * 1024)
615 /* Reserve the chunk of free address space starting _here_ and (usually)
616 covering at least _dll_size_ bytes. However, we must take care not
617 to clobber the dll's target address range because it often overlaps.
620 reserve_at (PCWCHAR name
, PVOID here
, PVOID dll_base
, DWORD dll_size
)
623 MEMORY_BASIC_INFORMATION mb
;
625 if (!VirtualQuery (here
, &mb
, sizeof (mb
)))
626 fabort ("couldn't examine memory at %p while mapping %W, %E", here
, name
);
627 if (mb
.State
!= MEM_FREE
)
630 size
= mb
.RegionSize
;
632 // don't clobber the space where we want the dll to land
633 caddr_t end
= (caddr_t
) here
+ size
;
634 caddr_t dll_end
= (caddr_t
) dll_base
+ dll_size
;
635 if (dll_base
< here
&& dll_end
> (caddr_t
) here
)
636 here
= (PVOID
) dll_end
; // the dll straddles our left edge
637 else if (dll_base
>= here
&& (caddr_t
) dll_base
< end
)
638 end
= (caddr_t
) dll_base
; // the dll overlaps partly or fully to our right
640 size
= end
- (caddr_t
) here
;
641 if (!VirtualAlloc (here
, size
, MEM_RESERVE
, PAGE_NOACCESS
))
642 fabort ("couldn't allocate memory %p(%d) for '%W' alignment, %E\n",
647 /* Release the memory previously allocated by "reserve_at" above. */
649 release_at (PCWCHAR name
, PVOID here
)
651 if (!VirtualFree (here
, 0, MEM_RELEASE
))
652 fabort ("couldn't release memory %p for '%W' alignment, %E\n",
656 /* Step 1: Reserve memory for all DLL_LOAD dlls. This is to prevent
657 anything else from taking their spot as we compensate for Windows
658 randomly relocating things.
660 NOTE: because we can't depend on LoadLibraryExW to do the right
661 thing, we have to do a vanilla VirtualAlloc instead. One possible
662 optimization might attempt a LoadLibraryExW first, in case it lands
663 in the right place, but then we have to find a way of tracking
664 which dlls ended up needing VirtualAlloc after all. */
666 dll_list::reserve_space ()
668 for (dll
* d
= dlls
.istart (DLL_LOAD
); d
; d
= dlls
.inext ())
669 if (!VirtualAlloc (d
->handle
, d
->image_size
, MEM_RESERVE
, PAGE_NOACCESS
))
670 fabort ("address space needed by '%W' (%p) is already occupied",
671 d
->modname
, d
->handle
);
674 /* Reload DLLs after a fork. Iterates over the list of dynamically loaded
675 DLLs and attempts to load them in the same place as they were loaded in the
676 parent. Updates main-executable and cygwin1.dll tracking. */
678 dll_list::load_after_fork (HANDLE parent
)
680 release_forkables ();
682 // moved to frok::child for performance reasons:
683 // dll_list::reserve_space();
685 in_load_after_fork
= true;
687 load_after_fork_impl (parent
, dlls
.istart (DLL_LOAD
), 0);
689 in_load_after_fork
= false;
692 static int const DLL_RETRY_MAX
= 6;
693 void dll_list::load_after_fork_impl (HANDLE parent
, dll
* d
, int retries
)
695 /* Step 2: For each dll which did not map at its preferred base
696 address in the parent, try to coerce it to land at the same spot
697 as before. If not, unload it, reserve the memory around it, and
698 try again. Use recursion to remember blocked regions address
699 space so we can release them later.
701 We DONT_RESOLVE_DLL_REFERENCES at first in case the DLL lands in
704 NOTE: This step skips DLLs which loaded at their preferred address in
705 the parent because they should behave (we already verified that their
706 preferred address in the child is available). However, this may fail
707 with ASLR active, because the ASLR base address will usually not equal
708 the preferred base recorded in the dll. In this case, we should make
709 the LoadLibraryExW call unconditional.
711 for ( ; d
; d
= dlls
.inext ())
712 if (d
->handle
!= d
->preferred_base
)
714 /* See if the DLL will load in proper place. If not, unload it,
715 reserve the memory around it, and try again.
717 If this is the first attempt, we need to release the
718 dll's protective reservation from step 1
720 if (!retries
&& !VirtualFree (d
->handle
, 0, MEM_RELEASE
))
721 fabort ("unable to release protective reservation (%p) for %W, %E",
722 d
->handle
, d
->ntname
);
724 HMODULE h
= LoadLibraryExW (buffered_shortname (d
->forkedntname ()),
725 NULL
, DONT_RESOLVE_DLL_REFERENCES
);
727 fabort ("unable to create interim mapping for %W (using %W), %E",
728 d
->ntname
, buffered_shortname (d
->forkedntname ()));
731 sigproc_printf ("%W (using %W) loaded in wrong place: %p != %p",
732 d
->ntname
, buffered_shortname (d
->forkedntname ()),
735 PVOID reservation
= reserve_at (d
->ntname
, h
,
736 d
->handle
, d
->image_size
);
738 fabort ("unable to block off %p to prevent %W from loading there",
741 if (retries
< DLL_RETRY_MAX
)
742 load_after_fork_impl (parent
, d
, retries
+1);
744 fabort ("unable to remap %W (using %W) to same address as parent (%p) - try running rebaseall",
745 d
->ntname
, buffered_shortname (d
->forkedntname ()), d
->handle
);
747 /* once the above returns all the dlls are mapped; release
748 the reservation and continue unwinding */
749 sigproc_printf ("releasing blocked space at %p", reservation
);
750 release_at (d
->ntname
, reservation
);
755 /* Step 3: try to load each dll for real after either releasing the
756 protective reservation (for well-behaved dlls) or unloading the
757 interim mapping (for rebased dlls) . The dll list is sorted in
758 dependency order, so we shouldn't pull in any additional dlls
759 outside our control. */
760 for (dll
*d
= dlls
.istart (DLL_LOAD
); d
; d
= dlls
.inext ())
762 if (d
->handle
== d
->preferred_base
)
764 if (!VirtualFree (d
->handle
, 0, MEM_RELEASE
))
765 fabort ("unable to release protective reservation for %W (%p), %E",
766 d
->ntname
, d
->handle
);
770 /* Free the library using our parent's handle: it's identical
771 to ours or we wouldn't have gotten this far */
772 if (!FreeLibrary (d
->handle
))
773 fabort ("unable to unload interim mapping of %W (using %W), %E",
774 d
->ntname
, buffered_shortname (d
->forkedntname ()));
776 /* cygwin1.dll - as linked dependency - may reuse the shortname
777 buffer, even in case of failure: don't reuse shortname later */
778 HMODULE h
= LoadLibraryW (buffered_shortname (d
->forkedntname ()));
780 fabort ("unable to map %W (using %W), %E",
781 d
->ntname
, buffered_shortname (d
->forkedntname ()));
783 fabort ("unable to map %W (using %W) to same address as parent: %p != %p",
784 d
->ntname
, buffered_shortname (d
->forkedntname ()), d
->handle
, h
);
785 /* Fix OS reference count. */
786 for (int cnt
= 1; cnt
< d
->count
; ++cnt
)
787 LoadLibraryW (buffered_shortname (d
->forkedntname ()));
796 dllcrt0_info (HMODULE h0
, per_process
*p0
): h (h0
), p (p0
) {}
800 dll_dllcrt0 (HMODULE h
, per_process
*p
)
802 if (dynamically_loaded
)
804 dllcrt0_info
x (h
, p
);
810 dll_dllcrt0_1 (VOID
*x
)
812 HMODULE
& h
= ((dllcrt0_info
*) x
)->h
;
813 per_process
*& p
= ((dllcrt0_info
*) x
)->p
;
814 PVOID
& res
= ((dllcrt0_info
*) x
)->res
;
817 p
= &__cygwin_user_data
;
820 *(p
->impure_ptr_ptr
) = __cygwin_user_data
.impure_ptr
;
821 _pei386_runtime_relocator (p
);
824 bool linked
= !cygwin_finished_initializing
&& !in_load_after_fork
;
826 /* Broken DLLs built against Cygwin versions 1.7.0-49 up to 1.7.0-57
827 override the cxx_malloc pointer in their DLL initialization code,
828 when loaded either statically or dynamically. Because this leaves
829 a stale pointer into demapped memory space if the DLL is unloaded
830 by a call to dlclose, we prevent this happening for dynamically
831 loaded DLLs in dlopen by saving and restoring cxx_malloc around
832 the call to LoadLibrary, which invokes the DLL's startup sequence.
833 Modern DLLs won't even attempt to override the pointer when loaded
834 statically, but will write their overrides directly into the
835 struct it points to. With all modern DLLs, this will remain the
836 default_cygwin_cxx_malloc struct in cxx.cc, but if any broken DLLs
837 are in the mix they will have overridden the pointer and subsequent
838 overrides will go into their embedded cxx_malloc structs. This is
839 almost certainly not a problem as they can never be unloaded, but
840 if we ever did want to do anything about it, we could check here to
841 see if the pointer had been altered in the early parts of the DLL's
842 startup, and if so copy back the new overrides and reset it here.
843 However, that's just a note for the record; at the moment, we can't
844 see any need to worry about this happening. */
846 check_sanity_and_sync (p
);
850 /* If this function is called before cygwin has finished
851 initializing, then the DLL must be a cygwin-aware DLL
852 that was explicitly linked into the program rather than
859 dlls
.reload_on_fork
= 1;
862 /* Allocate and initialize space for the DLL. */
863 dll
*d
= dlls
.alloc (h
, p
, type
);
865 /* If d == NULL, then something is broken.
866 Otherwise, if we've finished initializing, it's ok to
867 initialize the DLL. If we haven't finished initializing,
868 it may not be safe to call the dll's "main" since not
869 all of cygwin's internal structures may have been set up. */
870 if (!d
|| (!linked
&& !d
->init ()))
877 cygwin_detach_dll (dll
*)
880 if (_my_tls
.isinitialized ())
881 retaddr
= (void *) _my_tls
.retaddr ();
883 retaddr
= __builtin_return_address (0);
884 dlls
.detach (retaddr
);
890 dlls
.reload_on_fork
= val
;