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