1 
2 /* A Lib object is what is in the "lib" attribute of a C extension
3    module originally created by recompile().
4 
5    A Lib object is special in the sense that it has a custom
6    __getattr__ which returns C globals, functions and constants.  The
7    original idea was to raise AttributeError for anything else, even
8    attrs like '__class__', but it breaks various things; now, standard
9    attrs are returned, but in the unlikely case where a user cdef()s
10    the same name, then the standard attr is hidden (and the various
11    things like introspection might break).
12 
13    A Lib object has got a reference to the _cffi_type_context_s
14    structure, which is used to create lazily the objects returned by
15    __getattr__.
16 */
17 
18 struct CPyExtFunc_s {
19     PyMethodDef md;
20     void *direct_fn;
21     int type_index;
22     char doc[1];
23 };
24 
25 struct LibObject_s {
26     PyObject_HEAD
27     builder_c_t *l_types_builder; /* same as the one on the ffi object */
28     PyObject *l_dict;           /* content, built lazily */
29     PyObject *l_libname;        /* some string that gives the name of the lib */
30     FFIObject *l_ffi;           /* reference back to the ffi object */
31     void *l_libhandle;          /* the dlopen()ed handle, if any */
32 };
33 
_cpyextfunc_get(PyObject * x)34 static struct CPyExtFunc_s *_cpyextfunc_get(PyObject *x)
35 {
36     PyObject *y;
37     LibObject *lo;
38     PyCFunctionObject *fo;
39 
40     if (!PyCFunction_Check(x))
41         return NULL;
42     y = PyCFunction_GET_SELF(x);
43     if (!LibObject_Check(y))
44         return NULL;
45 
46     fo = (PyCFunctionObject *)x;
47     lo = (LibObject *)y;
48     if (lo->l_libname != fo->m_module)
49         return NULL;
50 
51     return (struct CPyExtFunc_s *)(fo->m_ml);
52 }
53 
_cpyextfunc_type(LibObject * lib,struct CPyExtFunc_s * exf)54 static PyObject *_cpyextfunc_type(LibObject *lib, struct CPyExtFunc_s *exf)
55 {
56     PyObject *tuple, *result;
57     tuple = realize_c_type_or_func(lib->l_types_builder,
58                                    lib->l_types_builder->ctx.types,
59                                    exf->type_index);
60     if (tuple == NULL)
61         return NULL;
62 
63     /* 'tuple' is a tuple of length 1 containing the real CT_FUNCTIONPTR
64        object */
65     result = PyTuple_GetItem(tuple, 0);
66     Py_XINCREF(result);
67     Py_DECREF(tuple);
68     return result;
69 }
70 
_cpyextfunc_type_index(PyObject * x)71 static PyObject *_cpyextfunc_type_index(PyObject *x)
72 {
73     struct CPyExtFunc_s *exf;
74     LibObject *lib;
75 
76     assert(PyErr_Occurred());
77     exf = _cpyextfunc_get(x);
78     if (exf == NULL)
79         return NULL;    /* still the same exception is set */
80 
81     PyErr_Clear();
82 
83     lib = (LibObject *)PyCFunction_GET_SELF(x);
84     return _cpyextfunc_type(lib, exf);
85 }
86 
87 static void cdlopen_close_ignore_errors(void *libhandle);  /* forward */
88 static void *cdlopen_fetch(PyObject *libname, void *libhandle,
89                            const char *symbol);
90 
lib_dealloc(LibObject * lib)91 static void lib_dealloc(LibObject *lib)
92 {
93     PyObject_GC_UnTrack(lib);
94     cdlopen_close_ignore_errors(lib->l_libhandle);
95     Py_DECREF(lib->l_dict);
96     Py_DECREF(lib->l_libname);
97     Py_DECREF(lib->l_ffi);
98     PyObject_GC_Del(lib);
99 }
100 
lib_traverse(LibObject * lib,visitproc visit,void * arg)101 static int lib_traverse(LibObject *lib, visitproc visit, void *arg)
102 {
103     Py_VISIT(lib->l_dict);
104     Py_VISIT(lib->l_libname);
105     Py_VISIT(lib->l_ffi);
106     return 0;
107 }
108 
lib_repr(LibObject * lib)109 static PyObject *lib_repr(LibObject *lib)
110 {
111     return PyText_FromFormat("<Lib object for '%.200s'>",
112                              PyText_AS_UTF8(lib->l_libname));
113 }
114 
lib_build_cpython_func(LibObject * lib,const struct _cffi_global_s * g,const char * s,int flags)115 static PyObject *lib_build_cpython_func(LibObject *lib,
116                                         const struct _cffi_global_s *g,
117                                         const char *s, int flags)
118 {
119     /* First make sure the argument types and return type are really
120        built.  The C extension code can then assume that they are,
121        by calling _cffi_type().
122     */
123     PyObject *result = NULL;
124     CTypeDescrObject **pfargs = NULL;
125     CTypeDescrObject *fresult;
126     Py_ssize_t nargs = 0;
127     struct CPyExtFunc_s *xfunc;
128     int i, type_index = _CFFI_GETARG(g->type_op);
129     _cffi_opcode_t *opcodes = lib->l_types_builder->ctx.types;
130     static const char *const format = ";\n\nCFFI C function from %s.lib";
131     const char *libname = PyText_AS_UTF8(lib->l_libname);
132     struct funcbuilder_s funcbuilder;
133 
134     /* return type: */
135     fresult = realize_c_func_return_type(lib->l_types_builder, opcodes,
136                                        type_index);
137     if (fresult == NULL)
138         goto error;
139 
140     /* argument types: */
141     /* note that if the arguments are already built, they have a
142        pointer in the 'opcodes' array, and GETOP() returns a
143        random even value.  But OP_FUNCTION_END is odd, so the
144        condition below still works correctly. */
145     i = type_index + 1;
146     while (_CFFI_GETOP(opcodes[i]) != _CFFI_OP_FUNCTION_END)
147         i++;
148     pfargs = alloca(sizeof(CTypeDescrObject *) * (i - type_index - 1));
149     i = type_index + 1;
150     while (_CFFI_GETOP(opcodes[i]) != _CFFI_OP_FUNCTION_END) {
151         CTypeDescrObject *ct = realize_c_type(lib->l_types_builder, opcodes, i);
152         if (ct == NULL)
153             goto error;
154         pfargs[nargs++] = ct;
155         i++;
156     }
157 
158     memset(&funcbuilder, 0, sizeof(funcbuilder));
159     if (fb_build_name(&funcbuilder, g->name, pfargs, nargs, fresult, 0) < 0)
160         goto error;
161 
162     /* The few bytes of memory we allocate here appear to leak, but
163        this is not a real leak.  Indeed, CPython never unloads its C
164        extension modules.  There is only one PyMem_Malloc() per real
165        C function in a CFFI C extension module.  That means that this
166        PyMem_Malloc() could also have been written with a static
167        global variable generated for each CPYTHON_BLTN defined in the
168        C extension, and the effect would be the same (but a bit more
169        complicated).
170     */
171     xfunc = PyMem_Malloc(sizeof(struct CPyExtFunc_s) +
172                          funcbuilder.nb_bytes +
173                          strlen(format) + strlen(libname));
174     if (xfunc == NULL) {
175         PyErr_NoMemory();
176         goto error;
177     }
178     memset((char *)xfunc, 0, sizeof(struct CPyExtFunc_s));
179     assert(g->address);
180     xfunc->md.ml_meth = (PyCFunction)g->address;
181     xfunc->md.ml_flags = flags;
182     xfunc->md.ml_name = g->name;
183     xfunc->md.ml_doc = xfunc->doc;
184     xfunc->direct_fn = g->size_or_direct_fn;
185     xfunc->type_index = type_index;
186 
187     /* build the docstring */
188     funcbuilder.bufferp = xfunc->doc;
189     if (fb_build_name(&funcbuilder, g->name, pfargs, nargs, fresult, 0) < 0)
190         goto error;
191     sprintf(funcbuilder.bufferp - 1, format, libname);
192     /* done building the docstring */
193 
194     result = PyCFunction_NewEx(&xfunc->md, (PyObject *)lib, lib->l_libname);
195     /* fall-through */
196  error:
197     Py_XDECREF(fresult);
198     while (nargs > 0) {
199         --nargs;
200         Py_DECREF(pfargs[nargs]);
201     }
202     return result;
203 }
204 
lib_build_and_cache_attr(LibObject * lib,PyObject * name,int recursion)205 static PyObject *lib_build_and_cache_attr(LibObject *lib, PyObject *name,
206                                           int recursion)
207 {
208     /* does not return a new reference! */
209     PyObject *x;
210     int index;
211     const struct _cffi_global_s *g;
212     CTypeDescrObject *ct;
213     builder_c_t *types_builder = lib->l_types_builder;
214     const char *s = PyText_AsUTF8(name);
215     if (s == NULL)
216         return NULL;
217 
218     index = search_in_globals(&types_builder->ctx, s, strlen(s));
219     if (index < 0) {
220 
221         if (types_builder->included_libs != NULL) {
222             Py_ssize_t i;
223             PyObject *included_ffis = types_builder->included_ffis;
224             PyObject *included_libs = types_builder->included_libs;
225 
226             if (recursion > 100) {
227                 PyErr_SetString(PyExc_RuntimeError,
228                     "recursion overflow in ffi.include() delegations");
229                 return NULL;
230             }
231 
232             for (i = 0; i < PyTuple_GET_SIZE(included_libs); i++) {
233                 LibObject *lib1;
234 
235                 lib1 = (LibObject *)PyTuple_GET_ITEM(included_libs, i);
236                 if (lib1 != NULL) {
237                     x = PyDict_GetItem(lib1->l_dict, name);
238                     if (x != NULL) {
239                         Py_INCREF(x);
240                         goto found;
241                     }
242                     x = lib_build_and_cache_attr(lib1, name, recursion + 1);
243                     if (x != NULL) {
244                         Py_INCREF(x);
245                         goto found;
246                     }
247                 }
248                 else {
249                     FFIObject *ffi1;
250 
251                     ffi1 = (FFIObject *)PyTuple_GetItem(included_ffis, i);
252                     if (ffi1 == NULL)
253                         return NULL;
254                     x = ffi_fetch_int_constant(ffi1, s, recursion + 1);
255                     if (x != NULL)
256                         goto found;
257                 }
258                 if (PyErr_Occurred())
259                     return NULL;
260             }
261         }
262 
263         if (recursion > 0)
264             return NULL;  /* no error set, continue looking elsewhere */
265 
266         PyErr_Format(PyExc_AttributeError,
267                      "cffi library '%.200s' has no function, constant "
268                      "or global variable named '%.200s'",
269                      PyText_AS_UTF8(lib->l_libname), s);
270         return NULL;
271     }
272 
273     g = &types_builder->ctx.globals[index];
274 
275     switch (_CFFI_GETOP(g->type_op)) {
276 
277     case _CFFI_OP_CPYTHON_BLTN_V:
278         x = lib_build_cpython_func(lib, g, s, METH_VARARGS);
279         break;
280 
281     case _CFFI_OP_CPYTHON_BLTN_N:
282         x = lib_build_cpython_func(lib, g, s, METH_NOARGS);
283         break;
284 
285     case _CFFI_OP_CPYTHON_BLTN_O:
286         x = lib_build_cpython_func(lib, g, s, METH_O);
287         break;
288 
289     case _CFFI_OP_CONSTANT_INT:
290     case _CFFI_OP_ENUM:
291     {
292         /* a constant integer whose value, in an "unsigned long long",
293            is obtained by calling the function at g->address */
294         x = realize_global_int(types_builder, index);
295         break;
296     }
297 
298     case _CFFI_OP_CONSTANT:
299     case _CFFI_OP_DLOPEN_CONST:
300     {
301         /* a constant which is not of integer type */
302         char *data;
303         ct = realize_c_type(types_builder, types_builder->ctx.types,
304                             _CFFI_GETARG(g->type_op));
305         if (ct == NULL)
306             return NULL;
307 
308         if (ct->ct_size <= 0) {
309             PyErr_Format(FFIError, "constant '%s' is of type '%s', "
310                          "whose size is not known", s, ct->ct_name);
311             return NULL;
312         }
313         if (g->address == NULL) {
314             /* for dlopen() style */
315             assert(_CFFI_GETOP(g->type_op) == _CFFI_OP_DLOPEN_CONST);
316             data = cdlopen_fetch(lib->l_libname, lib->l_libhandle, s);
317             if (data == NULL)
318                 return NULL;
319         }
320         else {
321             /* The few bytes of memory we allocate here appear to leak, but
322                this is not a real leak.  Indeed, CPython never unloads its C
323                extension modules.  There is only one PyMem_Malloc() per real
324                non-integer C constant in a CFFI C extension module.  That
325                means that this PyMem_Malloc() could also have been written
326                with a static global variable generated for each OP_CONSTANT
327                defined in the C extension, and the effect would be the same
328                (but a bit more complicated).
329 
330                Note that we used to do alloca(), but see issue #198.  We
331                could still do alloca(), or explicit PyMem_Free(), in some
332                cases; but there is no point and it only makes the remaining
333                less-common cases more suspicious.
334             */
335             assert(_CFFI_GETOP(g->type_op) == _CFFI_OP_CONSTANT);
336             data = PyMem_Malloc(ct->ct_size);
337             if (data == NULL) {
338                 PyErr_NoMemory();
339                 return NULL;
340             }
341             ((void(*)(char*))g->address)(data);
342         }
343         x = convert_to_object(data, ct);
344         Py_DECREF(ct);
345         break;
346     }
347 
348     case _CFFI_OP_GLOBAL_VAR:
349     {
350         /* global variable of the exact type specified here
351            (nowadays, only used by the ABI mode or backward
352            compatibility; see _CFFI_OP_GLOBAL_VAR_F for the API mode)
353          */
354         Py_ssize_t g_size = (Py_ssize_t)g->size_or_direct_fn;
355         ct = realize_c_type(types_builder, types_builder->ctx.types,
356                             _CFFI_GETARG(g->type_op));
357         if (ct == NULL)
358             return NULL;
359         if (g_size != ct->ct_size && g_size != 0 && ct->ct_size > 0) {
360             PyErr_Format(FFIError,
361                          "global variable '%.200s' should be %zd bytes "
362                          "according to the cdef, but is actually %zd",
363                          s, ct->ct_size, g_size);
364             x = NULL;
365         }
366         else {
367             void *address = g->address;
368             if (address == NULL) {
369                 /* for dlopen() style */
370                 address = cdlopen_fetch(lib->l_libname, lib->l_libhandle, s);
371                 if (address == NULL)
372                     return NULL;
373             }
374             x = make_global_var(name, ct, address, NULL);
375         }
376         Py_DECREF(ct);
377         break;
378     }
379 
380     case _CFFI_OP_GLOBAL_VAR_F:
381         ct = realize_c_type(types_builder, types_builder->ctx.types,
382                             _CFFI_GETARG(g->type_op));
383         if (ct == NULL)
384             return NULL;
385         x = make_global_var(name, ct, NULL, (gs_fetch_addr_fn)g->address);
386         Py_DECREF(ct);
387         break;
388 
389     case _CFFI_OP_DLOPEN_FUNC:
390     {
391         /* For dlopen(): the function of the given 'name'.  We use
392            dlsym() to get the address of something in the dynamic
393            library, which we interpret as being exactly a function of
394            the specified type.
395         */
396         PyObject *ct1;
397         void *address = cdlopen_fetch(lib->l_libname, lib->l_libhandle, s);
398         if (address == NULL)
399             return NULL;
400 
401         ct1 = realize_c_type_or_func(types_builder,
402                                      types_builder->ctx.types,
403                                      _CFFI_GETARG(g->type_op));
404         if (ct1 == NULL)
405             return NULL;
406 
407         assert(!CTypeDescr_Check(ct1));   /* must be a function */
408         x = new_simple_cdata(address, unwrap_fn_as_fnptr(ct1));
409 
410         Py_DECREF(ct1);
411         break;
412     }
413 
414     case _CFFI_OP_EXTERN_PYTHON:
415         /* for reading 'lib.bar' where bar is declared with extern "Python" */
416         ct = realize_c_type(types_builder, types_builder->ctx.types,
417                             _CFFI_GETARG(g->type_op));
418         if (ct == NULL)
419             return NULL;
420         x = convert_to_object((char *)&g->size_or_direct_fn, ct);
421         Py_DECREF(ct);
422         break;
423 
424     default:
425         PyErr_Format(PyExc_NotImplementedError, "in lib_build_attr: op=%d",
426                      (int)_CFFI_GETOP(g->type_op));
427         return NULL;
428     }
429 
430  found:
431     if (x != NULL) {
432         int err = PyDict_SetItem(lib->l_dict, name, x);
433         Py_DECREF(x);
434         if (err < 0)     /* else there is still one ref left in the dict */
435             return NULL;
436     }
437     return x;
438 }
439 
440 #define LIB_GET_OR_CACHE_ADDR(x, lib, name, error)      \
441     do {                                                \
442         x = PyDict_GetItem(lib->l_dict, name);          \
443         if (x == NULL) {                                \
444             x = lib_build_and_cache_attr(lib, name, 0); \
445             if (x == NULL) {                            \
446                 error;                                  \
447             }                                           \
448         }                                               \
449     } while (0)
450 
_lib_dir1(LibObject * lib,int ignore_global_vars)451 static PyObject *_lib_dir1(LibObject *lib, int ignore_global_vars)
452 {
453     const struct _cffi_global_s *g = lib->l_types_builder->ctx.globals;
454     int i, count = 0, total = lib->l_types_builder->ctx.num_globals;
455     PyObject *s, *lst = PyList_New(total);
456     if (lst == NULL)
457         return NULL;
458 
459     for (i = 0; i < total; i++) {
460         if (ignore_global_vars) {
461             int op = _CFFI_GETOP(g[i].type_op);
462             if (op == _CFFI_OP_GLOBAL_VAR || op == _CFFI_OP_GLOBAL_VAR_F)
463                 continue;
464         }
465         s = PyText_FromString(g[i].name);
466         if (s == NULL)
467             goto error;
468         PyList_SET_ITEM(lst, count, s);
469         count++;
470     }
471     if (PyList_SetSlice(lst, count, total, NULL) < 0)
472         goto error;
473     return lst;
474 
475  error:
476     Py_DECREF(lst);
477     return NULL;
478 }
479 
_lib_dict(LibObject * lib)480 static PyObject *_lib_dict(LibObject *lib)
481 {
482     const struct _cffi_global_s *g = lib->l_types_builder->ctx.globals;
483     int i, total = lib->l_types_builder->ctx.num_globals;
484     PyObject *name, *x, *d = PyDict_New();
485     if (d == NULL)
486         return NULL;
487 
488     for (i = 0; i < total; i++) {
489         name = PyText_FromString(g[i].name);
490         if (name == NULL)
491             goto error;
492 
493         LIB_GET_OR_CACHE_ADDR(x, lib, name, goto error);
494 
495         if (PyDict_SetItem(d, name, x) < 0)
496             goto error;
497         Py_DECREF(name);
498     }
499     return d;
500 
501  error:
502     Py_XDECREF(name);
503     Py_DECREF(d);
504     return NULL;
505 }
506 
lib_getattr(LibObject * lib,PyObject * name)507 static PyObject *lib_getattr(LibObject *lib, PyObject *name)
508 {
509     const char *p;
510     PyObject *x;
511     LIB_GET_OR_CACHE_ADDR(x, lib, name, goto missing);
512 
513     if (GlobSupport_Check(x)) {
514         return read_global_var((GlobSupportObject *)x);
515     }
516     Py_INCREF(x);
517     return x;
518 
519  missing:
520     /*** ATTRIBUTEERROR IS SET HERE ***/
521     p = PyText_AsUTF8(name);
522     if (p == NULL)
523         return NULL;
524     if (strcmp(p, "__all__") == 0) {
525         PyErr_Clear();
526         return _lib_dir1(lib, 1);
527     }
528     if (strcmp(p, "__dict__") == 0) {
529         PyErr_Clear();
530         return _lib_dict(lib);
531     }
532     if (strcmp(p, "__class__") == 0) {
533         PyErr_Clear();
534         x = (PyObject *)&PyModule_Type;
535         /* ^^^ used to be Py_TYPE(lib).  But HAAAAAACK!  That makes
536            help() behave correctly.  I couldn't find a more reasonable
537            way.  Urgh. */
538         Py_INCREF(x);
539         return x;
540     }
541     /* this hack is for Python 3.5, and also to give a more
542        module-like behavior */
543     if (strcmp(p, "__name__") == 0) {
544         PyErr_Clear();
545         return PyText_FromFormat("%s.lib", PyText_AS_UTF8(lib->l_libname));
546     }
547 #if PY_MAJOR_VERSION >= 3
548     if (strcmp(p, "__loader__") == 0 || strcmp(p, "__spec__") == 0) {
549         /* some more module-like behavior hacks */
550         PyErr_Clear();
551         Py_INCREF(Py_None);
552         return Py_None;
553     }
554 #endif
555     return NULL;
556 }
557 
lib_setattr(LibObject * lib,PyObject * name,PyObject * val)558 static int lib_setattr(LibObject *lib, PyObject *name, PyObject *val)
559 {
560     PyObject *x;
561     LIB_GET_OR_CACHE_ADDR(x, lib, name, return -1);
562 
563     if (val == NULL) {
564         PyErr_SetString(PyExc_AttributeError, "C attribute cannot be deleted");
565         return -1;
566     }
567 
568     if (GlobSupport_Check(x)) {
569         return write_global_var((GlobSupportObject *)x, val);
570     }
571 
572     PyErr_Format(PyExc_AttributeError,
573                  "cannot write to function or constant '%.200s'",
574                  PyText_Check(name) ? PyText_AS_UTF8(name) : "?");
575     return -1;
576 }
577 
lib_dir(PyObject * self,PyObject * noarg)578 static PyObject *lib_dir(PyObject *self, PyObject *noarg)
579 {
580     return _lib_dir1((LibObject *)self, 0);
581 }
582 
583 static PyMethodDef lib_methods[] = {
584     {"__dir__",   lib_dir,  METH_NOARGS},
585     {NULL,        NULL}           /* sentinel */
586 };
587 
588 static PyTypeObject Lib_Type = {
589     PyVarObject_HEAD_INIT(NULL, 0)
590     "CompiledLib",
591     sizeof(LibObject),
592     0,
593     (destructor)lib_dealloc,                    /* tp_dealloc */
594     0,                                          /* tp_print */
595     0,                                          /* tp_getattr */
596     0,                                          /* tp_setattr */
597     0,                                          /* tp_compare */
598     (reprfunc)lib_repr,                         /* tp_repr */
599     0,                                          /* tp_as_number */
600     0,                                          /* tp_as_sequence */
601     0,                                          /* tp_as_mapping */
602     0,                                          /* tp_hash */
603     0,                                          /* tp_call */
604     0,                                          /* tp_str */
605     (getattrofunc)lib_getattr,                  /* tp_getattro */
606     (setattrofunc)lib_setattr,                  /* tp_setattro */
607     0,                                          /* tp_as_buffer */
608     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,    /* tp_flags */
609     0,                                          /* tp_doc */
610     (traverseproc)lib_traverse,                 /* tp_traverse */
611     0,                                          /* tp_clear */
612     0,                                          /* tp_richcompare */
613     0,                                          /* tp_weaklistoffset */
614     0,                                          /* tp_iter */
615     0,                                          /* tp_iternext */
616     lib_methods,                                /* tp_methods */
617     0,                                          /* tp_members */
618     0,                                          /* tp_getset */
619     0,                                          /* tp_base */
620     0,                                          /* tp_dict */
621     0,                                          /* tp_descr_get */
622     0,                                          /* tp_descr_set */
623     offsetof(LibObject, l_dict),                /* tp_dictoffset */
624 };
625 
lib_internal_new(FFIObject * ffi,const char * module_name,void * dlopen_libhandle)626 static LibObject *lib_internal_new(FFIObject *ffi, const char *module_name,
627                                    void *dlopen_libhandle)
628 {
629     LibObject *lib;
630     PyObject *libname, *dict;
631 
632     libname = PyText_FromString(module_name);
633     if (libname == NULL)
634         goto err1;
635 
636     dict = PyDict_New();
637     if (dict == NULL)
638         goto err2;
639 
640     lib = (LibObject *)PyType_GenericAlloc(&Lib_Type, 0);
641     if (lib == NULL)
642         goto err3;
643 
644     lib->l_types_builder = &ffi->types_builder;
645     lib->l_dict = dict;
646     lib->l_libname = libname;
647     Py_INCREF(ffi);
648     lib->l_ffi = ffi;
649     lib->l_libhandle = dlopen_libhandle;
650     return lib;
651 
652  err3:
653     Py_DECREF(dict);
654  err2:
655     Py_DECREF(libname);
656  err1:
657     cdlopen_close_ignore_errors(dlopen_libhandle);
658     return NULL;
659 }
660 
address_of_global_var(PyObject * args)661 static PyObject *address_of_global_var(PyObject *args)
662 {
663     LibObject *lib;
664     PyObject *x, *o_varname;
665     char *varname;
666 
667     if (!PyArg_ParseTuple(args, "O!s", &Lib_Type, &lib, &varname))
668         return NULL;
669 
670     /* rebuild a string from 'varname', to do typechecks and to force
671        a unicode back to a plain string (on python 2) */
672     o_varname = PyText_FromString(varname);
673     if (o_varname == NULL)
674         return NULL;
675 
676     LIB_GET_OR_CACHE_ADDR(x, lib, o_varname, goto error);
677     Py_DECREF(o_varname);
678     if (GlobSupport_Check(x)) {
679         return cg_addressof_global_var((GlobSupportObject *)x);
680     }
681     else {
682         struct CPyExtFunc_s *exf = _cpyextfunc_get(x);
683         if (exf != NULL) {  /* an OP_CPYTHON_BLTN: '&func' returns a cdata */
684             PyObject *ct;
685             if (exf->direct_fn == NULL) {
686                 Py_INCREF(x);    /* backward compatibility */
687                 return x;
688             }
689             ct = _cpyextfunc_type(lib, exf);
690             if (ct == NULL)
691                 return NULL;
692             x = new_simple_cdata(exf->direct_fn, (CTypeDescrObject *)ct);
693             Py_DECREF(ct);
694             return x;
695         }
696         if (CData_Check(x) &&  /* a constant functionptr cdata: 'f == &f' */
697                 (((CDataObject *)x)->c_type->ct_flags & CT_FUNCTIONPTR) != 0) {
698             Py_INCREF(x);
699             return x;
700         }
701         else {
702             PyErr_Format(PyExc_AttributeError,
703                          "cannot take the address of the constant '%.200s'",
704                          varname);
705             return NULL;
706         }
707     }
708 
709  error:
710     Py_DECREF(o_varname);
711     return NULL;
712 }
713