Proper overflow checking for numeric chars

This commit is contained in:
rdb 2015-07-08 02:03:24 +02:00
parent 342b9a8db8
commit 5913546229
3 changed files with 56 additions and 6 deletions

View File

@ -4929,7 +4929,9 @@ write_function_instance(ostream &out, FunctionRemap *remap,
expected_params += "long";
only_pyobjects = false;
} else if (TypeManager::is_unsigned_short(type)) {
} else if (TypeManager::is_unsigned_short(type) ||
TypeManager::is_unsigned_char(type) || TypeManager::is_signed_char(type)) {
if (args_type == AT_single_arg) {
type_check = "PyLongOrInt_Check(arg)";
extra_convert
@ -4945,12 +4947,25 @@ write_function_instance(ostream &out, FunctionRemap *remap,
// The "H" format code, unlike "h", does not do overflow checking, so
// we have to do it ourselves (except in release builds).
extra_convert
<< "#ifndef NDEBUG\n"
<< "if (" << param_name << " < 0 || " << param_name << " > USHRT_MAX) {\n";
<< "#ifndef NDEBUG\n";
if (TypeManager::is_unsigned_short(type)) {
extra_convert << "if (" << param_name << " < 0 || " << param_name << " > USHRT_MAX) {\n";
error_raise_return(extra_convert, 2, return_flags, "OverflowError",
"value %ld out of range for unsigned short integer",
param_name);
} else if (TypeManager::is_unsigned_char(type)) {
extra_convert << "if (" << param_name << " < 0 || " << param_name << " > UCHAR_MAX) {\n";
error_raise_return(extra_convert, 2, return_flags, "OverflowError",
"value %ld out of range for unsigned byte",
param_name);
} else {
extra_convert << "if (" << param_name << " < CHAR_MIN || " << param_name << " > CHAR_MAX) {\n";
error_raise_return(extra_convert, 2, return_flags, "OverflowError",
"value %ld out of range for signed byte",
param_name);
}
error_raise_return(extra_convert, 2, return_flags, "OverflowError",
"value %ld out of range for unsigned short integer",
param_name);
extra_convert
<< "}\n"
<< "#endif\n";

View File

@ -638,6 +638,40 @@ is_unsigned_char(CPPType *type) {
return false;
}
////////////////////////////////////////////////////////////////////
// Function: TypeManager::is_signed_char
// Access: Public, Static
// Description: Returns true if the indicated type is signed char,
// but not unsigned or 'plain' char.
////////////////////////////////////////////////////////////////////
bool TypeManager::
is_signed_char(CPPType *type) {
switch (type->get_subtype()) {
case CPPDeclaration::ST_const:
return is_signed_char(type->as_const_type()->_wrapped_around);
case CPPDeclaration::ST_simple:
{
CPPSimpleType *simple_type = type->as_simple_type();
if (simple_type != (CPPSimpleType *)NULL) {
return
(simple_type->_type == CPPSimpleType::T_char) &&
(simple_type->_flags & CPPSimpleType::F_signed) != 0;
}
}
break;
case CPPDeclaration::ST_typedef:
return is_signed_char(type->as_typedef_type()->_type);
default:
break;
}
return false;
}
////////////////////////////////////////////////////////////////////
// Function: TypeManager::is_char_pointer
// Access: Public, Static

View File

@ -67,6 +67,7 @@ public:
static bool is_pointable(CPPType *type);
static bool is_char(CPPType *type);
static bool is_unsigned_char(CPPType *type);
static bool is_signed_char(CPPType *type);
static bool is_char_pointer(CPPType *type);
static bool is_const_char_pointer(CPPType *type);
static bool is_unsigned_char_pointer(CPPType *type);