Update SIP to 4.19.4

This commit is contained in:
Robin Dunn
2017-11-02 21:13:51 -07:00
parent 0fb1ce987a
commit 666761337b
11 changed files with 1253 additions and 360 deletions

View File

@@ -42,6 +42,12 @@ Changes in this release include the following:
* Fix object ownership issue for menus added to toolbar items. (#580)
* Updated SIP to version 4.19.4. One of the new features of this version is
that integer overflows are no longer silently truncated and ignored. In
other words, if a wrapped API has a parameter that is a C int type, and you
pass a value that is larger than what will fit in that type of integer then
an OverflowError exception will be raised.

View File

@@ -75,12 +75,12 @@ wxICON = 'docs/sphinx/_static/images/sphinxdocs/mondrian.png'
# Some tools will be downloaded for the builds. These are the versions and
# MD5s of the tool binaries currently in use.
sipCurrentVersion = '4.19.2'
sipCurrentVersion = '4.19.4'
sipMD5 = {
'darwin' : '9a1ba6447b05926f8ff58a602bd156ba',
'win32' : 'e358f96f1e10649a62e3657fc599cbb6',
'linux32' : 'd9909d1c12ae758f68c025b644257e20',
'linux64' : '8dc9cd737f9f0a7c1538c0c85ce7120e',
'darwin' : '48490bda534c6dee00e1551e168a5f25',
'win32' : '9970d6e7f65cf03c600d7b0d906db442',
'linux32' : '3551670d779a591708aea5ec2962dae1',
'linux64' : '76459c118ed02a59a392144d2564247f',
}
wafCurrentVersion = '1.7.15-p1'

View File

@@ -632,32 +632,32 @@ static void *get_value(sipArrayObject *array, PyObject *value)
switch (*array->format)
{
case 'b':
static_data.s_char_t = (signed char)SIPLong_AsLong(value);
static_data.s_char_t = sip_api_long_as_char(value);
data = &static_data.s_char_t;
break;
case 'B':
static_data.u_char_t = (unsigned char)sip_api_long_as_unsigned_long(value);
static_data.u_char_t = sip_api_long_as_unsigned_char(value);
data = &static_data.u_char_t;
break;
case 'h':
static_data.s_short_t = (signed short)SIPLong_AsLong(value);
static_data.s_short_t = sip_api_long_as_short(value);
data = &static_data.s_short_t;
break;
case 'H':
static_data.u_short_t = (unsigned short)sip_api_long_as_unsigned_long(value);
static_data.u_short_t = sip_api_long_as_unsigned_short(value);
data = &static_data.u_short_t;
break;
case 'i':
static_data.s_int_t = SIPLong_AsLong(value);
static_data.s_int_t = sip_api_long_as_int(value);
data = &static_data.s_int_t;
break;
case 'I':
static_data.u_int_t = sip_api_long_as_unsigned_long(value);
static_data.u_int_t = sip_api_long_as_unsigned_int(value);
data = &static_data.u_int_t;
break;

368
sip/siplib/int_convertors.c Normal file
View File

@@ -0,0 +1,368 @@
/*
* The implementation of the Python object to C/C++ integer convertors.
*
* Copyright (c) 2017 Riverbank Computing Limited <info@riverbankcomputing.com>
*
* This file is part of SIP.
*
* This copy of SIP is licensed for use under the terms of the SIP License
* Agreement. See the file LICENSE for more details.
*
* This copy of SIP may also used under the terms of the GNU General Public
* License v2 or v3 as published by the Free Software Foundation which can be
* found in the files LICENSE-GPL2 and LICENSE-GPL3 included in this package.
*
* SIP is supplied WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
/*
* NOTES
*
* The legacy integer conversions (ie. without support for overflow checking)
* are flawed and inconsistent. Large Python signed values were converted to
* -1 whereas small values where truncated. When converting function arguments
* all overlows were ignored, however when converting the results returned by
* Python re-implementations then large Python values raised an exception
* whereas small values were truncated.
*
* With the new integer conversions large Python signed values will always
* raise an overflow exception (even if overflow checking is disabled). This
* is because a truncated value is not available - it would have to be
* computed. This may cause new exceptions to be raised but is justified in
* that the value that was being used bore no relation to the original value.
*/
#include <Python.h>
#include <limits.h>
#include "sipint.h"
/* Wrappers to deal with lack of long long support. */
#if defined(HAVE_LONG_LONG)
#define SIPLong_AsLongLong PyLong_AsLongLong
#define SIP_LONG_LONG PY_LONG_LONG
#define SIP_LONG_LONG_FORMAT "%lld"
#define SIP_UNSIGNED_LONG_LONG_FORMAT "%llu"
#else
#define SIPLong_AsLongLong PyLong_AsLong
#define SIP_LONG_LONG long
#define SIP_LONG_LONG_FORMAT "%ld"
#define SIP_UNSIGNED_LONG_LONG_FORMAT "%lu"
#endif
static int overflow_checking = FALSE; /* Check for overflows. */
static SIP_LONG_LONG long_as_long_long(PyObject *o, SIP_LONG_LONG min,
SIP_LONG_LONG max);
static unsigned long long_as_unsigned_long(PyObject *o, unsigned long max);
static void raise_signed_overflow(SIP_LONG_LONG min, SIP_LONG_LONG max);
static void raise_unsigned_overflow(unsigned SIP_LONG_LONG max);
/*
* Enable or disable overflow checking (Python API).
*/
PyObject *sipEnableOverflowChecking(PyObject *self, PyObject *args)
{
int enable;
(void)self;
if (PyArg_ParseTuple(args, "i:enableoverflowchecking", &enable))
{
PyObject *res;
res = (sip_api_enable_overflow_checking(enable) ? Py_True : Py_False);
Py_INCREF(res);
return res;
}
return NULL;
}
/*
* Enable or disable overflow checking (C API).
*/
int sip_api_enable_overflow_checking(int enable)
{
int was_enabled = overflow_checking;
overflow_checking = enable;
return was_enabled;
}
/*
* Convert a Python object to a C++ bool (returned as an int).
*/
int sip_api_convert_to_bool(PyObject *o)
{
int was_enabled, v;
/* Convert the object to an int while checking for overflow. */
was_enabled = sip_api_enable_overflow_checking(TRUE);
v = sip_api_long_as_int(o);
sip_api_enable_overflow_checking(was_enabled);
if (PyErr_Occurred())
{
if (PyErr_ExceptionMatches(PyExc_OverflowError))
{
PyErr_Clear();
/* The value must have been non-zero. */
v = 1;
}
else
{
PyErr_Format(PyExc_TypeError, "a 'bool' is expected not '%s'",
Py_TYPE(o)->tp_name);
v = -1;
}
}
else if (v != 0)
{
v = 1;
}
return v;
}
/*
* Convert a Python object to a C char.
*/
char sip_api_long_as_char(PyObject *o)
{
return (char)long_as_long_long(o, CHAR_MIN, CHAR_MAX);
}
/*
* Convert a Python object to a C signed char.
*/
signed char sip_api_long_as_signed_char(PyObject *o)
{
return (signed char)long_as_long_long(o, SCHAR_MIN, SCHAR_MAX);
}
/*
* Convert a Python object to a C unsigned char.
*/
unsigned char sip_api_long_as_unsigned_char(PyObject *o)
{
return (unsigned char)long_as_unsigned_long(o, UCHAR_MAX);
}
/*
* Convert a Python object to a C short.
*/
short sip_api_long_as_short(PyObject *o)
{
return (short)long_as_long_long(o, SHRT_MIN, SHRT_MAX);
}
/*
* Convert a Python object to a C unsigned short.
*/
unsigned short sip_api_long_as_unsigned_short(PyObject *o)
{
return (unsigned short)long_as_unsigned_long(o, USHRT_MAX);
}
/*
* Convert a Python object to a C int.
*/
int sip_api_long_as_int(PyObject *o)
{
return (int)long_as_long_long(o, INT_MIN, INT_MAX);
}
/*
* Convert a Python object to a C unsigned int.
*/
unsigned sip_api_long_as_unsigned_int(PyObject *o)
{
return (unsigned)long_as_unsigned_long(o, UINT_MAX);
}
/*
* Convert a Python object to a C long.
*/
long sip_api_long_as_long(PyObject *o)
{
return (long)long_as_long_long(o, LONG_MIN, LONG_MAX);
}
/*
* Convert a Python object to a C unsigned long.
*/
unsigned long sip_api_long_as_unsigned_long(PyObject *o)
{
return long_as_unsigned_long(o, ULONG_MAX);
}
#if defined(HAVE_LONG_LONG)
/*
* Convert a Python object to a C long long.
*/
PY_LONG_LONG sip_api_long_as_long_long(PyObject *o)
{
return long_as_long_long(o, LLONG_MIN, LLONG_MAX);
}
/*
* Convert a Python object to a C unsigned long long.
*/
unsigned PY_LONG_LONG sip_api_long_as_unsigned_long_long(PyObject *o)
{
unsigned PY_LONG_LONG value;
PyErr_Clear();
if (overflow_checking)
{
value = PyLong_AsUnsignedLongLong(o);
if (PyErr_Occurred())
{
/* Provide a better exception message. */
if (PyErr_ExceptionMatches(PyExc_OverflowError))
raise_unsigned_overflow(ULLONG_MAX);
}
}
else
{
/*
* Note that this doesn't handle Python v2 int objects, but the old
* convertors didn't either.
*/
value = PyLong_AsUnsignedLongLongMask(o);
}
return value;
}
#endif
/*
* Convert a Python object to a long long checking that the value is within a
* range if overflow checking is enabled.
*/
static SIP_LONG_LONG long_as_long_long(PyObject *o, SIP_LONG_LONG min,
SIP_LONG_LONG max)
{
SIP_LONG_LONG value;
PyErr_Clear();
value = SIPLong_AsLongLong(o);
if (PyErr_Occurred())
{
/* Provide a better exception message. */
if (PyErr_ExceptionMatches(PyExc_OverflowError))
raise_signed_overflow(min, max);
}
else if (overflow_checking && (value < min || value > max))
{
raise_signed_overflow(min, max);
}
return value;
}
/*
* Convert a Python object to an unsigned long checking that the value is
* within a range if overflow checking is enabled.
*/
static unsigned long long_as_unsigned_long(PyObject *o, unsigned long max)
{
unsigned long value;
PyErr_Clear();
if (overflow_checking)
{
value = PyLong_AsUnsignedLong(o);
if (PyErr_Occurred())
{
/* Provide a better exception message. */
if (PyErr_ExceptionMatches(PyExc_OverflowError))
raise_unsigned_overflow(max);
}
else if (value > max)
{
raise_unsigned_overflow(max);
}
}
else
{
#if PY_VERSION_HEX < 0x02040000
/*
* Work around a bug in Python versions prior to v2.4 where an integer
* (or a named enum) causes an error.
*/
if (!PyLong_Check(o) && PyInt_Check(o))
{
long v = PyInt_AsLong(o);
if (v < 0)
{
raise_unsigned_overflow(max);
return (unsigned long)-1;
}
return v;
}
#endif
value = PyLong_AsUnsignedLongMask(o);
}
return value;
}
/*
* Raise an overflow exception if a signed value is out of range.
*/
static void raise_signed_overflow(SIP_LONG_LONG min, SIP_LONG_LONG max)
{
PyErr_Format(PyExc_OverflowError,
"value must be in the range " SIP_LONG_LONG_FORMAT " to " SIP_LONG_LONG_FORMAT,
min, max);
}
/*
* Raise an overflow exception if an unsigned value is out of range.
*/
static void raise_unsigned_overflow(unsigned SIP_LONG_LONG max)
{
PyErr_Format(PyExc_OverflowError,
"value must be in the range 0 to " SIP_UNSIGNED_LONG_LONG_FORMAT,
max);
}

View File

@@ -2,7 +2,7 @@
* This module implements a hash table class for mapping C/C++ addresses to the
* corresponding wrapped Python object.
*
* Copyright (c) 2016 Riverbank Computing Limited <info@riverbankcomputing.com>
* Copyright (c) 2017 Riverbank Computing Limited <info@riverbankcomputing.com>
*
* This file is part of SIP.
*
@@ -282,7 +282,7 @@ static void add_object(sipObjectMap *om, void *addr, sipSimpleWrapper *val)
* stale alias entry from the object map, triggering a
* use-after-free when accessing its C++ object.
*/
sip_api_common_dtor(sw);
sip_api_instance_destroyed(sw);
sipSetNotInMap(sw);
}

View File

@@ -54,8 +54,8 @@ extern "C" {
/*
* Define the SIP version number.
*/
#define SIP_VERSION 0x041302
#define SIP_VERSION_STR "4.19.2"
#define SIP_VERSION 0x041304
#define SIP_VERSION_STR "4.19.4"
/*
@@ -68,6 +68,23 @@ extern "C" {
*
* History:
*
* 12.3 Added SIP_TYPE_SCOPED_ENUM to the sipTypeDef flags.
* Added sip_api_convert_to_enum() to the public API.
* Added sip_api_convert_to_bool() to the public API.
* Added sip_api_long_as_char(), sip_api_long_as_signed_char(),
* sip_api_long_as_unsigned_char(), sip_api_long_as_short(),
* sip_api_long_as_unsigned_short(), sip_api_long_as_int(),
* sip_api_long_as_unsigned_int(), sip_api_long_as_long(),
* sip_api_long_as_unsigned_long(), sip_api_long_as_long_long(),
* sip_api_long_as_unsigned_long_long() to the public API.
* Deprecated sip_api_can_convert_to_enum().
*
* 12.2 Added sip_api_print_object() to the public API.
* Renamed sip_api_common_dtor() to sip_api_instance_destroyed() and added
* it to the public API.
* Added sipEventType and sip_api_register_event_handler() to the public
* API.
*
* 12.1 Added sip_api_enable_gc() to the public API.
*
* 12.0 Added SIP_TYPE_LIMITED_API to the sipTypeDef flags.
@@ -246,7 +263,7 @@ extern "C" {
* 0.0 Original version.
*/
#define SIP_API_MAJOR_NR 12
#define SIP_API_MINOR_NR 1
#define SIP_API_MINOR_NR 3
/* The name of the sip module. */
@@ -413,8 +430,21 @@ typedef struct _sipWrapper sipWrapper;
/*
* Some convenient function pointers.
* The different events a handler can be registered for.
*/
typedef enum
{
sipEventWrappedInstance, /* After wrapping a C/C++ instance. */
sipEventCollectingWrapper, /* When garbage collecting a wrapper object. */
sipEventNrEvents
} sipEventType;
/*
* The event handlers.
*/
typedef void (*sipWrappedInstanceEventHandler)(void *sipCpp);
typedef void (*sipCollectingWrapperEventHandler)(sipSimpleWrapper *sipSelf);
/*
* The operation an access function is being asked to perform.
@@ -426,6 +456,10 @@ typedef enum
ReleaseGuard /* Release the guard, if any. */
} AccessFuncOp;
/*
* Some convenient function pointers.
*/
typedef void *(*sipInitFunc)(sipSimpleWrapper *, PyObject *, PyObject *,
PyObject **, PyObject **, PyObject **);
typedef int (*sipFinalFunc)(PyObject *, void *, PyObject *, PyObject **);
@@ -451,7 +485,7 @@ typedef PyObject *(*sipConvertFromFunc)(void *, PyObject *);
typedef void (*sipVirtErrorHandlerFunc)(sipSimpleWrapper *, sip_gilstate_t);
typedef int (*sipVirtHandlerFunc)(sip_gilstate_t, sipVirtErrorHandlerFunc,
sipSimpleWrapper *, PyObject *, ...);
typedef void (*sipAssignFunc)(void *, SIP_SSIZE_T, const void *);
typedef void (*sipAssignFunc)(void *, SIP_SSIZE_T, void *);
typedef void *(*sipArrayFunc)(SIP_SSIZE_T);
typedef void *(*sipCopyFunc)(const void *, SIP_SSIZE_T);
typedef void (*sipReleaseFunc)(void *, int);
@@ -1637,7 +1671,15 @@ typedef struct _sipAPIDef {
PyObject *transferObj, int flags, int *statep, int *iserrp);
void *(*api_force_convert_to_type)(PyObject *pyObj, const sipTypeDef *td,
PyObject *transferObj, int flags, int *statep, int *iserrp);
/*
* The following are deprecated parts of the public API.
*/
int (*api_can_convert_to_enum)(PyObject *pyObj, const sipTypeDef *td);
/*
* The following are part of the public API.
*/
void (*api_release_type)(void *cpp, const sipTypeDef *td, int state);
PyObject *(*api_convert_from_type)(void *cpp, const sipTypeDef *td,
PyObject *transferObj);
@@ -1723,7 +1765,15 @@ typedef struct _sipAPIDef {
const char *fmt, ...);
int (*api_parse_pair)(PyObject **parseErrp, PyObject *arg0, PyObject *arg1,
const char *fmt, ...);
void (*api_common_dtor)(sipSimpleWrapper *sipSelf);
/*
* The following are part of the public API.
*/
void (*api_instance_destroyed)(sipSimpleWrapper *sipSelf);
/*
* The following are not part of the public API.
*/
void (*api_no_function)(PyObject *parseErr, const char *func,
const char *doc);
void (*api_no_method)(PyObject *parseErr, const char *scope,
@@ -1808,6 +1858,27 @@ typedef struct _sipAPIDef {
* The following are part of the public API.
*/
int (*api_enable_gc)(int enable);
void (*api_print_object)(PyObject *o);
int (*api_register_event_handler)(sipEventType type, const sipTypeDef *td,
void *handler);
int (*api_convert_to_enum)(PyObject *obj, const sipTypeDef *td);
int (*api_convert_to_bool)(PyObject *obj);
int (*api_enable_overflow_checking)(int enable);
char (*api_long_as_char)(PyObject *o);
signed char (*api_long_as_signed_char)(PyObject *o);
unsigned char (*api_long_as_unsigned_char)(PyObject *o);
short (*api_long_as_short)(PyObject *o);
unsigned short (*api_long_as_unsigned_short)(PyObject *o);
int (*api_long_as_int)(PyObject *o);
unsigned int (*api_long_as_unsigned_int)(PyObject *o);
long (*api_long_as_long)(PyObject *o);
#if defined(HAVE_LONG_LONG)
PY_LONG_LONG (*api_long_as_long_long)(PyObject *o);
unsigned PY_LONG_LONG (*api_long_as_unsigned_long_long)(PyObject *o);
#else
void *api_long_as_long_long;
void *api_long_as_unsigned_long_long;
#endif
} sipAPIDef;
@@ -1904,6 +1975,7 @@ typedef struct _sipQtAPI {
#define SIP_TYPE_NAMESPACE 0x0001 /* If the type is a C++ namespace. */
#define SIP_TYPE_MAPPED 0x0002 /* If the type is a mapped type. */
#define SIP_TYPE_ENUM 0x0003 /* If the type is a named enum. */
#define SIP_TYPE_SCOPED_ENUM 0x0004 /* If the type is a scoped enum. */
#define SIP_TYPE_ABSTRACT 0x0008 /* If the type is abstract. */
#define SIP_TYPE_SCC 0x0010 /* If the type is subject to sub-class convertors. */
#define SIP_TYPE_ALLOW_NONE 0x0020 /* If the type can handle None. */
@@ -1920,6 +1992,7 @@ typedef struct _sipQtAPI {
#define sipTypeIsNamespace(td) (((td)->td_flags & SIP_TYPE_TYPE_MASK) == SIP_TYPE_NAMESPACE)
#define sipTypeIsMapped(td) (((td)->td_flags & SIP_TYPE_TYPE_MASK) == SIP_TYPE_MAPPED)
#define sipTypeIsEnum(td) (((td)->td_flags & SIP_TYPE_TYPE_MASK) == SIP_TYPE_ENUM)
#define sipTypeIsScopedEnum(td) (((td)->td_flags & SIP_TYPE_TYPE_MASK) == SIP_TYPE_SCOPED_ENUM)
#define sipTypeAsPyTypeObject(td) ((td)->u.td_py_type)
#define sipTypeName(td) sipNameFromPool((td)->td_module, (td)->td_cname)
#define sipTypePluginData(td) ((td)->td_plugin_data)

View File

@@ -1,7 +1,7 @@
/*
* This file defines the SIP library internal interfaces.
*
* Copyright (c) 2016 Riverbank Computing Limited <info@riverbankcomputing.com>
* Copyright (c) 2017 Riverbank Computing Limited <info@riverbankcomputing.com>
*
* This file is part of SIP.
*
@@ -96,6 +96,27 @@ PyObject *sip_api_convert_from_const_void_ptr_and_size(const void *val,
SIP_SSIZE_T size);
/*
* Support for int convertors.
*/
PyObject *sipEnableOverflowChecking(PyObject *self, PyObject *args);
int sip_api_enable_overflow_checking(int enable);
int sip_api_convert_to_bool(PyObject *o);
char sip_api_long_as_char(PyObject *o);
signed char sip_api_long_as_signed_char(PyObject *o);
unsigned char sip_api_long_as_unsigned_char(PyObject *o);
short sip_api_long_as_short(PyObject *o);
unsigned short sip_api_long_as_unsigned_short(PyObject *o);
int sip_api_long_as_int(PyObject *o);
unsigned int sip_api_long_as_unsigned_int(PyObject *o);
long sip_api_long_as_long(PyObject *o);
unsigned long sip_api_long_as_unsigned_long(PyObject *o);
#if defined(HAVE_LONG_LONG)
PY_LONG_LONG sip_api_long_as_long_long(PyObject *o);
unsigned PY_LONG_LONG sip_api_long_as_unsigned_long_long(PyObject *o);
#endif
extern sipQtAPI *sipQtSupport; /* The Qt support API. */
extern sipWrapperType sipSimpleWrapper_Type; /* The simple wrapper type. */
extern sipTypeDef *sipQObjectType; /* The QObject type. */
@@ -117,12 +138,11 @@ void *sip_api_get_address(sipSimpleWrapper *w);
void *sip_api_get_cpp_ptr(sipSimpleWrapper *w, const sipTypeDef *td);
PyObject *sip_api_convert_from_type(void *cppPtr, const sipTypeDef *td,
PyObject *transferObj);
void sip_api_common_dtor(sipSimpleWrapper *sipSelf);
void sip_api_instance_destroyed(sipSimpleWrapper *sipSelf);
void sip_api_end_thread(void);
void *sip_api_force_convert_to_type(PyObject *pyObj, const sipTypeDef *td,
PyObject *transferObj, int flags, int *statep, int *iserrp);
void sip_api_free_sipslot(sipSlot *slot);
unsigned long sip_api_long_as_unsigned_long(PyObject *o);
int sip_api_same_slot(const sipSlot *sp, PyObject *rxObj, const char *slot);
PyObject *sip_api_invoke_slot(const sipSlot *slot, PyObject *sigargs);
PyObject *sip_api_invoke_slot_ex(const sipSlot *slot, PyObject *sigargs,

File diff suppressed because it is too large Load Diff

View File

@@ -200,9 +200,7 @@ static PyObject *sipVoidPtr_setwriteable(sipVoidPtrObject *v, PyObject *arg)
{
int rw;
rw = (int)SIPLong_AsLong(arg);
if (PyErr_Occurred())
if ((rw = PyObject_IsTrue(arg)) < 0)
return NULL;
v->rw = rw;

28
unittests/test_dtor.py Normal file
View File

@@ -0,0 +1,28 @@
import unittest
from unittests import wtc
import wx
#---------------------------------------------------------------------------
class dtor_Tests(wtc.WidgetTestCase):
def test_dtor(self):
# Test that a __dtor__ method is called when a wrapped C++ class is
# destroyed
class MyPanel(wx.Panel):
def __init__(self, parent):
super(MyPanel, self).__init__(parent)
self.Parent.dtor_called = False
def __dtor__(self):
self.Parent.dtor_called = True
panel = MyPanel(self.frame)
self.myYield()
assert not self.frame.dtor_called
panel.Destroy()
self.myYield()
assert self.frame.dtor_called

View File

@@ -513,6 +513,7 @@ def build(bld):
'sip/siplib/array.c',
'sip/siplib/bool.cpp',
'sip/siplib/descriptors.c',
'sip/siplib/int_convertors.c',
'sip/siplib/objmap.c',
'sip/siplib/qtlib.c',
'sip/siplib/siplib.c',