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
14static void
15CThunkObject_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
27static int
28CThunkObject_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
37static int
38CThunkObject_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
47PyTypeObject 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
81static void
82PrintError(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 */
108static void
109TryAddRef(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 */
134static 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
308static 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
324static 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
350CThunkObject *_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
468static void LoadPython(void)
469{
470 if (!Py_IsInitialized()) {
471 Py_Initialize();
472 }
473}
474
475/******************************************************************/
476
477long 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
536STDAPI 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
550long 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
595STDAPI 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
605BOOL 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