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