1 #ifndef Py_BUILD_CORE_BUILTIN
2 # define Py_BUILD_CORE_MODULE 1
3 #endif
4 #define NEEDS_PY_IDENTIFIER
5
6 #include "Python.h"
7 // windows.h must be included before pycore internal headers
8 #ifdef MS_WIN32
9 # include <windows.h>
10 #endif
11
12 #include "pycore_call.h" // _PyObject_CallNoArgs()
13
14 #include <stdbool.h>
15
16 #ifdef MS_WIN32
17 # include <malloc.h>
18 #endif
19
20 #include <ffi.h>
21 #include "ctypes.h"
22
23 #ifdef HAVE_ALLOCA_H
24 /* AIX needs alloca.h for alloca() */
25 #include <alloca.h>
26 #endif
27
28 /**************************************************************/
29
30 static void
CThunkObject_dealloc(PyObject * myself)31 CThunkObject_dealloc(PyObject *myself)
32 {
33 CThunkObject *self = (CThunkObject *)myself;
34 PyObject_GC_UnTrack(self);
35 Py_XDECREF(self->converters);
36 Py_XDECREF(self->callable);
37 Py_XDECREF(self->restype);
38 if (self->pcl_write)
39 Py_ffi_closure_free(self->pcl_write);
40 PyObject_GC_Del(self);
41 }
42
43 static int
CThunkObject_traverse(PyObject * myself,visitproc visit,void * arg)44 CThunkObject_traverse(PyObject *myself, visitproc visit, void *arg)
45 {
46 CThunkObject *self = (CThunkObject *)myself;
47 Py_VISIT(self->converters);
48 Py_VISIT(self->callable);
49 Py_VISIT(self->restype);
50 return 0;
51 }
52
53 static int
CThunkObject_clear(PyObject * myself)54 CThunkObject_clear(PyObject *myself)
55 {
56 CThunkObject *self = (CThunkObject *)myself;
57 Py_CLEAR(self->converters);
58 Py_CLEAR(self->callable);
59 Py_CLEAR(self->restype);
60 return 0;
61 }
62
63 PyTypeObject PyCThunk_Type = {
64 PyVarObject_HEAD_INIT(NULL, 0)
65 "_ctypes.CThunkObject",
66 sizeof(CThunkObject), /* tp_basicsize */
67 sizeof(ffi_type), /* tp_itemsize */
68 CThunkObject_dealloc, /* tp_dealloc */
69 0, /* tp_vectorcall_offset */
70 0, /* tp_getattr */
71 0, /* tp_setattr */
72 0, /* tp_as_async */
73 0, /* tp_repr */
74 0, /* tp_as_number */
75 0, /* tp_as_sequence */
76 0, /* tp_as_mapping */
77 0, /* tp_hash */
78 0, /* tp_call */
79 0, /* tp_str */
80 0, /* tp_getattro */
81 0, /* tp_setattro */
82 0, /* tp_as_buffer */
83 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
84 PyDoc_STR("CThunkObject"), /* tp_doc */
85 CThunkObject_traverse, /* tp_traverse */
86 CThunkObject_clear, /* tp_clear */
87 0, /* tp_richcompare */
88 0, /* tp_weaklistoffset */
89 0, /* tp_iter */
90 0, /* tp_iternext */
91 0, /* tp_methods */
92 0, /* tp_members */
93 };
94
95 /**************************************************************/
96
97 static void
PrintError(const char * msg,...)98 PrintError(const char *msg, ...)
99 {
100 char buf[512];
101 PyObject *f = PySys_GetObject("stderr");
102 va_list marker;
103
104 va_start(marker, msg);
105 PyOS_vsnprintf(buf, sizeof(buf), msg, marker);
106 va_end(marker);
107 if (f != NULL && f != Py_None)
108 PyFile_WriteString(buf, f);
109 PyErr_Print();
110 }
111
112
113 #ifdef MS_WIN32
114 /*
115 * We must call AddRef() on non-NULL COM pointers we receive as arguments
116 * to callback functions - these functions are COM method implementations.
117 * The Python instances we create have a __del__ method which calls Release().
118 *
119 * The presence of a class attribute named '_needs_com_addref_' triggers this
120 * behaviour. It would also be possible to call the AddRef() Python method,
121 * after checking for PyObject_IsTrue(), but this would probably be somewhat
122 * slower.
123 */
124 static void
TryAddRef(StgDictObject * dict,CDataObject * obj)125 TryAddRef(StgDictObject *dict, CDataObject *obj)
126 {
127 IUnknown *punk;
128 _Py_IDENTIFIER(_needs_com_addref_);
129
130 int r = _PyDict_ContainsId((PyObject *)dict, &PyId__needs_com_addref_);
131 if (r <= 0) {
132 if (r < 0) {
133 PrintError("getting _needs_com_addref_");
134 }
135 return;
136 }
137
138 punk = *(IUnknown **)obj->b_ptr;
139 if (punk)
140 punk->lpVtbl->AddRef(punk);
141 return;
142 }
143 #endif
144
145 /******************************************************************************
146 *
147 * Call the python object with all arguments
148 *
149 */
_CallPythonObject(void * mem,ffi_type * restype,SETFUNC setfunc,PyObject * callable,PyObject * converters,int flags,void ** pArgs)150 static void _CallPythonObject(void *mem,
151 ffi_type *restype,
152 SETFUNC setfunc,
153 PyObject *callable,
154 PyObject *converters,
155 int flags,
156 void **pArgs)
157 {
158 PyObject *result = NULL;
159 Py_ssize_t i = 0, j = 0, nargs = 0;
160 PyObject *error_object = NULL;
161 int *space;
162 PyGILState_STATE state = PyGILState_Ensure();
163
164 assert(PyTuple_Check(converters));
165 nargs = PyTuple_GET_SIZE(converters);
166 assert(nargs <= CTYPES_MAX_ARGCOUNT);
167 PyObject **args = alloca(nargs * sizeof(PyObject *));
168 PyObject **cnvs = PySequence_Fast_ITEMS(converters);
169 for (i = 0; i < nargs; i++) {
170 PyObject *cnv = cnvs[i]; // borrowed ref
171 StgDictObject *dict;
172 dict = PyType_stgdict(cnv);
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 goto Done;
179 }
180 args[i] = v;
181 /* XXX XXX XX
182 We have the problem that c_byte or c_short have dict->size of
183 1 resp. 4, but these parameters are pushed as sizeof(int) bytes.
184 BTW, the same problem occurs when they are pushed as parameters
185 */
186 } else if (dict) {
187 /* Hm, shouldn't we use PyCData_AtAddress() or something like that instead? */
188 CDataObject *obj = (CDataObject *)_PyObject_CallNoArgs(cnv);
189 if (!obj) {
190 PrintError("create argument %zd:\n", i);
191 goto Done;
192 }
193 if (!CDataObject_Check(obj)) {
194 Py_DECREF(obj);
195 PrintError("unexpected result of create argument %zd:\n", i);
196 goto Done;
197 }
198 memcpy(obj->b_ptr, *pArgs, dict->size);
199 args[i] = (PyObject *)obj;
200 #ifdef MS_WIN32
201 TryAddRef(dict, obj);
202 #endif
203 } else {
204 PyErr_SetString(PyExc_TypeError,
205 "cannot build parameter");
206 PrintError("Parsing argument %zd\n", i);
207 goto Done;
208 }
209 /* XXX error handling! */
210 pArgs++;
211 }
212
213 if (flags & (FUNCFLAG_USE_ERRNO | FUNCFLAG_USE_LASTERROR)) {
214 error_object = _ctypes_get_errobj(&space);
215 if (error_object == NULL)
216 goto Done;
217 if (flags & FUNCFLAG_USE_ERRNO) {
218 int temp = space[0];
219 space[0] = errno;
220 errno = temp;
221 }
222 #ifdef MS_WIN32
223 if (flags & FUNCFLAG_USE_LASTERROR) {
224 int temp = space[1];
225 space[1] = GetLastError();
226 SetLastError(temp);
227 }
228 #endif
229 }
230
231 result = PyObject_Vectorcall(callable, args, nargs, NULL);
232 if (result == NULL) {
233 _PyErr_WriteUnraisableMsg("on calling ctypes callback function",
234 callable);
235 }
236
237 #ifdef MS_WIN32
238 if (flags & FUNCFLAG_USE_LASTERROR) {
239 int temp = space[1];
240 space[1] = GetLastError();
241 SetLastError(temp);
242 }
243 #endif
244 if (flags & FUNCFLAG_USE_ERRNO) {
245 int temp = space[0];
246 space[0] = errno;
247 errno = temp;
248 }
249 Py_XDECREF(error_object);
250
251 if (restype != &ffi_type_void && result) {
252 assert(setfunc);
253
254 #ifdef WORDS_BIGENDIAN
255 /* See the corresponding code in _ctypes_callproc():
256 in callproc.c, around line 1219. */
257 if (restype->type != FFI_TYPE_FLOAT && restype->size < sizeof(ffi_arg)) {
258 mem = (char *)mem + sizeof(ffi_arg) - restype->size;
259 }
260 #endif
261
262 /* keep is an object we have to keep alive so that the result
263 stays valid. If there is no such object, the setfunc will
264 have returned Py_None.
265
266 If there is such an object, we have no choice than to keep
267 it alive forever - but a refcount and/or memory leak will
268 be the result. EXCEPT when restype is py_object - Python
269 itself knows how to manage the refcount of these objects.
270 */
271 PyObject *keep = setfunc(mem, result, 0);
272
273 if (keep == NULL) {
274 /* Could not convert callback result. */
275 _PyErr_WriteUnraisableMsg("on converting result "
276 "of ctypes callback function",
277 callable);
278 }
279 else if (setfunc != _ctypes_get_fielddesc("O")->setfunc) {
280 if (keep == Py_None) {
281 /* Nothing to keep */
282 Py_DECREF(keep);
283 }
284 else if (PyErr_WarnEx(PyExc_RuntimeWarning,
285 "memory leak in callback function.",
286 1) == -1) {
287 _PyErr_WriteUnraisableMsg("on converting result "
288 "of ctypes callback function",
289 callable);
290 }
291 }
292 }
293
294 Py_XDECREF(result);
295
296 Done:
297 for (j = 0; j < i; j++) {
298 Py_DECREF(args[j]);
299 }
300 PyGILState_Release(state);
301 }
302
closure_fcn(ffi_cif * cif,void * resp,void ** args,void * userdata)303 static void closure_fcn(ffi_cif *cif,
304 void *resp,
305 void **args,
306 void *userdata)
307 {
308 CThunkObject *p = (CThunkObject *)userdata;
309
310 _CallPythonObject(resp,
311 p->ffi_restype,
312 p->setfunc,
313 p->callable,
314 p->converters,
315 p->flags,
316 args);
317 }
318
CThunkObject_new(Py_ssize_t nargs)319 static CThunkObject* CThunkObject_new(Py_ssize_t nargs)
320 {
321 CThunkObject *p;
322 Py_ssize_t i;
323
324 p = PyObject_GC_NewVar(CThunkObject, &PyCThunk_Type, nargs);
325 if (p == NULL) {
326 return NULL;
327 }
328
329 p->pcl_write = NULL;
330 p->pcl_exec = NULL;
331 memset(&p->cif, 0, sizeof(p->cif));
332 p->flags = 0;
333 p->converters = NULL;
334 p->callable = NULL;
335 p->restype = NULL;
336 p->setfunc = NULL;
337 p->ffi_restype = NULL;
338
339 for (i = 0; i < nargs + 1; ++i)
340 p->atypes[i] = NULL;
341 PyObject_GC_Track((PyObject *)p);
342 return p;
343 }
344
_ctypes_alloc_callback(PyObject * callable,PyObject * converters,PyObject * restype,int flags)345 CThunkObject *_ctypes_alloc_callback(PyObject *callable,
346 PyObject *converters,
347 PyObject *restype,
348 int flags)
349 {
350 int result;
351 CThunkObject *p;
352 Py_ssize_t nargs, i;
353 ffi_abi cc;
354
355 assert(PyTuple_Check(converters));
356 nargs = PyTuple_GET_SIZE(converters);
357 p = CThunkObject_new(nargs);
358 if (p == NULL)
359 return NULL;
360
361 assert(CThunk_CheckExact((PyObject *)p));
362
363 p->pcl_write = Py_ffi_closure_alloc(sizeof(ffi_closure), &p->pcl_exec);
364 if (p->pcl_write == NULL) {
365 PyErr_NoMemory();
366 goto error;
367 }
368
369 p->flags = flags;
370 PyObject **cnvs = PySequence_Fast_ITEMS(converters);
371 for (i = 0; i < nargs; ++i) {
372 PyObject *cnv = cnvs[i]; // borrowed ref
373 p->atypes[i] = _ctypes_get_ffi_type(cnv);
374 }
375 p->atypes[i] = NULL;
376
377 Py_INCREF(restype);
378 p->restype = restype;
379 if (restype == Py_None) {
380 p->setfunc = NULL;
381 p->ffi_restype = &ffi_type_void;
382 } else {
383 StgDictObject *dict = PyType_stgdict(restype);
384 if (dict == NULL || dict->setfunc == NULL) {
385 PyErr_SetString(PyExc_TypeError,
386 "invalid result type for callback function");
387 goto error;
388 }
389 p->setfunc = dict->setfunc;
390 p->ffi_restype = &dict->ffi_type_pointer;
391 }
392
393 cc = FFI_DEFAULT_ABI;
394 #if defined(MS_WIN32) && !defined(_WIN32_WCE) && !defined(MS_WIN64) && !defined(_M_ARM)
395 if ((flags & FUNCFLAG_CDECL) == 0)
396 cc = FFI_STDCALL;
397 #endif
398 result = ffi_prep_cif(&p->cif, cc,
399 Py_SAFE_DOWNCAST(nargs, Py_ssize_t, int),
400 p->ffi_restype,
401 &p->atypes[0]);
402 if (result != FFI_OK) {
403 PyErr_Format(PyExc_RuntimeError,
404 "ffi_prep_cif failed with %d", result);
405 goto error;
406 }
407
408
409 #if HAVE_FFI_PREP_CLOSURE_LOC
410 # ifdef USING_APPLE_OS_LIBFFI
411 # ifdef HAVE_BUILTIN_AVAILABLE
412 # define HAVE_FFI_PREP_CLOSURE_LOC_RUNTIME __builtin_available(macos 10.15, ios 13, watchos 6, tvos 13, *)
413 # else
414 # define HAVE_FFI_PREP_CLOSURE_LOC_RUNTIME (ffi_prep_closure_loc != NULL)
415 # endif
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 defined(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
LoadPython(void)468 static void LoadPython(void)
469 {
470 if (!Py_IsInitialized()) {
471 Py_Initialize();
472 }
473 }
474
475 /******************************************************************/
476
Call_GetClassObject(REFCLSID rclsid,REFIID riid,LPVOID * ppv)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_ImportModule("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
DllGetClassObject(REFCLSID rclsid,REFIID riid,LPVOID * ppv)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
Call_CanUnloadNow(void)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_ImportModule("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_CallNoArgs(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
DllCanUnloadNow(void)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
DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvRes)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