• 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         Py_DECREF(message);
130     }
131     else
132         v = NULL;
133     LocalFree(s_buf);
134     return v;
135 }
136 #else
b_getwinerror(PyObject * self,PyObject * args,PyObject * kwds)137 static PyObject *b_getwinerror(PyObject *self, PyObject *args, PyObject *kwds)
138 {
139     int err = -1;
140     int len;
141     char *s;
142     char *s_buf = NULL; /* Free via LocalFree */
143     char s_small_buf[40]; /* Room for "Windows Error 0xFFFFFFFFFFFFFFFF" */
144     PyObject *v;
145     static char *keywords[] = {"code", NULL};
146 
147     if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", keywords, &err))
148         return NULL;
149 
150     if (err == -1) {
151         struct cffi_tls_s *p = get_cffi_tls();
152         if (p == NULL)
153             return PyErr_NoMemory();
154         err = p->saved_lasterror;
155     }
156 
157     len = FormatMessage(
158         /* Error API error */
159         FORMAT_MESSAGE_ALLOCATE_BUFFER |
160         FORMAT_MESSAGE_FROM_SYSTEM |
161         FORMAT_MESSAGE_IGNORE_INSERTS,
162         NULL,           /* no message source */
163         err,
164         MAKELANGID(LANG_NEUTRAL,
165         SUBLANG_DEFAULT), /* Default language */
166         (LPTSTR) &s_buf,
167         0,              /* size not used */
168         NULL);          /* no args */
169     if (len==0) {
170         /* Only seen this in out of mem situations */
171         sprintf(s_small_buf, "Windows Error 0x%X", err);
172         s = s_small_buf;
173     } else {
174         s = s_buf;
175         /* remove trailing cr/lf and dots */
176         while (len > 0 && (s[len-1] <= ' ' || s[len-1] == '.'))
177             s[--len] = '\0';
178     }
179     v = Py_BuildValue("(is)", err, s);
180     LocalFree(s_buf);
181     return v;
182 }
183 #endif
184 
185 
186 /************************************************************/
187 /* Emulate dlopen()&co. from the Windows API */
188 
189 #define RTLD_LAZY   0
190 #define RTLD_NOW    0
191 #define RTLD_GLOBAL 0
192 #define RTLD_LOCAL  0
193 
dlopen(const char * filename,int flag)194 static void *dlopen(const char *filename, int flag)
195 {
196     return (void *)LoadLibraryA(filename);
197 }
198 
dlopenW(const wchar_t * filename)199 static void *dlopenW(const wchar_t *filename)
200 {
201     return (void *)LoadLibraryW(filename);
202 }
203 
dlsym(void * handle,const char * symbol)204 static void *dlsym(void *handle, const char *symbol)
205 {
206     void *address = GetProcAddress((HMODULE)handle, symbol);
207 #ifndef MS_WIN64
208     if (!address) {
209         /* If 'symbol' is not found, then try '_symbol@N' for N in
210            (0, 4, 8, 12, ..., 124).  Unlike ctypes, we try to do that
211            for any symbol, although in theory it should only be done
212            for __stdcall functions.
213         */
214         int i;
215         char *mangled_name = alloca(1 + strlen(symbol) + 1 + 3 + 1);
216         if (!mangled_name)
217             return NULL;
218         for (i = 0; i < 32; i++) {
219             sprintf(mangled_name, "_%s@%d", symbol, i * 4);
220             address = GetProcAddress((HMODULE)handle, mangled_name);
221             if (address)
222                 break;
223         }
224     }
225 #endif
226     return address;
227 }
228 
dlclose(void * handle)229 static int dlclose(void *handle)
230 {
231     return FreeLibrary((HMODULE)handle) ? 0 : -1;
232 }
233 
dlerror(void)234 static const char *dlerror(void)
235 {
236     static char buf[32];
237     DWORD dw = GetLastError();
238     if (dw == 0)
239         return NULL;
240     sprintf(buf, "error 0x%x", (unsigned int)dw);
241     return buf;
242 }
243