]> sourceware.org Git - newlib-cygwin.git/blob - winsup/cygwin/cygtls.cc
* Merge in cygwin-64bit-branch.
[newlib-cygwin.git] / winsup / cygwin / cygtls.cc
1 /* cygtls.cc
2
3 Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Red
4 Hat, Inc.
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"
11 #define USE_SYS_TYPES_FD_SET
12 #include "cygtls.h"
13 #include <syslog.h>
14 #include <stdlib.h>
15 #include "path.h"
16 #include "fhandler.h"
17 #include "dtable.h"
18 #include "cygheap.h"
19 #include "sigproc.h"
20 #include "exception.h"
21
22 /* Two calls to get the stack right... */
23 void
24 _cygtls::call (DWORD (*func) (void *, void *), void *arg)
25 {
26 char buf[CYGTLS_PADSIZE];
27 /* Initialize this thread's ability to respond to things like
28 SIGSEGV or SIGFPE. */
29 exception protect;
30 _my_tls.call2 (func, arg, buf);
31 }
32
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 {
47 L"advapi32.dll",
48 L"kernel32.dll",
49 L"mswsock.dll",
50 L"ntdll.dll",
51 L"ole32.dll",
52 L"shlwapi.dll",
53 L"wbemprox.dll",
54 L"ws2_32.dll",
55 };
56
57 void
58 _cygtls::call2 (DWORD (*func) (void *, void *), void *arg, void *buf)
59 {
60 init_thread (buf, func);
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,
64 since pthreads are always calling thread_wrapper in miscfuncs.cc.
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
99 DWORD res = func (arg, buf);
100 remove (INFINITE);
101 /* Don't call ExitThread on the main thread since we may have been
102 dynamically loaded. */
103 if ((void *) func != (void *) dll_crt0_1
104 && (void *) func != (void *) dll_dllcrt0_1)
105 ExitThread (res);
106 }
107
108 void
109 _cygtls::init_thread (void *x, DWORD (*func) (void *, void *))
110 {
111 if (x)
112 {
113 memset (this, 0, sizeof (*this));
114 _REENT_INIT_PTR (&local_clib);
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;
121 local_clib.__sdidinit = _GLOBAL_REENT->__sdidinit ? -1 : 0;
122 local_clib.__cleanup = _GLOBAL_REENT->__cleanup;
123 local_clib.__sglue._niobs = 3;
124 local_clib.__sglue._iobs = &_GLOBAL_REENT->__sf[0];
125 }
126 }
127
128 thread_id = GetCurrentThreadId ();
129 initialized = CYGTLS_INITIALIZED;
130 errno_addr = &(local_clib._errno);
131 locals.cw_timer = NULL;
132
133 if ((void *) func == (void *) cygthread::stub
134 || (void *) func == (void *) cygthread::simplestub)
135 return;
136
137 cygheap->add_tls (this);
138 }
139
140 void
141 _cygtls::fixup_after_fork ()
142 {
143 if (sig)
144 {
145 pop ();
146 sig = 0;
147 }
148 stacklock = spinning = 0;
149 signal_arrived = NULL;
150 locals.select.sockevt = NULL;
151 locals.cw_timer = NULL;
152 wq.thread_ev = NULL;
153 }
154
155 #define free_local(x) \
156 if (locals.x) \
157 { \
158 free (locals.x); \
159 locals.x = NULL; \
160 }
161
162 void
163 _cygtls::remove (DWORD wait)
164 {
165 initialized = 0;
166 if (exit_state >= ES_FINAL)
167 return;
168
169 debug_printf ("wait %u", wait);
170
171 /* FIXME: Need some sort of atthreadexit function to allow things like
172 select to control this themselves. */
173
174 if (signal_arrived)
175 {
176 HANDLE h = signal_arrived;
177 signal_arrived = NULL;
178 CloseHandle (h);
179 }
180
181 /* Close handle and free memory used by select. */
182 if (locals.select.sockevt)
183 {
184 CloseHandle (locals.select.sockevt);
185 locals.select.sockevt = NULL;
186 free_local (select.ser_num);
187 free_local (select.w4);
188 }
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);
194 /* Free temporary TLS path buffers. */
195 locals.pathbufs.destroy ();
196 cygheap->remove_tls (this, wait);
197 remove_wq (wait);
198 }
This page took 0.043841 seconds and 5 git commands to generate.