• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include <malloc.h>   /* for alloca() */
2 
3 
4 /************************************************************/
5 /* errno and GetLastError support */
6 
7 #include "misc_thread_common.h"
8 
9 static DWORD cffi_tls_index = TLS_OUT_OF_INDEXES;
10 
DllMain(HINSTANCE hinstDLL,DWORD reason_for_call,LPVOID reserved)11 BOOL WINAPI DllMain(HINSTANCE hinstDLL,
12                     DWORD     reason_for_call,
13                     LPVOID    reserved)
14 {
15     LPVOID p;
16 
17     switch (reason_for_call) {
18 
19     case DLL_THREAD_DETACH:
20         if (cffi_tls_index != TLS_OUT_OF_INDEXES) {
21             p = TlsGetValue(cffi_tls_index);
22             if (p != NULL) {
23                 TlsSetValue(cffi_tls_index, NULL);
24                 cffi_thread_shutdown(p);
25             }
26         }
27         break;
28 
29     default:
30         break;
31     }
32     return TRUE;
33 }
34 
init_cffi_tls(void)35 static void init_cffi_tls(void)
36 {
37     if (cffi_tls_index == TLS_OUT_OF_INDEXES) {
38         cffi_tls_index = TlsAlloc();
39         if (cffi_tls_index == TLS_OUT_OF_INDEXES)
40             PyErr_SetString(PyExc_WindowsError, "TlsAlloc() failed");
41     }
42 }
43 
get_cffi_tls(void)44 static struct cffi_tls_s *get_cffi_tls(void)
45 {
46     LPVOID p = TlsGetValue(cffi_tls_index);
47 
48     if (p == NULL) {
49         p = malloc(sizeof(struct cffi_tls_s));
50         if (p == NULL)
51             return NULL;
52         memset(p, 0, sizeof(struct cffi_tls_s));
53         TlsSetValue(cffi_tls_index, p);
54     }
55     return (struct cffi_tls_s *)p;
56 }
57 
58 #ifdef USE__THREAD
59 # error "unexpected USE__THREAD on Windows"
60 #endif
61 
save_errno(void)62 static void save_errno(void)
63 {
64     int current_err = errno;
65     int current_lasterr = GetLastError();
66     struct cffi_tls_s *p = get_cffi_tls();
67     if (p != NULL) {
68         p->saved_errno = current_err;
69         p->saved_lasterror = current_lasterr;
70     }
71     /* else: cannot report the error */
72 }
73 
restore_errno(void)74 static void restore_errno(void)
75 {
76     struct cffi_tls_s *p = get_cffi_tls();
77     if (p != NULL) {
78         SetLastError(p->saved_lasterror);
79         errno = p->saved_errno;
80     }
81     /* else: cannot report the error */
82 }
83 
84 /************************************************************/
85 
86 
87 #if PY_MAJOR_VERSION >= 3
b_getwinerror(PyObject * self,PyObject * args,PyObject * kwds)88 static PyObject *b_getwinerror(PyObject *self, PyObject *args, PyObject *kwds)
89 {
90     int err = -1;
91     int len;
92     WCHAR *s_buf = NULL; /* Free via LocalFree */
93     PyObject *v, *message;
94     static char *keywords[] = {"code", NULL};
95 
96     if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", keywords, &err))
97         return NULL;
98 
99     if (err == -1) {
100         struct cffi_tls_s *p = get_cffi_tls();
101         if (p == NULL)
102             return PyErr_NoMemory();
103         err = p->saved_lasterror;
104     }
105 
106     len = FormatMessageW(
107         /* Error API error */
108         FORMAT_MESSAGE_ALLOCATE_BUFFER |
109         FORMAT_MESSAGE_FROM_SYSTEM |
110         FORMAT_MESSAGE_IGNORE_INSERTS,
111         NULL,           /* no message source */
112         err,
113         MAKELANGID(LANG_NEUTRAL,
114         SUBLANG_DEFAULT), /* Default language */
115         (LPWSTR) &s_buf,
116         0,              /* size not used */
117         NULL);          /* no args */
118     if (len==0) {
119         /* Only seen this in out of mem situations */
120         message = PyUnicode_FromFormat("Windows Error 0x%X", err);
121     } else {
122         /* remove trailing cr/lf and dots */
123         while (len > 0 && (s_buf[len-1] <= L' ' || s_buf[len-1] == L'.'))
124             s_buf[--len] = L'\0';
125         message = PyUnicode_FromWideChar(s_buf, len);
126     }
127     if (message != NULL)
128         v = Py_BuildValue("(iO)", err, message);
129     else
130         v = NULL;
131     LocalFree(s_buf);
132     return v;
133 }
134 #else
b_getwinerror(PyObject * self,PyObject * args,PyObject * kwds)135 static PyObject *b_getwinerror(PyObject *self, PyObject *args, PyObject *kwds)
136 {
137     int err = -1;
138     int len;
139     char *s;
140     char *s_buf = NULL; /* Free via LocalFree */
141     char s_small_buf[40]; /* Room for "Windows Error 0xFFFFFFFFFFFFFFFF" */
142     PyObject *v;
143     static char *keywords[] = {"code", NULL};
144 
145     if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", keywords, &err))
146         return NULL;
147 
148     if (err == -1) {
149         struct cffi_tls_s *p = get_cffi_tls();
150         if (p == NULL)
151             return PyErr_NoMemory();
152         err = p->saved_lasterror;
153     }
154 
155     len = FormatMessage(
156         /* Error API error */
157         FORMAT_MESSAGE_ALLOCATE_BUFFER |
158         FORMAT_MESSAGE_FROM_SYSTEM |
159         FORMAT_MESSAGE_IGNORE_INSERTS,
160         NULL,           /* no message source */
161         err,
162         MAKELANGID(LANG_NEUTRAL,
163         SUBLANG_DEFAULT), /* Default language */
164         (LPTSTR) &s_buf,
165         0,              /* size not used */
166         NULL);          /* no args */
167     if (len==0) {
168         /* Only seen this in out of mem situations */
169         sprintf(s_small_buf, "Windows Error 0x%X", err);
170         s = s_small_buf;
171         s_buf = NULL;
172     } else {
173         s = s_buf;
174         /* remove trailing cr/lf and dots */
175         while (len > 0 && (s[len-1] <= ' ' || s[len-1] == '.'))
176             s[--len] = '\0';
177     }
178     v = Py_BuildValue("(is)", err, s);
179     LocalFree(s_buf);
180     return v;
181 }
182 #endif
183 
184 
185 /************************************************************/
186 /* Emulate dlopen()&co. from the Windows API */
187 
188 #define RTLD_LAZY   0
189 #define RTLD_NOW    0
190 #define RTLD_GLOBAL 0
191 #define RTLD_LOCAL  0
192 
dlopen(const char * filename,int flag)193 static void *dlopen(const char *filename, int flag)
194 {
195     return (void *)LoadLibraryA(filename);
196 }
197 
dlopenW(const wchar_t * filename)198 static void *dlopenW(const wchar_t *filename)
199 {
200     return (void *)LoadLibraryW(filename);
201 }
202 
dlsym(void * handle,const char * symbol)203 static void *dlsym(void *handle, const char *symbol)
204 {
205     void *address = GetProcAddress((HMODULE)handle, symbol);
206 #ifndef MS_WIN64
207     if (!address) {
208         /* If 'symbol' is not found, then try '_symbol@N' for N in
209            (0, 4, 8, 12, ..., 124).  Unlike ctypes, we try to do that
210            for any symbol, although in theory it should only be done
211            for __stdcall functions.
212         */
213         int i;
214         char *mangled_name = alloca(1 + strlen(symbol) + 1 + 3 + 1);
215         if (!mangled_name)
216             return NULL;
217         for (i = 0; i < 32; i++) {
218             sprintf(mangled_name, "_%s@%d", symbol, i * 4);
219             address = GetProcAddress((HMODULE)handle, mangled_name);
220             if (address)
221                 break;
222         }
223     }
224 #endif
225     return address;
226 }
227 
dlclose(void * handle)228 static int dlclose(void *handle)
229 {
230     return FreeLibrary((HMODULE)handle) ? 0 : -1;
231 }
232 
dlerror(void)233 static const char *dlerror(void)
234 {
235     static char buf[32];
236     DWORD dw = GetLastError();
237     if (dw == 0)
238         return NULL;
239     sprintf(buf, "error 0x%x", (unsigned int)dw);
240     return buf;
241 }
242