mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-10 11:55:49 +00:00
Improve ctypes error handling per review comments.
This commit is contained in:
parent
6b434c4683
commit
323f802805
@ -98,10 +98,38 @@ jsvalToDoubleStrict(jsval aValue, jsdouble *dp)
|
||||
return false;
|
||||
}
|
||||
|
||||
static nsresult
|
||||
TypeError(JSContext *cx, const char *message)
|
||||
JSErrorFormatString ErrorFormatString[CTYPESERR_LIMIT] = {
|
||||
#define MSG_DEF(name, number, count, exception, format) \
|
||||
{ format, count, exception } ,
|
||||
#include "ctypes.msg"
|
||||
#undef MSG_DEF
|
||||
};
|
||||
|
||||
const JSErrorFormatString*
|
||||
GetErrorMessage(void* userRef, const char* locale, const uintN errorNumber)
|
||||
{
|
||||
JS_ReportError(cx, "%s", message);
|
||||
if (0 < errorNumber && errorNumber < CTYPESERR_LIMIT)
|
||||
return &ErrorFormatString[errorNumber];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char*
|
||||
ToSource(JSContext* cx, jsval vp)
|
||||
{
|
||||
JSString* str = JS_ValueToSource(cx, vp);
|
||||
if (str)
|
||||
return JS_GetStringBytes(str);
|
||||
|
||||
JS_ClearPendingException(cx);
|
||||
return "<<error converting value to string>>";
|
||||
}
|
||||
|
||||
static nsresult
|
||||
TypeError(JSContext* cx, const char* expected, jsval actual)
|
||||
{
|
||||
const char* src = ToSource(cx, actual);
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, NULL,
|
||||
CTYPESMSG_TYPE_ERROR, expected, src);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
@ -196,67 +224,67 @@ PrepareValue(JSContext* aContext, const Type& aType, jsval aValue, Value& aResul
|
||||
// Programs can convert explicitly, if needed, using `Boolean(v)` or `!!v`.
|
||||
if (!jsvalToIntStrict(aValue, &aResult.mValue.mUint8) ||
|
||||
aResult.mValue.mUint8 > 1)
|
||||
return TypeError(aContext, "Expected boolean value");
|
||||
return TypeError(aContext, "boolean", aValue);
|
||||
|
||||
aResult.mData = &aResult.mValue.mUint8;
|
||||
break;
|
||||
case nsIForeignLibrary::INT8:
|
||||
// Do not implicitly lose bits.
|
||||
if (!jsvalToIntStrict(aValue, &aResult.mValue.mInt8))
|
||||
return TypeError(aContext, "Expected int8 value");
|
||||
return TypeError(aContext, "int8", aValue);
|
||||
|
||||
aResult.mData = &aResult.mValue.mInt8;
|
||||
break;
|
||||
case nsIForeignLibrary::INT16:
|
||||
// Do not implicitly lose bits.
|
||||
if (!jsvalToIntStrict(aValue, &aResult.mValue.mInt16))
|
||||
return TypeError(aContext, "Expected int16 value");
|
||||
return TypeError(aContext, "int16", aValue);
|
||||
|
||||
aResult.mData = &aResult.mValue.mInt16;
|
||||
break;
|
||||
case nsIForeignLibrary::INT32:
|
||||
// Do not implicitly lose bits.
|
||||
if (!jsvalToIntStrict(aValue, &aResult.mValue.mInt32))
|
||||
return TypeError(aContext, "Expected int32 value");
|
||||
return TypeError(aContext, "int32", aValue);
|
||||
|
||||
aResult.mData = &aResult.mValue.mInt32;
|
||||
case nsIForeignLibrary::INT64:
|
||||
// Do not implicitly lose bits.
|
||||
if (!jsvalToIntStrict(aValue, &aResult.mValue.mInt64))
|
||||
return TypeError(aContext, "Expected int64 value");
|
||||
return TypeError(aContext, "int64", aValue);
|
||||
|
||||
aResult.mData = &aResult.mValue.mInt64;
|
||||
break;
|
||||
case nsIForeignLibrary::UINT8:
|
||||
// Do not implicitly lose bits.
|
||||
if (!jsvalToIntStrict(aValue, &aResult.mValue.mUint8))
|
||||
return TypeError(aContext, "Expected uint8 value");
|
||||
return TypeError(aContext, "uint8", aValue);
|
||||
|
||||
aResult.mData = &aResult.mValue.mUint8;
|
||||
break;
|
||||
case nsIForeignLibrary::UINT16:
|
||||
// Do not implicitly lose bits.
|
||||
if (!jsvalToIntStrict(aValue, &aResult.mValue.mUint16))
|
||||
return TypeError(aContext, "Expected uint16 value");
|
||||
return TypeError(aContext, "uint16", aValue);
|
||||
|
||||
aResult.mData = &aResult.mValue.mUint16;
|
||||
break;
|
||||
case nsIForeignLibrary::UINT32:
|
||||
// Do not implicitly lose bits.
|
||||
if (!jsvalToIntStrict(aValue, &aResult.mValue.mUint32))
|
||||
return TypeError(aContext, "Expected uint32 value");
|
||||
return TypeError(aContext, "uint32", aValue);
|
||||
|
||||
aResult.mData = &aResult.mValue.mUint32;
|
||||
case nsIForeignLibrary::UINT64:
|
||||
// Do not implicitly lose bits.
|
||||
if (!jsvalToIntStrict(aValue, &aResult.mValue.mUint64))
|
||||
return TypeError(aContext, "Expected uint64 value");
|
||||
return TypeError(aContext, "uint64", aValue);
|
||||
|
||||
aResult.mData = &aResult.mValue.mUint64;
|
||||
break;
|
||||
case nsIForeignLibrary::FLOAT:
|
||||
if (!jsvalToDoubleStrict(aValue, &d))
|
||||
return TypeError(aContext, "Expected number");
|
||||
return TypeError(aContext, "float", aValue);
|
||||
|
||||
// The following cast silently throws away some bits, but there's
|
||||
// no good way around it. Sternly requiring that the 64-bit double
|
||||
@ -267,7 +295,7 @@ PrepareValue(JSContext* aContext, const Type& aType, jsval aValue, Value& aResul
|
||||
break;
|
||||
case nsIForeignLibrary::DOUBLE:
|
||||
if (!jsvalToDoubleStrict(aValue, &d))
|
||||
return TypeError(aContext, "Expected number");
|
||||
return TypeError(aContext, "double", aValue);
|
||||
|
||||
aResult.mValue.mDouble = d;
|
||||
aResult.mData = &aResult.mValue.mDouble;
|
||||
@ -281,7 +309,7 @@ PrepareValue(JSContext* aContext, const Type& aType, jsval aValue, Value& aResul
|
||||
} else {
|
||||
// Don't implicitly convert to string. Users can implicitly convert
|
||||
// with `String(x)` or `""+x`.
|
||||
return TypeError(aContext, "Expected string");
|
||||
return TypeError(aContext, "string", aValue);
|
||||
}
|
||||
|
||||
aResult.mData = &aResult.mValue.mPointer;
|
||||
@ -295,7 +323,7 @@ PrepareValue(JSContext* aContext, const Type& aType, jsval aValue, Value& aResul
|
||||
} else {
|
||||
// Don't implicitly convert to string. Users can implicitly convert
|
||||
// with `String(x)` or `""+x`.
|
||||
return TypeError(aContext, "Expected string");
|
||||
return TypeError(aContext, "ustring", aValue);
|
||||
}
|
||||
|
||||
aResult.mData = &aResult.mValue.mPointer;
|
||||
@ -488,8 +516,10 @@ Function::Init(JSContext* aContext,
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// disallow void argument types
|
||||
if (mArgTypes[i].mType == nsIForeignLibrary::VOID)
|
||||
return TypeError(aContext, "Cannot have void argument type");
|
||||
if (mArgTypes[i].mType == nsIForeignLibrary::VOID) {
|
||||
JS_ReportError(aContext, "Cannot have void argument type");
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
// ffi_prep_cif requires an array of ffi_types; prepare it separately.
|
||||
mFFITypes.AppendElement(&mArgTypes[i].mFFIType);
|
||||
|
@ -51,6 +51,18 @@
|
||||
namespace mozilla {
|
||||
namespace ctypes {
|
||||
|
||||
// for JS error reporting
|
||||
enum ErrorNum {
|
||||
#define MSG_DEF(name, number, count, exception, format) \
|
||||
name = number,
|
||||
#include "ctypes.msg"
|
||||
#undef MSG_DEF
|
||||
CTYPESERR_LIMIT
|
||||
};
|
||||
|
||||
const JSErrorFormatString*
|
||||
GetErrorMessage(void* userRef, const char* locale, const uintN errorNumber);
|
||||
|
||||
struct Type
|
||||
{
|
||||
ffi_type mFFIType;
|
||||
|
@ -60,7 +60,7 @@ jsvalToUint16(JSContext* aContext, jsval aVal, PRUint16& aResult)
|
||||
}
|
||||
}
|
||||
|
||||
JS_ReportError(aContext, "Parameter must be an integer");
|
||||
JS_ReportError(aContext, "Parameter must be a valid ABI constant");
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
|
52
js/ctypes/ctypes.msg
Normal file
52
js/ctypes/ctypes.msg
Normal file
@ -0,0 +1,52 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is js-ctypes.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* The Mozilla Foundation <http://www.mozilla.org/>.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Dan Witte <dwitte@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/*
|
||||
* This is the jsctypes error message file.
|
||||
*
|
||||
* For syntax details, see js/src/js.msg.
|
||||
*/
|
||||
|
||||
MSG_DEF(CTYPESMSG_PLACEHOLDER_0, 0, 0, JSEXN_NONE, NULL)
|
||||
MSG_DEF(CTYPESMSG_PLACEHOLDER_1, 1, 0, JSEXN_NONE, NULL)
|
||||
MSG_DEF(CTYPESMSG_PLACEHOLDER_2, 2, 0, JSEXN_NONE, NULL)
|
||||
|
||||
// This error has to be number 3 in order to be a TypeError,
|
||||
// due to a bug in the js engine.
|
||||
MSG_DEF(CTYPESMSG_TYPE_ERROR, 3, 2, JSEXN_TYPEERR, "expected type {0}, got {1}")
|
||||
|
@ -114,7 +114,7 @@ function run_short_tests(library) {
|
||||
{toString: function () { return 7; }},
|
||||
{valueOf: function () { return 7; }}];
|
||||
for (var i = 0; i < vals.length; i++)
|
||||
do_check_throws(function () { test_s_s(vals[i]); }, Error);
|
||||
do_check_throws(function () { test_s_s(vals[i]); }, TypeError);
|
||||
|
||||
var test_s_ss = library.declare("test_s_ss", Types.DEFAULT, Types.INT16, Types.INT16, Types.INT16);
|
||||
do_check_eq(test_s_ss(5, 5), 10);
|
||||
@ -123,8 +123,8 @@ function run_short_tests(library) {
|
||||
// here, since it's binary-compatible.)
|
||||
var test_us_us = library.declare("test_s_s", Types.DEFAULT, Types.UINT16, Types.UINT16);
|
||||
do_check_eq(test_us_us(0xffff), 0xffff);
|
||||
do_check_throws(function () { test_us_us(0x10000); }, Error);
|
||||
do_check_throws(function () { test_us_us(-1); }, Error);
|
||||
do_check_throws(function () { test_us_us(0x10000); }, TypeError);
|
||||
do_check_throws(function () { test_us_us(-1); }, TypeError);
|
||||
}
|
||||
|
||||
function run_int_tests(library) {
|
||||
@ -146,7 +146,7 @@ function run_int_tests(library) {
|
||||
{toString: function () { return 7; }},
|
||||
{valueOf: function () { return 7; }}];
|
||||
for (var i = 0; i < vals.length; i++)
|
||||
do_check_throws(function () { test_i_i(vals[i]); }, Error);
|
||||
do_check_throws(function () { test_i_i(vals[i]); }, TypeError);
|
||||
|
||||
var test_i_ii = library.declare("test_i_ii", Types.DEFAULT, Types.INT32, Types.INT32, Types.INT32);
|
||||
do_check_eq(test_i_ii(5, 5), 10);
|
||||
@ -155,8 +155,8 @@ function run_int_tests(library) {
|
||||
// here, since it's binary-compatible.)
|
||||
var test_ui_ui = library.declare("test_i_i", Types.DEFAULT, Types.UINT32, Types.UINT32);
|
||||
do_check_eq(test_ui_ui(0xffffffff), 0xffffffff);
|
||||
do_check_throws(function () { test_ui_ui(0x100000000); }, Error);
|
||||
do_check_throws(function () { test_ui_ui(-1); }, Error);
|
||||
do_check_throws(function () { test_ui_ui(0x100000000); }, TypeError);
|
||||
do_check_throws(function () { test_ui_ui(-1); }, TypeError);
|
||||
}
|
||||
|
||||
function run_float_tests(library) {
|
||||
@ -179,7 +179,7 @@ function run_float_tests(library) {
|
||||
{toString: function () { return 7; }},
|
||||
{valueOf: function () { return 7; }}];
|
||||
for (var i = 0; i < vals.length; i++)
|
||||
do_check_throws(function () { test_d_d(vals[i]); }, Error);
|
||||
do_check_throws(function () { test_f_f(vals[i]); }, TypeError);
|
||||
|
||||
var test_f_ff = library.declare("test_f_ff", Types.DEFAULT, Types.FLOAT, Types.FLOAT, Types.FLOAT);
|
||||
do_check_eq(test_f_ff(5, 5), 10);
|
||||
@ -203,7 +203,7 @@ function run_double_tests(library) {
|
||||
{toString: function () { return 7; }},
|
||||
{valueOf: function () { return 7; }}];
|
||||
for (var i = 0; i < vals.length; i++)
|
||||
do_check_throws(function () { test_d_d(vals[i]); }, Error);
|
||||
do_check_throws(function () { test_d_d(vals[i]); }, TypeError);
|
||||
|
||||
var test_d_dd = library.declare("test_d_dd", Types.DEFAULT, Types.DOUBLE, Types.DOUBLE, Types.DOUBLE);
|
||||
do_check_eq(test_d_dd(5, 5), 10);
|
||||
@ -218,7 +218,7 @@ function run_string_tests(library) {
|
||||
// don't convert anything else to a string
|
||||
var vals = [true, 0, 1/3, undefined, {}, {toString: function () { return "bad"; }}, []];
|
||||
for (var i = 0; i < vals.length; i++)
|
||||
do_check_throws(function() { test_ansi_len(vals[i]); }, Error);
|
||||
do_check_throws(function() { test_ansi_len(vals[i]); }, TypeError);
|
||||
|
||||
var test_wide_len = library.declare("test_wide_len", Types.DEFAULT, Types.INT32, Types.USTRING);
|
||||
do_check_eq(test_wide_len("hello world"), 11);
|
||||
@ -237,6 +237,6 @@ function run_string_tests(library) {
|
||||
function run_mixed_tests(library) {
|
||||
var test_i_if_floor = library.declare("test_i_if_floor", Types.DEFAULT, Types.INT32, Types.INT32, Types.FLOAT);
|
||||
do_check_eq(test_i_if_floor(5, 5.5), 10);
|
||||
do_check_throws(function() { test_i_if_floor(5.5, 5); }, Error);
|
||||
do_check_throws(function() { test_i_if_floor(5.5, 5); }, TypeError);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user