Browse Source

Proper overflow checking for numeric chars

rdb 10 years ago
parent
commit
5913546229

+ 21 - 6
dtool/src/interrogate/interfaceMakerPythonNative.cxx

@@ -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";

+ 34 - 0
dtool/src/interrogate/typeManager.cxx

@@ -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

+ 1 - 0
dtool/src/interrogate/typeManager.h

@@ -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);