1 | #include "Python.h" |
2 | #include "frameobject.h" |
3 | |
4 | #include <stdbool.h> |
5 | |
6 | #include <ffi.h> |
7 | #ifdef MS_WIN32 |
8 | #include <windows.h> |
9 | #endif |
10 | #include "ctypes.h" |
11 | |
12 | /**************************************************************/ |
13 | |
14 | static void |
15 | CThunkObject_dealloc(PyObject *myself) |
16 | { |
17 | CThunkObject *self = (CThunkObject *)myself; |
18 | PyObject_GC_UnTrack(self); |
19 | Py_XDECREF(self->converters); |
20 | Py_XDECREF(self->callable); |
21 | Py_XDECREF(self->restype); |
22 | if (self->pcl_write) |
23 | Py_ffi_closure_free(self->pcl_write); |
24 | PyObject_GC_Del(self); |
25 | } |
26 | |
27 | static int |
28 | CThunkObject_traverse(PyObject *myself, visitproc visit, void *arg) |
29 | { |
30 | CThunkObject *self = (CThunkObject *)myself; |
31 | Py_VISIT(self->converters); |
32 | Py_VISIT(self->callable); |
33 | Py_VISIT(self->restype); |
34 | return 0; |
35 | } |
36 | |
37 | static int |
38 | CThunkObject_clear(PyObject *myself) |
39 | { |
40 | CThunkObject *self = (CThunkObject *)myself; |
41 | Py_CLEAR(self->converters); |
42 | Py_CLEAR(self->callable); |
43 | Py_CLEAR(self->restype); |
44 | return 0; |
45 | } |
46 | |
47 | PyTypeObject PyCThunk_Type = { |
48 | PyVarObject_HEAD_INIT(NULL, 0) |
49 | "_ctypes.CThunkObject" , |
50 | sizeof(CThunkObject), /* tp_basicsize */ |
51 | sizeof(ffi_type), /* tp_itemsize */ |
52 | CThunkObject_dealloc, /* tp_dealloc */ |
53 | 0, /* tp_vectorcall_offset */ |
54 | 0, /* tp_getattr */ |
55 | 0, /* tp_setattr */ |
56 | 0, /* tp_as_async */ |
57 | 0, /* tp_repr */ |
58 | 0, /* tp_as_number */ |
59 | 0, /* tp_as_sequence */ |
60 | 0, /* tp_as_mapping */ |
61 | 0, /* tp_hash */ |
62 | 0, /* tp_call */ |
63 | 0, /* tp_str */ |
64 | 0, /* tp_getattro */ |
65 | 0, /* tp_setattro */ |
66 | 0, /* tp_as_buffer */ |
67 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ |
68 | PyDoc_STR("CThunkObject" ), /* tp_doc */ |
69 | CThunkObject_traverse, /* tp_traverse */ |
70 | CThunkObject_clear, /* tp_clear */ |
71 | 0, /* tp_richcompare */ |
72 | 0, /* tp_weaklistoffset */ |
73 | 0, /* tp_iter */ |
74 | 0, /* tp_iternext */ |
75 | 0, /* tp_methods */ |
76 | 0, /* tp_members */ |
77 | }; |
78 | |
79 | /**************************************************************/ |
80 | |
81 | static void |
82 | PrintError(const char *msg, ...) |
83 | { |
84 | char buf[512]; |
85 | PyObject *f = PySys_GetObject("stderr" ); |
86 | va_list marker; |
87 | |
88 | va_start(marker, msg); |
89 | PyOS_vsnprintf(buf, sizeof(buf), msg, marker); |
90 | va_end(marker); |
91 | if (f != NULL && f != Py_None) |
92 | PyFile_WriteString(buf, f); |
93 | PyErr_Print(); |
94 | } |
95 | |
96 | |
97 | #ifdef MS_WIN32 |
98 | /* |
99 | * We must call AddRef() on non-NULL COM pointers we receive as arguments |
100 | * to callback functions - these functions are COM method implementations. |
101 | * The Python instances we create have a __del__ method which calls Release(). |
102 | * |
103 | * The presence of a class attribute named '_needs_com_addref_' triggers this |
104 | * behaviour. It would also be possible to call the AddRef() Python method, |
105 | * after checking for PyObject_IsTrue(), but this would probably be somewhat |
106 | * slower. |
107 | */ |
108 | static void |
109 | TryAddRef(StgDictObject *dict, CDataObject *obj) |
110 | { |
111 | IUnknown *punk; |
112 | _Py_IDENTIFIER(_needs_com_addref_); |
113 | |
114 | int r = _PyDict_ContainsId((PyObject *)dict, &PyId__needs_com_addref_); |
115 | if (r <= 0) { |
116 | if (r < 0) { |
117 | PrintError("getting _needs_com_addref_" ); |
118 | } |
119 | return; |
120 | } |
121 | |
122 | punk = *(IUnknown **)obj->b_ptr; |
123 | if (punk) |
124 | punk->lpVtbl->AddRef(punk); |
125 | return; |
126 | } |
127 | #endif |
128 | |
129 | /****************************************************************************** |
130 | * |
131 | * Call the python object with all arguments |
132 | * |
133 | */ |
134 | static void _CallPythonObject(void *mem, |
135 | ffi_type *restype, |
136 | SETFUNC setfunc, |
137 | PyObject *callable, |
138 | PyObject *converters, |
139 | int flags, |
140 | void **pArgs) |
141 | { |
142 | Py_ssize_t i; |
143 | PyObject *result; |
144 | PyObject *arglist = NULL; |
145 | Py_ssize_t nArgs; |
146 | PyObject *error_object = NULL; |
147 | int *space; |
148 | PyGILState_STATE state = PyGILState_Ensure(); |
149 | |
150 | nArgs = PySequence_Length(converters); |
151 | /* Hm. What to return in case of error? |
152 | For COM, 0xFFFFFFFF seems better than 0. |
153 | */ |
154 | if (nArgs < 0) { |
155 | PrintError("BUG: PySequence_Length" ); |
156 | goto Done; |
157 | } |
158 | |
159 | arglist = PyTuple_New(nArgs); |
160 | if (!arglist) { |
161 | PrintError("PyTuple_New()" ); |
162 | goto Done; |
163 | } |
164 | for (i = 0; i < nArgs; ++i) { |
165 | /* Note: new reference! */ |
166 | PyObject *cnv = PySequence_GetItem(converters, i); |
167 | StgDictObject *dict; |
168 | if (cnv) |
169 | dict = PyType_stgdict(cnv); |
170 | else { |
171 | PrintError("Getting argument converter %zd\n" , i); |
172 | goto Done; |
173 | } |
174 | |
175 | if (dict && dict->getfunc && !_ctypes_simple_instance(cnv)) { |
176 | PyObject *v = dict->getfunc(*pArgs, dict->size); |
177 | if (!v) { |
178 | PrintError("create argument %zd:\n" , i); |
179 | Py_DECREF(cnv); |
180 | goto Done; |
181 | } |
182 | PyTuple_SET_ITEM(arglist, i, v); |
183 | /* XXX XXX XX |
184 | We have the problem that c_byte or c_short have dict->size of |
185 | 1 resp. 4, but these parameters are pushed as sizeof(int) bytes. |
186 | BTW, the same problem occurs when they are pushed as parameters |
187 | */ |
188 | } else if (dict) { |
189 | /* Hm, shouldn't we use PyCData_AtAddress() or something like that instead? */ |
190 | CDataObject *obj = (CDataObject *)_PyObject_CallNoArg(cnv); |
191 | if (!obj) { |
192 | PrintError("create argument %zd:\n" , i); |
193 | Py_DECREF(cnv); |
194 | goto Done; |
195 | } |
196 | if (!CDataObject_Check(obj)) { |
197 | Py_DECREF(obj); |
198 | Py_DECREF(cnv); |
199 | PrintError("unexpected result of create argument %zd:\n" , i); |
200 | goto Done; |
201 | } |
202 | memcpy(obj->b_ptr, *pArgs, dict->size); |
203 | PyTuple_SET_ITEM(arglist, i, (PyObject *)obj); |
204 | #ifdef MS_WIN32 |
205 | TryAddRef(dict, obj); |
206 | #endif |
207 | } else { |
208 | PyErr_SetString(PyExc_TypeError, |
209 | "cannot build parameter" ); |
210 | PrintError("Parsing argument %zd\n" , i); |
211 | Py_DECREF(cnv); |
212 | goto Done; |
213 | } |
214 | Py_DECREF(cnv); |
215 | /* XXX error handling! */ |
216 | pArgs++; |
217 | } |
218 | |
219 | if (flags & (FUNCFLAG_USE_ERRNO | FUNCFLAG_USE_LASTERROR)) { |
220 | error_object = _ctypes_get_errobj(&space); |
221 | if (error_object == NULL) |
222 | goto Done; |
223 | if (flags & FUNCFLAG_USE_ERRNO) { |
224 | int temp = space[0]; |
225 | space[0] = errno; |
226 | errno = temp; |
227 | } |
228 | #ifdef MS_WIN32 |
229 | if (flags & FUNCFLAG_USE_LASTERROR) { |
230 | int temp = space[1]; |
231 | space[1] = GetLastError(); |
232 | SetLastError(temp); |
233 | } |
234 | #endif |
235 | } |
236 | |
237 | result = PyObject_CallObject(callable, arglist); |
238 | if (result == NULL) { |
239 | _PyErr_WriteUnraisableMsg("on calling ctypes callback function" , |
240 | callable); |
241 | } |
242 | |
243 | #ifdef MS_WIN32 |
244 | if (flags & FUNCFLAG_USE_LASTERROR) { |
245 | int temp = space[1]; |
246 | space[1] = GetLastError(); |
247 | SetLastError(temp); |
248 | } |
249 | #endif |
250 | if (flags & FUNCFLAG_USE_ERRNO) { |
251 | int temp = space[0]; |
252 | space[0] = errno; |
253 | errno = temp; |
254 | } |
255 | Py_XDECREF(error_object); |
256 | |
257 | if (restype != &ffi_type_void && result) { |
258 | assert(setfunc); |
259 | |
260 | #ifdef WORDS_BIGENDIAN |
261 | /* See the corresponding code in _ctypes_callproc(): |
262 | in callproc.c, around line 1219. */ |
263 | if (restype->type != FFI_TYPE_FLOAT && restype->size < sizeof(ffi_arg)) { |
264 | mem = (char *)mem + sizeof(ffi_arg) - restype->size; |
265 | } |
266 | #endif |
267 | |
268 | /* keep is an object we have to keep alive so that the result |
269 | stays valid. If there is no such object, the setfunc will |
270 | have returned Py_None. |
271 | |
272 | If there is such an object, we have no choice than to keep |
273 | it alive forever - but a refcount and/or memory leak will |
274 | be the result. EXCEPT when restype is py_object - Python |
275 | itself knows how to manage the refcount of these objects. |
276 | */ |
277 | PyObject *keep = setfunc(mem, result, 0); |
278 | |
279 | if (keep == NULL) { |
280 | /* Could not convert callback result. */ |
281 | _PyErr_WriteUnraisableMsg("on converting result " |
282 | "of ctypes callback function" , |
283 | callable); |
284 | } |
285 | else if (keep == Py_None) { |
286 | /* Nothing to keep */ |
287 | Py_DECREF(keep); |
288 | } |
289 | else if (setfunc != _ctypes_get_fielddesc("O" )->setfunc) { |
290 | if (-1 == PyErr_WarnEx(PyExc_RuntimeWarning, |
291 | "memory leak in callback function." , |
292 | 1)) |
293 | { |
294 | _PyErr_WriteUnraisableMsg("on converting result " |
295 | "of ctypes callback function" , |
296 | callable); |
297 | } |
298 | } |
299 | } |
300 | |
301 | Py_XDECREF(result); |
302 | |
303 | Done: |
304 | Py_XDECREF(arglist); |
305 | PyGILState_Release(state); |
306 | } |
307 | |
308 | static void closure_fcn(ffi_cif *cif, |
309 | void *resp, |
310 | void **args, |
311 | void *userdata) |
312 | { |
313 | CThunkObject *p = (CThunkObject *)userdata; |
314 | |
315 | _CallPythonObject(resp, |
316 | p->ffi_restype, |
317 | p->setfunc, |
318 | p->callable, |
319 | p->converters, |
320 | p->flags, |
321 | args); |
322 | } |
323 | |
324 | static CThunkObject* CThunkObject_new(Py_ssize_t nArgs) |
325 | { |
326 | CThunkObject *p; |
327 | Py_ssize_t i; |
328 | |
329 | p = PyObject_GC_NewVar(CThunkObject, &PyCThunk_Type, nArgs); |
330 | if (p == NULL) { |
331 | return NULL; |
332 | } |
333 | |
334 | p->pcl_write = NULL; |
335 | p->pcl_exec = NULL; |
336 | memset(&p->cif, 0, sizeof(p->cif)); |
337 | p->flags = 0; |
338 | p->converters = NULL; |
339 | p->callable = NULL; |
340 | p->restype = NULL; |
341 | p->setfunc = NULL; |
342 | p->ffi_restype = NULL; |
343 | |
344 | for (i = 0; i < nArgs + 1; ++i) |
345 | p->atypes[i] = NULL; |
346 | PyObject_GC_Track((PyObject *)p); |
347 | return p; |
348 | } |
349 | |
350 | CThunkObject *_ctypes_alloc_callback(PyObject *callable, |
351 | PyObject *converters, |
352 | PyObject *restype, |
353 | int flags) |
354 | { |
355 | int result; |
356 | CThunkObject *p; |
357 | Py_ssize_t nArgs, i; |
358 | ffi_abi cc; |
359 | |
360 | nArgs = PySequence_Size(converters); |
361 | p = CThunkObject_new(nArgs); |
362 | if (p == NULL) |
363 | return NULL; |
364 | |
365 | assert(CThunk_CheckExact((PyObject *)p)); |
366 | |
367 | p->pcl_write = Py_ffi_closure_alloc(sizeof(ffi_closure), &p->pcl_exec); |
368 | if (p->pcl_write == NULL) { |
369 | PyErr_NoMemory(); |
370 | goto error; |
371 | } |
372 | |
373 | p->flags = flags; |
374 | for (i = 0; i < nArgs; ++i) { |
375 | PyObject *cnv = PySequence_GetItem(converters, i); |
376 | if (cnv == NULL) |
377 | goto error; |
378 | p->atypes[i] = _ctypes_get_ffi_type(cnv); |
379 | Py_DECREF(cnv); |
380 | } |
381 | p->atypes[i] = NULL; |
382 | |
383 | Py_INCREF(restype); |
384 | p->restype = restype; |
385 | if (restype == Py_None) { |
386 | p->setfunc = NULL; |
387 | p->ffi_restype = &ffi_type_void; |
388 | } else { |
389 | StgDictObject *dict = PyType_stgdict(restype); |
390 | if (dict == NULL || dict->setfunc == NULL) { |
391 | PyErr_SetString(PyExc_TypeError, |
392 | "invalid result type for callback function" ); |
393 | goto error; |
394 | } |
395 | p->setfunc = dict->setfunc; |
396 | p->ffi_restype = &dict->ffi_type_pointer; |
397 | } |
398 | |
399 | cc = FFI_DEFAULT_ABI; |
400 | #if defined(MS_WIN32) && !defined(_WIN32_WCE) && !defined(MS_WIN64) && !defined(_M_ARM) |
401 | if ((flags & FUNCFLAG_CDECL) == 0) |
402 | cc = FFI_STDCALL; |
403 | #endif |
404 | result = ffi_prep_cif(&p->cif, cc, |
405 | Py_SAFE_DOWNCAST(nArgs, Py_ssize_t, int), |
406 | _ctypes_get_ffi_type(restype), |
407 | &p->atypes[0]); |
408 | if (result != FFI_OK) { |
409 | PyErr_Format(PyExc_RuntimeError, |
410 | "ffi_prep_cif failed with %d" , result); |
411 | goto error; |
412 | } |
413 | #if HAVE_FFI_PREP_CLOSURE_LOC |
414 | # if USING_APPLE_OS_LIBFFI |
415 | # define HAVE_FFI_PREP_CLOSURE_LOC_RUNTIME __builtin_available(macos 10.15, ios 13, watchos 6, tvos 13, *) |
416 | # else |
417 | # define HAVE_FFI_PREP_CLOSURE_LOC_RUNTIME 1 |
418 | # endif |
419 | if (HAVE_FFI_PREP_CLOSURE_LOC_RUNTIME) { |
420 | result = ffi_prep_closure_loc(p->pcl_write, &p->cif, closure_fcn, |
421 | p, |
422 | p->pcl_exec); |
423 | } else |
424 | #endif |
425 | { |
426 | #if USING_APPLE_OS_LIBFFI && defined(__arm64__) |
427 | PyErr_Format(PyExc_NotImplementedError, "ffi_prep_closure_loc() is missing" ); |
428 | goto error; |
429 | #else |
430 | #if defined(__clang__) || defined(MACOSX) |
431 | #pragma clang diagnostic push |
432 | #pragma clang diagnostic ignored "-Wdeprecated-declarations" |
433 | #endif |
434 | #if defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))) |
435 | #pragma GCC diagnostic push |
436 | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" |
437 | #endif |
438 | result = ffi_prep_closure(p->pcl_write, &p->cif, closure_fcn, p); |
439 | |
440 | #if defined(__clang__) || defined(MACOSX) |
441 | #pragma clang diagnostic pop |
442 | #endif |
443 | #if defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))) |
444 | #pragma GCC diagnostic pop |
445 | #endif |
446 | |
447 | #endif |
448 | } |
449 | if (result != FFI_OK) { |
450 | PyErr_Format(PyExc_RuntimeError, |
451 | "ffi_prep_closure failed with %d" , result); |
452 | goto error; |
453 | } |
454 | |
455 | Py_INCREF(converters); |
456 | p->converters = converters; |
457 | Py_INCREF(callable); |
458 | p->callable = callable; |
459 | return p; |
460 | |
461 | error: |
462 | Py_XDECREF(p); |
463 | return NULL; |
464 | } |
465 | |
466 | #ifdef MS_WIN32 |
467 | |
468 | static void LoadPython(void) |
469 | { |
470 | if (!Py_IsInitialized()) { |
471 | Py_Initialize(); |
472 | } |
473 | } |
474 | |
475 | /******************************************************************/ |
476 | |
477 | long Call_GetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) |
478 | { |
479 | PyObject *mod, *func, *result; |
480 | long retval; |
481 | static PyObject *context; |
482 | |
483 | if (context == NULL) |
484 | context = PyUnicode_InternFromString("_ctypes.DllGetClassObject" ); |
485 | |
486 | mod = PyImport_ImportModuleNoBlock("ctypes" ); |
487 | if (!mod) { |
488 | PyErr_WriteUnraisable(context ? context : Py_None); |
489 | /* There has been a warning before about this already */ |
490 | return E_FAIL; |
491 | } |
492 | |
493 | func = PyObject_GetAttrString(mod, "DllGetClassObject" ); |
494 | Py_DECREF(mod); |
495 | if (!func) { |
496 | PyErr_WriteUnraisable(context ? context : Py_None); |
497 | return E_FAIL; |
498 | } |
499 | |
500 | { |
501 | PyObject *py_rclsid = PyLong_FromVoidPtr((void *)rclsid); |
502 | PyObject *py_riid = PyLong_FromVoidPtr((void *)riid); |
503 | PyObject *py_ppv = PyLong_FromVoidPtr(ppv); |
504 | if (!py_rclsid || !py_riid || !py_ppv) { |
505 | Py_XDECREF(py_rclsid); |
506 | Py_XDECREF(py_riid); |
507 | Py_XDECREF(py_ppv); |
508 | Py_DECREF(func); |
509 | PyErr_WriteUnraisable(context ? context : Py_None); |
510 | return E_FAIL; |
511 | } |
512 | result = PyObject_CallFunctionObjArgs(func, |
513 | py_rclsid, |
514 | py_riid, |
515 | py_ppv, |
516 | NULL); |
517 | Py_DECREF(py_rclsid); |
518 | Py_DECREF(py_riid); |
519 | Py_DECREF(py_ppv); |
520 | } |
521 | Py_DECREF(func); |
522 | if (!result) { |
523 | PyErr_WriteUnraisable(context ? context : Py_None); |
524 | return E_FAIL; |
525 | } |
526 | |
527 | retval = PyLong_AsLong(result); |
528 | if (PyErr_Occurred()) { |
529 | PyErr_WriteUnraisable(context ? context : Py_None); |
530 | retval = E_FAIL; |
531 | } |
532 | Py_DECREF(result); |
533 | return retval; |
534 | } |
535 | |
536 | STDAPI DllGetClassObject(REFCLSID rclsid, |
537 | REFIID riid, |
538 | LPVOID *ppv) |
539 | { |
540 | long result; |
541 | PyGILState_STATE state; |
542 | |
543 | LoadPython(); |
544 | state = PyGILState_Ensure(); |
545 | result = Call_GetClassObject(rclsid, riid, ppv); |
546 | PyGILState_Release(state); |
547 | return result; |
548 | } |
549 | |
550 | long Call_CanUnloadNow(void) |
551 | { |
552 | PyObject *mod, *func, *result; |
553 | long retval; |
554 | static PyObject *context; |
555 | |
556 | if (context == NULL) |
557 | context = PyUnicode_InternFromString("_ctypes.DllCanUnloadNow" ); |
558 | |
559 | mod = PyImport_ImportModuleNoBlock("ctypes" ); |
560 | if (!mod) { |
561 | /* OutputDebugString("Could not import ctypes"); */ |
562 | /* We assume that this error can only occur when shutting |
563 | down, so we silently ignore it */ |
564 | PyErr_Clear(); |
565 | return E_FAIL; |
566 | } |
567 | /* Other errors cannot be raised, but are printed to stderr */ |
568 | func = PyObject_GetAttrString(mod, "DllCanUnloadNow" ); |
569 | Py_DECREF(mod); |
570 | if (!func) { |
571 | PyErr_WriteUnraisable(context ? context : Py_None); |
572 | return E_FAIL; |
573 | } |
574 | |
575 | result = _PyObject_CallNoArg(func); |
576 | Py_DECREF(func); |
577 | if (!result) { |
578 | PyErr_WriteUnraisable(context ? context : Py_None); |
579 | return E_FAIL; |
580 | } |
581 | |
582 | retval = PyLong_AsLong(result); |
583 | if (PyErr_Occurred()) { |
584 | PyErr_WriteUnraisable(context ? context : Py_None); |
585 | retval = E_FAIL; |
586 | } |
587 | Py_DECREF(result); |
588 | return retval; |
589 | } |
590 | |
591 | /* |
592 | DllRegisterServer and DllUnregisterServer still missing |
593 | */ |
594 | |
595 | STDAPI DllCanUnloadNow(void) |
596 | { |
597 | long result; |
598 | PyGILState_STATE state = PyGILState_Ensure(); |
599 | result = Call_CanUnloadNow(); |
600 | PyGILState_Release(state); |
601 | return result; |
602 | } |
603 | |
604 | #ifndef Py_NO_ENABLE_SHARED |
605 | BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvRes) |
606 | { |
607 | switch(fdwReason) { |
608 | case DLL_PROCESS_ATTACH: |
609 | DisableThreadLibraryCalls(hinstDLL); |
610 | break; |
611 | } |
612 | return TRUE; |
613 | } |
614 | #endif |
615 | |
616 | #endif |
617 | |
618 | /* |
619 | Local Variables: |
620 | compile-command: "cd .. && python setup.py -q build_ext" |
621 | End: |
622 | */ |
623 | |