]>
Commit | Line | Data |
---|---|---|
2d1d1eb1 | 1 | /* cygtls.cc |
281e4194 | 2 | |
bc837d22 CF |
3 | Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Red |
4 | Hat, Inc. | |
281e4194 CF |
5 | |
6 | This software is a copyrighted work licensed under the terms of the | |
7 | Cygwin license. Please consult the file "CYGWIN_LICENSE" for | |
8 | details. */ | |
9 | ||
10 | #include "winsup.h" | |
893ac8e0 | 11 | #define USE_SYS_TYPES_FD_SET |
281e4194 | 12 | #include "cygtls.h" |
281e4194 | 13 | #include <syslog.h> |
2be50cac | 14 | #include <stdlib.h> |
2d1d1eb1 CF |
15 | #include "path.h" |
16 | #include "fhandler.h" | |
17 | #include "dtable.h" | |
18 | #include "cygheap.h" | |
f6936c48 | 19 | #include "sigproc.h" |
98a97ac6 | 20 | #include "exception.h" |
2d1d1eb1 | 21 | |
281e4194 CF |
22 | /* Two calls to get the stack right... */ |
23 | void | |
e431827c | 24 | _cygtls::call (DWORD (*func) (void *, void *), void *arg) |
281e4194 CF |
25 | { |
26 | char buf[CYGTLS_PADSIZE]; | |
98a97ac6 CF |
27 | /* Initialize this thread's ability to respond to things like |
28 | SIGSEGV or SIGFPE. */ | |
29 | exception protect; | |
38229bcd | 30 | _my_tls.call2 (func, arg, buf); |
281e4194 CF |
31 | } |
32 | ||
07a6b9dd CV |
33 | static int |
34 | dll_cmp (const void *a, const void *b) | |
35 | { | |
36 | return wcscasecmp ((const wchar_t *) a, *(const wchar_t **) b); | |
37 | } | |
38 | ||
39 | /* Keep sorted! | |
40 | This is a list of well-known core system DLLs which contain code | |
41 | whiuch is started in its own thread by the system. Kernel32.dll, | |
42 | for instance, contains the thread called on every Ctrl-C keypress | |
43 | in a console window. The DLLs in this list are not recognized as | |
44 | BLODAs. */ | |
45 | const wchar_t *well_known_dlls[] = | |
46 | { | |
5a519b88 | 47 | L"advapi32.dll", |
07a6b9dd CV |
48 | L"kernel32.dll", |
49 | L"mswsock.dll", | |
50 | L"ntdll.dll", | |
4a4f6f94 | 51 | L"ole32.dll", |
d783d46c | 52 | L"shlwapi.dll", |
4a4f6f94 | 53 | L"wbemprox.dll", |
07a6b9dd CV |
54 | L"ws2_32.dll", |
55 | }; | |
56 | ||
281e4194 | 57 | void |
e431827c | 58 | _cygtls::call2 (DWORD (*func) (void *, void *), void *arg, void *buf) |
281e4194 | 59 | { |
38229bcd | 60 | init_thread (buf, func); |
07a6b9dd CV |
61 | |
62 | /* Optional BLODA detection. The idea is that the function address is | |
63 | supposed to be within Cygwin itself. This is also true for pthreads, | |
46f5dd59 | 64 | since pthreads are always calling thread_wrapper in miscfuncs.cc. |
07a6b9dd CV |
65 | Therefore, every function call to a function outside of the Cygwin DLL |
66 | is potentially a thread injected into the Cygwin process by some BLODA. | |
67 | ||
68 | But that's a bit too simple. Assuming the application itself calls | |
69 | CreateThread, then this is a bad idea, but not really invalid. So we | |
70 | shouldn't print a BLODA message if the address is within the loaded | |
71 | image of the application. Also, ntdll.dll starts threads into the | |
72 | application which */ | |
73 | if (detect_bloda) | |
74 | { | |
75 | PIMAGE_DOS_HEADER img_start = (PIMAGE_DOS_HEADER) GetModuleHandle (NULL); | |
76 | PIMAGE_NT_HEADERS32 ntheader = (PIMAGE_NT_HEADERS32) | |
77 | ((PBYTE) img_start + img_start->e_lfanew); | |
78 | void *img_end = (void *) ((PBYTE) img_start | |
79 | + ntheader->OptionalHeader.SizeOfImage); | |
80 | if (((void *) func < (void *) cygwin_hmodule | |
81 | || (void *) func > (void *) cygheap) | |
82 | && ((void *) func < (void *) img_start || (void *) func >= img_end)) | |
83 | { | |
84 | MEMORY_BASIC_INFORMATION mbi; | |
85 | wchar_t modname[PATH_MAX]; | |
86 | ||
87 | VirtualQuery ((PVOID) func, &mbi, sizeof mbi); | |
88 | GetModuleFileNameW ((HMODULE) mbi.AllocationBase, modname, PATH_MAX); | |
89 | /* Fetch basename and check against list of above system DLLs. */ | |
90 | const wchar_t *modbasename = wcsrchr (modname, L'\\') + 1; | |
91 | if (!bsearch (modbasename, well_known_dlls, | |
92 | sizeof well_known_dlls / sizeof well_known_dlls[0], | |
93 | sizeof well_known_dlls[0], dll_cmp)) | |
94 | small_printf ("\n\nPotential BLODA detected! Thread function " | |
95 | "called outside of Cygwin DLL:\n %W\n\n", modname); | |
96 | } | |
97 | } | |
98 | ||
2d1d1eb1 | 99 | DWORD res = func (arg, buf); |
38229bcd | 100 | remove (INFINITE); |
a2b6c065 CF |
101 | /* Don't call ExitThread on the main thread since we may have been |
102 | dynamically loaded. */ | |
2346864a CF |
103 | if ((void *) func != (void *) dll_crt0_1 |
104 | && (void *) func != (void *) dll_dllcrt0_1) | |
65068ebd | 105 | ExitThread (res); |
281e4194 CF |
106 | } |
107 | ||
108 | void | |
e431827c | 109 | _cygtls::init_thread (void *x, DWORD (*func) (void *, void *)) |
281e4194 CF |
110 | { |
111 | if (x) | |
112 | { | |
562adf78 | 113 | memset (this, 0, sizeof (*this)); |
cd441f06 | 114 | _REENT_INIT_PTR (&local_clib); |
281e4194 CF |
115 | stackptr = stack; |
116 | if (_GLOBAL_REENT) | |
117 | { | |
118 | local_clib._stdin = _GLOBAL_REENT->_stdin; | |
119 | local_clib._stdout = _GLOBAL_REENT->_stdout; | |
120 | local_clib._stderr = _GLOBAL_REENT->_stderr; | |
6f7a746c | 121 | local_clib.__sdidinit = _GLOBAL_REENT->__sdidinit ? -1 : 0; |
281e4194 | 122 | local_clib.__cleanup = _GLOBAL_REENT->__cleanup; |
5e0f482f CF |
123 | local_clib.__sglue._niobs = 3; |
124 | local_clib.__sglue._iobs = &_GLOBAL_REENT->__sf[0]; | |
281e4194 | 125 | } |
281e4194 CF |
126 | } |
127 | ||
985d0e68 | 128 | thread_id = GetCurrentThreadId (); |
09b01096 | 129 | initialized = CYGTLS_INITIALIZED; |
281e4194 | 130 | errno_addr = &(local_clib._errno); |
f0968c1e | 131 | locals.cw_timer = NULL; |
2d1d1eb1 CF |
132 | |
133 | if ((void *) func == (void *) cygthread::stub | |
134 | || (void *) func == (void *) cygthread::simplestub) | |
135 | return; | |
136 | ||
52d2371d | 137 | cygheap->add_tls (this); |
281e4194 CF |
138 | } |
139 | ||
140 | void | |
e431827c CF |
141 | _cygtls::fixup_after_fork () |
142 | { | |
e867f8f1 CF |
143 | if (sig) |
144 | { | |
145 | pop (); | |
146 | sig = 0; | |
147 | } | |
82c925af | 148 | stacklock = spinning = 0; |
962f9a2c | 149 | signal_arrived = NULL; |
023c2582 | 150 | locals.select.sockevt = NULL; |
f0968c1e | 151 | locals.cw_timer = NULL; |
9863b78e | 152 | wq.thread_ev = NULL; |
e431827c CF |
153 | } |
154 | ||
fe836470 CF |
155 | #define free_local(x) \ |
156 | if (locals.x) \ | |
157 | { \ | |
158 | free (locals.x); \ | |
159 | locals.x = NULL; \ | |
160 | } | |
161 | ||
e431827c CF |
162 | void |
163 | _cygtls::remove (DWORD wait) | |
281e4194 | 164 | { |
9badd94a | 165 | initialized = 0; |
023c2582 | 166 | if (exit_state >= ES_FINAL) |
55b67002 | 167 | return; |
4cf4fd4d | 168 | |
61522196 | 169 | debug_printf ("wait %u", wait); |
a0307f99 CV |
170 | |
171 | /* FIXME: Need some sort of atthreadexit function to allow things like | |
172 | select to control this themselves. */ | |
173 | ||
962f9a2c CF |
174 | if (signal_arrived) |
175 | { | |
176 | HANDLE h = signal_arrived; | |
177 | signal_arrived = NULL; | |
178 | CloseHandle (h); | |
179 | } | |
180 | ||
a0307f99 | 181 | /* Close handle and free memory used by select. */ |
1d8170bd | 182 | if (locals.select.sockevt) |
42aa06a5 | 183 | { |
a0307f99 CV |
184 | CloseHandle (locals.select.sockevt); |
185 | locals.select.sockevt = NULL; | |
186 | free_local (select.ser_num); | |
187 | free_local (select.w4); | |
42aa06a5 | 188 | } |
a0307f99 CV |
189 | /* Free memory used by network functions. */ |
190 | free_local (ntoa_buf); | |
191 | free_local (protoent_buf); | |
192 | free_local (servent_buf); | |
193 | free_local (hostent_buf); | |
752b16ce CV |
194 | /* Free temporary TLS path buffers. */ |
195 | locals.pathbufs.destroy (); | |
52d2371d | 196 | cygheap->remove_tls (this, wait); |
168d7785 | 197 | remove_wq (wait); |
281e4194 | 198 | } |