Bug 891107 - Part 11: Show information about type in cast error messages in js-ctypes. r=jorendorff
☠☠ backed out by 3acdbde976fa ☠ ☠
authorTooru Fujisawa <arai_a@mac.com>
Fri, 07 Aug 2015 06:58:58 +0900
changeset 288416 c1bb74893286a8a73eb76700ea65bd5470b77da8
parent 288415 07d1058b745e603593394ce9465e91669256e4d4
child 288417 905e3a9f755778aacfbf3308ff00e9f2ee22ffb5
push id73418
push userarai_a@mac.com
push dateSat, 12 Mar 2016 17:22:03 +0000
treeherdermozilla-inbound@8db1ac84d30e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjorendorff
bugs891107
milestone48.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 891107 - Part 11: Show information about type in cast error messages in js-ctypes. r=jorendorff
js/src/ctypes/CTypes.cpp
js/src/ctypes/ctypes.msg
js/src/jit-test/tests/ctypes/cast.js
toolkit/components/ctypes/tests/unit/test_jsctypes.js
--- a/js/src/ctypes/CTypes.cpp
+++ b/js/src/ctypes/CTypes.cpp
@@ -1822,16 +1822,65 @@ TypeOverflow(JSContext* cx, const char* 
     return false;
 
   JS_ReportErrorNumber(cx, GetErrorMessage, nullptr,
                        CTYPESMSG_TYPE_OVERFLOW, valStr, expected);
   return false;
 }
 
 static bool
