Mercurial > pub > dyncall > bindings
comparison python/pydc/pydcext.c @ 43:1086ca649715
- fixed use after free issue with string handling (keeping strings as copy until after call)
author | Tassilo Philipp |
---|---|
date | Wed, 15 Apr 2020 21:58:13 +0200 |
parents | 1d50532dce12 |
children | 0f86a5ecfe61 |
comparison
equal
deleted
inserted
replaced
42:1e3d929e43be | 43:1086ca649715 |
---|---|
31 # define DcPyCObject_FromVoidPtr(ptr, dtor) PyCapsule_New((ptr), NULL, (dtor)) // !new ref! | 31 # define DcPyCObject_FromVoidPtr(ptr, dtor) PyCapsule_New((ptr), NULL, (dtor)) // !new ref! |
32 # define DcPyCObject_AsVoidPtr(ppobj) PyCapsule_GetPointer((ppobj), NULL) | 32 # define DcPyCObject_AsVoidPtr(ppobj) PyCapsule_GetPointer((ppobj), NULL) |
33 # define DcPyCObject_SetVoidPtr(ppobj, ptr) //@@@ unsure what to do, cannot/shouldn't call this with a null pointer as this wants to call the dtor, so not doing anything: PyCapsule_SetPointer((ppobj), (ptr)) // this might need to call the dtor to behave like PyCObject_SetVoidPtr? | 33 # define DcPyCObject_SetVoidPtr(ppobj, ptr) //@@@ unsure what to do, cannot/shouldn't call this with a null pointer as this wants to call the dtor, so not doing anything: PyCapsule_SetPointer((ppobj), (ptr)) // this might need to call the dtor to behave like PyCObject_SetVoidPtr? |
34 #endif | 34 #endif |
35 | 35 |
36 #if(PY_VERSION_HEX >= 0x03030000) | |
37 # define PYUNICODE_CACHES_UTF8 | |
38 #endif | |
39 | |
36 #if PY_MAJOR_VERSION >= 3 | 40 #if PY_MAJOR_VERSION >= 3 |
37 # define EXPECT_LONG_TYPE_STR "an int" | 41 # define EXPECT_LONG_TYPE_STR "an int" |
38 # define DcPyString_GET_SIZE PyBytes_GET_SIZE | 42 # define DcPyString_GET_SIZE PyBytes_GET_SIZE |
39 # define DcPyString_Check PyBytes_Check | 43 # define DcPyString_Check PyBytes_Check |
40 # define DcPyString_AsString PyBytes_AsString | 44 # define DcPyString_AsString PyBytes_AsString |
167 #include "dyncall.h" | 171 #include "dyncall.h" |
168 #include "dyncall_signature.h" | 172 #include "dyncall_signature.h" |
169 | 173 |
170 DCCallVM* gpCall = NULL; | 174 DCCallVM* gpCall = NULL; |
171 | 175 |
176 // helper to temporarily copy string arguments | |
177 #define NUM_AUX_STRS 64 | |
178 static int n_str_aux; | |
179 static char* str_aux[NUM_AUX_STRS]; // hard limit, most likely enough and checked for below @@@ugly though | |
180 | |
172 | 181 |
173 /* call function */ | 182 /* call function */ |
174 | 183 |
175 static PyObject* | 184 static PyObject* |
176 pydc_call(PyObject* self, PyObject* in_args) | 185 pydc_call_impl(PyObject* self, PyObject* in_args) /* implementation, called by wrapper func pydc_call() */ |
177 { | 186 { |
178 PyObject *pcobj_funcptr, *args; | 187 PyObject *pcobj_funcptr, *args; |
179 const char *signature, *ptr; | 188 const char *signature, *ptr; |
180 char ch; | 189 char ch; |
181 int pos, ts; | 190 int pos, ts; |
358 | 367 |
359 case DC_SIGCHAR_STRING: // strings are considered to be immutable objects | 368 case DC_SIGCHAR_STRING: // strings are considered to be immutable objects |
360 { | 369 { |
361 PyObject* bo = NULL; | 370 PyObject* bo = NULL; |
362 const char* p; | 371 const char* p; |
363 char* p_; | |
364 size_t s; | 372 size_t s; |
365 if ( PyUnicode_Check(po) ) { | 373 if ( PyUnicode_Check(po) ) |
374 { | |
375 if(n_str_aux >= NUM_AUX_STRS) | |
376 return PyErr_Format( PyExc_RuntimeError, "too many arguments (implementation limit of %d new UTF-8 string references reached) - abort", n_str_aux ); | |
377 | |
378 #if defined(PYUNICODE_CACHES_UTF8) | |
379 p = PyUnicode_AsUTF8(po); | |
380 #else | |
381 // w/o PyUnicode_AsUTF8(), which caches the UTF-8 representation, itself, create new ref we'll dec below | |
366 if((bo = PyUnicode_AsEncodedString(po, "utf-8", "strict"))) // !new ref! | 382 if((bo = PyUnicode_AsEncodedString(po, "utf-8", "strict"))) // !new ref! |
367 p = PyBytes_AS_STRING(bo); // Borrowed pointer | 383 p = PyBytes_AS_STRING(bo); // Borrowed pointer |
384 #endif | |
368 } else if ( DcPyString_Check(po) ) | 385 } else if ( DcPyString_Check(po) ) |
369 p = DcPyString_AsString(po); //@@@ must not be modified in any way | 386 p = DcPyString_AsString(po); |
370 else if ( PyByteArray_Check(po) ) | 387 else if ( PyByteArray_Check(po) ) |
371 p = (DCpointer) PyByteArray_AsString(po); // adds an extra '\0', but that's ok //@@@ not sure if allowed to modify | 388 p = (DCpointer) PyByteArray_AsString(po); // adds an extra '\0', but that's ok //@@@ not sure if allowed to modify |
372 else | 389 else |
373 return PyErr_Format( PyExc_RuntimeError, "arg %d - expecting a str", pos ); | 390 return PyErr_Format( PyExc_RuntimeError, "arg %d - expecting a str", pos ); |
374 | 391 |
375 // pointer points in any case to a buffer that shouldn't be modified, so pass a copy of the string to dyncall | 392 // p points in any case to a buffer that shouldn't be modified, so pass a copy to dyncall (cleaned up after call) |
376 s = strlen(p)+1; | 393 s = strlen(p)+1; |
377 p_ = malloc(s); | 394 str_aux[n_str_aux] = malloc(s); |
378 strncpy(p_, p, s); | 395 strncpy(str_aux[n_str_aux], p, s); |
379 Py_XDECREF(bo); | 396 Py_XDECREF(bo); |
380 dcArgPointer(gpCall, (DCpointer)p_); | 397 dcArgPointer(gpCall, (DCpointer)str_aux[n_str_aux++]); |
381 free(p_); | |
382 } | 398 } |
383 break; | 399 break; |
384 | 400 |
385 default: | 401 default: |
386 return PyErr_Format( PyExc_RuntimeError, "unknown signature character '%c'", ch); | 402 return PyErr_Format( PyExc_RuntimeError, "unknown signature character '%c'", ch); |
417 default: return PyErr_Format(PyExc_RuntimeError, "invalid return type signature"); | 433 default: return PyErr_Format(PyExc_RuntimeError, "invalid return type signature"); |
418 } | 434 } |
419 } | 435 } |
420 | 436 |
421 | 437 |
438 static PyObject* | |
439 pydc_call(PyObject* self, PyObject* in_args) | |
440 { | |
441 int i; | |
442 n_str_aux = 0; | |
443 PyObject* o = pydc_call_impl(self, in_args); | |
444 for(i = 0; i<n_str_aux; ++i) | |
445 free(str_aux[i]); | |
446 return o; | |
447 } | |
448 | |
422 | 449 |
423 // module deinit | 450 // module deinit |
424 static void deinit_pydc(void* x) | 451 static void deinit_pydc(void* x) |
425 { | 452 { |
426 if(gpCall) { | 453 if(gpCall) { |