+UndefinedSizeCastError(JSContext* cx, HandleObject targetTypeObj)
+{
+  AutoString targetTypeSource;
+  JSAutoByteString targetTypeBytes;
+  BuildTypeSource(cx, targetTypeObj, true, targetTypeSource);
+  const char* targetTypeStr = EncodeLatin1(cx, targetTypeSource,
+                                           targetTypeBytes);
+  if (!targetTypeStr)
+    return false;
+
+  JS_ReportErrorNumber(cx, GetErrorMessage, nullptr,
+                       CTYPESMSG_UNDEFINED_SIZE_CAST, targetTypeStr);
+  return false;
+}
+
+static bool
+SizeMismatchCastError(JSContext* cx,
+                      HandleObject sourceTypeObj, HandleObject targetTypeObj,
+                      size_t sourceSize, size_t targetSize)
+{
+  AutoString sourceTypeSource;
+  JSAutoByteString sourceTypeBytes;
+  BuildTypeSource(cx, sourceTypeObj, true, sourceTypeSource);
+  const char* sourceTypeStr = EncodeLatin1(cx, sourceTypeSource,
+                                           sourceTypeBytes);
+  if (!sourceTypeStr)
+    return false;
+
+  AutoString targetTypeSource;
+  JSAutoByteString targetTypeBytes;
+  BuildTypeSource(cx, targetTypeObj, true, targetTypeSource);
+  const char* targetTypeStr = EncodeLatin1(cx, targetTypeSource,
+                                           targetTypeBytes);
+  if (!targetTypeStr)
+    return false;
+
+  char sourceSizeStr[16];
+  char targetSizeStr[16];
+  JS_snprintf(sourceSizeStr, 16, "%u", sourceSize);
+  JS_snprintf(targetSizeStr, 16, "%u", targetSize);
+
+  JS_ReportErrorNumber(cx, GetErrorMessage, nullptr,
+                       CTYPESMSG_SIZE_MISMATCH_CAST,
+                       targetTypeStr, sourceTypeStr,
+                       targetSizeStr, sourceSizeStr);
+  return false;
+}
+
+static bool
 UndefinedSizePointerError(JSContext* cx, const char* action, HandleObject obj)
 {
   JSAutoByteString valBytes;
   RootedValue val(cx, ObjectValue(*obj));
   const char* valStr = CTypesToSourceForError(cx, val, valBytes);
   if (!valStr)
     return false;
 
@@ -7661,29 +7710,30 @@ CData::Cast(JSContext* cx, unsigned argc
   if (args.length() != 2) {
     return ArgumentLengthError(cx, "ctypes.cast", "two", "s");
   }
 
   if (args[0].isPrimitive() || !CData::IsCData(&args[0].toObject())) {
     return ArgumentTypeMismatch(cx, "first ", "ctypes.cast", "a CData");
   }
   RootedObject sourceData(cx, &args[0].toObject());
-  JSObject* sourceType = CData::GetCType(sourceData);
+  RootedObject sourceType(cx, CData::GetCType(sourceData));
 
   if (args[1].isPrimitive() || !CType::IsCType(&args[1].toObject())) {
     return ArgumentTypeMismatch(cx, "second ", "ctypes.cast", "a CType");
   }
 
   RootedObject targetType(cx, &args[1].toObject());
   size_t targetSize;
-  if (!CType::GetSafeSize(targetType, &targetSize) ||
-      targetSize > CType::GetSize(sourceType)) {
-    JS_ReportError(cx,
-      "target CType has undefined or larger size than source CType");
-    return false;
+  if (!CType::GetSafeSize(targetType, &targetSize)) {
+    return UndefinedSizeCastError(cx, targetType);
+  }
+  if (targetSize > CType::GetSize(sourceType)) {
+    return SizeMismatchCastError(cx, sourceType, targetType,
+                                 CType::GetSize(sourceType), targetSize);
   }
 
   // Construct a new CData object with a type of 'targetType' and a referent
   // of 'sourceData'.
   void* data = CData::GetData(sourceData);
   JSObject* result = CData::Create(cx, targetType, sourceData, data, false);
   if (!result)
     return false;
--- a/js/src/ctypes/ctypes.msg
+++ b/js/src/ctypes/ctypes.msg
@@ -65,8 +65,12 @@ MSG_DEF(CTYPESMSG_VARG_TYPE_ERROR,2, JSE
 
 /* ctype */
 MSG_DEF(CTYPESMSG_CANNOT_CONSTRUCT,1, JSEXN_TYPEERR, "cannot construct from {0}")
 
 /* pointer */
 MSG_DEF(CTYPESMSG_UNDEFINED_SIZE,2, JSEXN_TYPEERR, "cannot {0} pointer of undefined size {1}")
 MSG_DEF(CTYPESMSG_NULL_POINTER,  2, JSEXN_TYPEERR, "cannot {0} null pointer {1}")
 MSG_DEF(CTYPESMSG_NON_STRING_BASE,1, JSEXN_TYPEERR, "base type {0} is not an 8-bit or 16-bit integer or character type")
+
+/* cast */
+MSG_DEF(CTYPESMSG_UNDEFINED_SIZE_CAST,1, JSEXN_TYPEERR, "target type {0} has undefined size")
+MSG_DEF(CTYPESMSG_SIZE_MISMATCH_CAST,4, JSEXN_TYPEERR, "target type {0} has larger size than source type {1} ({2} > {3})")
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ctypes/cast.js
@@ -0,0 +1,12 @@
+load(libdir + 'asserts.js');
+
+function test() {
+  assertTypeErrorMessage(() => { ctypes.cast(ctypes.int32_t(0), ctypes.StructType("foo")); },
+                         "target type foo has undefined size");
+
+  assertTypeErrorMessage(() => { ctypes.cast(ctypes.int32_t(0), ctypes.StructType("foo", [ { x: ctypes.int32_t }, { y: ctypes.int32_t } ])); },
+                         "target type foo has larger size than source type ctypes.int32_t (8 > 4)");
+}
+
+if (typeof ctypes === "object")
+  test();
--- a/toolkit/components/ctypes/tests/unit/test_jsctypes.js
+++ b/toolkit/components/ctypes/tests/unit/test_jsctypes.js
@@ -2199,19 +2199,19 @@ function run_cast_tests() {
   let j = ctypes.cast(i, ctypes.int16_t);
   do_check_eq(ptrValue(i.address()), ptrValue(j.address()));
   do_check_eq(i.value, j.value);
   let k = ctypes.cast(i, ctypes.uint32_t);
   do_check_eq(ptrValue(i.address()), ptrValue(k.address()));
   do_check_eq(i.value, k.value);
 
   // Test casting to a type of undefined or larger size.
-  do_check_throws(function() { ctypes.cast(i, ctypes.void_t); }, Error);
-  do_check_throws(function() { ctypes.cast(i, ctypes.int32_t.array()); }, Error);
-  do_check_throws(function() { ctypes.cast(i, ctypes.int64_t); }, Error);
+  do_check_throws(function() { ctypes.cast(i, ctypes.void_t); }, TypeError);
+  do_check_throws(function() { ctypes.cast(i, ctypes.int32_t.array()); }, TypeError);
+  do_check_throws(function() { ctypes.cast(i, ctypes.int64_t); }, TypeError);
 
   // Test casting between special types.
   let g_t = ctypes.StructType("g_t", [{ a: ctypes.int32_t }, { b: ctypes.double }]);
   let a_t = ctypes.ArrayType(g_t, 4);
   let p_t = ctypes.PointerType(g_t);
   let f_t = ctypes.FunctionType(ctypes.default_abi, ctypes.void_t).ptr;
 
   let a = a_t();