зеркало из https://github.com/mozilla/gecko-dev.git
Bug 513788 - Revise js-facing API for js-ctypes. Followup to implement array and struct size overflow
tests. r=jorendorff
This commit is contained in:
Родитель
6708ab2dd9
Коммит
220630dc47
|
@ -244,6 +244,12 @@ NewUCString(JSContext* cx, const nsString& from)
|
|||
reinterpret_cast<const jschar*>(from.get()), from.Length());
|
||||
}
|
||||
|
||||
JS_ALWAYS_INLINE size_t
|
||||
Align(size_t val, size_t align)
|
||||
{
|
||||
return ((val - 1) | (align - 1)) + 1;
|
||||
}
|
||||
|
||||
ABICode
|
||||
GetABICode(JSContext* cx, JSObject* obj)
|
||||
{
|
||||
|
@ -2038,6 +2044,11 @@ CType::Create(JSContext* cx,
|
|||
!JS_SealObject(cx, typeObj, JS_FALSE))
|
||||
return NULL;
|
||||
|
||||
// Assert a sanity check on size and alignment: size % alignment should always
|
||||
// be zero.
|
||||
JS_ASSERT_IF(IsSizeDefined(cx, typeObj),
|
||||
GetSize(cx, typeObj) % GetAlignment(cx, typeObj) == 0);
|
||||
|
||||
return typeObj;
|
||||
}
|
||||
|
||||
|
@ -3279,26 +3290,28 @@ StructType::Create(JSContext* cx, uintN argc, jsval* vp)
|
|||
|
||||
size_t fieldSize = CType::GetSize(cx, info->mType);
|
||||
size_t fieldAlign = CType::GetAlignment(cx, info->mType);
|
||||
size_t padding = (fieldAlign - structSize % fieldAlign) % fieldAlign;
|
||||
if (structSize + padding < structSize ||
|
||||
structSize + padding + fieldSize < structSize) {
|
||||
size_t fieldOffset = Align(structSize, fieldAlign);
|
||||
// Check for overflow. Since we hold invariant that fieldSize % fieldAlign
|
||||
// be zero, we can safely check fieldOffset + fieldSize without first
|
||||
// checking fieldOffset for overflow.
|
||||
if (fieldOffset + fieldSize < structSize) {
|
||||
JS_ReportError(cx, "size overflow");
|
||||
return JS_FALSE;
|
||||
}
|
||||
info->mOffset = structSize + padding;
|
||||
structSize = structSize + padding + fieldSize;
|
||||
info->mOffset = fieldOffset;
|
||||
structSize = fieldOffset + fieldSize;
|
||||
|
||||
if (fieldAlign > structAlign)
|
||||
structAlign = fieldAlign;
|
||||
}
|
||||
|
||||
// Pad the struct tail according to struct alignment.
|
||||
size_t delta = (structAlign - structSize % structAlign) % structAlign;
|
||||
if (structSize + delta < structSize) {
|
||||
size_t structTail = Align(structSize, structAlign);
|
||||
if (structTail < structSize) {
|
||||
JS_ReportError(cx, "size overflow");
|
||||
return JS_FALSE;
|
||||
}
|
||||
structSize = structSize + delta;
|
||||
structSize = structTail;
|
||||
|
||||
} else {
|
||||
// Empty structs are illegal in C, but are legal and have a size of
|
||||
|
|
|
@ -1143,15 +1143,6 @@ function run_jschar_tests(library, t, name, limits) {
|
|||
18 ] ]);
|
||||
}
|
||||
|
||||
function extreme_size()
|
||||
{
|
||||
// Return something larger than the largest representable size value,
|
||||
// depending on platform. (Sizes must fit in both size_t and jsdouble.)
|
||||
return ctypes.size_t.size == 4 ?
|
||||
0x800000000 :
|
||||
ctypes.UInt64("0xffffffffffffffff")
|
||||
}
|
||||
|
||||
function run_StructType_tests() {
|
||||
do_check_throws(function() { ctypes.StructType(); }, Error);
|
||||
do_check_throws(function() { ctypes.StructType("a"); }, Error);
|
||||
|
@ -1223,6 +1214,76 @@ function run_StructType_tests() {
|
|||
do_check_throws(function() { t_t.fields[4].a = 0; }, Error);
|
||||
do_check_throws(function() { t_t.fields[4].e = 0; }, Error);
|
||||
|
||||
// Check that struct size bounds work, and that large, but not illegal, sizes
|
||||
// are OK. This gets tricky. The type constructor needs to allocate 'n'
|
||||
// fields for the type descriptor, so we have to build up structs of structs
|
||||
// to avoid trying to allocate an insane size.
|
||||
if (ctypes.size_t.size == 4) {
|
||||
// Test 1: overflow struct size + field padding + field size.
|
||||
let large_t = ctypes.int8_t;
|
||||
while (large_t.size != 0xffffffff)
|
||||
large_t = ctypes.StructType("large_t",
|
||||
[{"a": large_t.array(2)}, {"b": ctypes.int8_t}]);
|
||||
do_check_throws(function() {
|
||||
ctypes.StructType("large_t", [{"a": large_t}, {"b": ctypes.int8_t}]);
|
||||
}, Error);
|
||||
|
||||
// Test 2: overflow struct size + struct tail padding.
|
||||
// To do this, we use a struct with maximum size and alignment 2.
|
||||
large_t = ctypes.int16_t;
|
||||
while (large_t.size != 0xfffffffe)
|
||||
large_t = ctypes.StructType("large_t",
|
||||
[{"a": large_t.array(2)}, {"b": ctypes.int16_t}]);
|
||||
do_check_throws(function() {
|
||||
ctypes.StructType("large_t", [{"a": large_t}, {"b": ctypes.int8_t}]);
|
||||
}, Error);
|
||||
|
||||
} else {
|
||||
// Test 1: overflow struct size when converting from size_t to jsdouble.
|
||||
let small_t = ctypes.int8_t.array(0x800);
|
||||
let large_t = small_t;
|
||||
while (large_t.size != 0xfffffffffffff800)
|
||||
large_t = ctypes.StructType("large_t",
|
||||
[{"a": large_t.array(2)}, {"b": small_t}]);
|
||||
do_check_throws(function() {
|
||||
ctypes.StructType("large_t", [{"a": large_t}, {"b": ctypes.int8_t}]);
|
||||
}, Error);
|
||||
small_t = ctypes.int8_t.array(0x400);
|
||||
do_check_throws(function() {
|
||||
ctypes.StructType("large_t", [{"a": large_t}, {"b": small_t}]);
|
||||
}, Error);
|
||||
|
||||
large_t = ctypes.int8_t;
|
||||
while (large_t.size != 0x1fffffffffffff)
|
||||
large_t = ctypes.StructType("large_t",
|
||||
[{"a": large_t.array(2)}, {"b": ctypes.int8_t}]);
|
||||
do_check_throws(function() {
|
||||
ctypes.StructType("large_t", [{"a": large_t.array(2)}, {"b": ctypes.int8_t}]);
|
||||
}, Error);
|
||||
|
||||
// Test 2: overflow struct size + field padding + field size.
|
||||
small_t = ctypes.int8_t.array(0x800);
|
||||
large_t = small_t;
|
||||
while (large_t.size != 0xfffffffffffff800)
|
||||
large_t = ctypes.StructType("large_t",
|
||||
[{"a": large_t.array(2)}, {"b": small_t}]);
|
||||
do_check_throws(function() {
|
||||
ctypes.StructType("large_t", [{"a": large_t}, {"b": small_t}]);
|
||||
}, Error);
|
||||
|
||||
// Test 3: overflow struct size + struct tail padding.
|
||||
// To do this, we use a struct with maximum size and alignment 2.
|
||||
small_t = ctypes.int16_t.array(0x800);
|
||||
large_t = small_t;
|
||||
while (large_t.size != 0xfffffffffffff000)
|
||||
large_t = ctypes.StructType("large_t",
|
||||
[{"a": large_t.array(2)}, {"b": small_t}]);
|
||||
small_t = ctypes.int8_t.array(0xfff);
|
||||
do_check_throws(function() {
|
||||
ctypes.StructType("large_t", [{"a": large_t}, {"b": small_t}]);
|
||||
}, Error);
|
||||
}
|
||||
|
||||
let g = g_t();
|
||||
do_check_eq(g.a, 0);
|
||||
do_check_eq(g.b, 0);
|
||||
|
@ -1431,11 +1492,6 @@ function run_ArrayType_tests() {
|
|||
do_check_throws(function() { ctypes.ArrayType(ctypes.int32_t, 1, 5); }, Error);
|
||||
do_check_throws(function() { ctypes.ArrayType(ctypes.int32_t, -1); }, Error);
|
||||
|
||||
// Check that array size overflows are caught.
|
||||
do_check_throws(function() {
|
||||
ctypes.ArrayType(ctypes.int8_t, extreme_size());
|
||||
}, Error);
|
||||
|
||||
let name = "g_t";
|
||||
let g_t = ctypes.StructType(name, [{ a: ctypes.int32_t }, { b: ctypes.double }]);
|
||||
let g = g_t(1, 2);
|
||||
|
@ -1501,18 +1557,40 @@ function run_ArrayType_tests() {
|
|||
do_check_throws(function() { ctypes.ArrayType(ctypes.ArrayType(g_t)); }, Error);
|
||||
do_check_throws(function() { ctypes.ArrayType(ctypes.ArrayType(g_t), 5); }, Error);
|
||||
|
||||
let b_t = ctypes.int32_t.array(ctypes.UInt64(0xffff));
|
||||
let b_t = ctypes.int8_t.array(ctypes.UInt64(0xffff));
|
||||
do_check_eq(b_t.length, 0xffff);
|
||||
b_t = ctypes.int32_t.array(ctypes.Int64(0xffff));
|
||||
b_t = ctypes.int8_t.array(ctypes.Int64(0xffff));
|
||||
do_check_eq(b_t.length, 0xffff);
|
||||
do_check_throws(function() {
|
||||
ctypes.int32_t.array(ctypes.UInt64(0xffffffffffffffff));
|
||||
}, Error);
|
||||
if (ctypes.size_t.size == 8) {
|
||||
b_t = ctypes.int32_t.array(0xfffffffffffff000);
|
||||
do_check_eq(b_t.length, 0xfffffffffffff000);
|
||||
|
||||
// Check that array size bounds work, and that large, but not illegal, sizes
|
||||
// are OK. This gets tricky. The type constructor needs to allocate 'n'
|
||||
// elements for the type descriptor, so we have to build up arrays of arrays
|
||||
// to avoid trying to allocate an insane size.
|
||||
if (ctypes.size_t.size == 4) {
|
||||
do_check_throws(function() {
|
||||
ctypes.ArrayType(ctypes.int8_t, 0x100000000);
|
||||
}, Error);
|
||||
do_check_throws(function() {
|
||||
ctypes.ArrayType(ctypes.int16_t, 0x80000000);
|
||||
}, Error);
|
||||
|
||||
let large_t = ctypes.int8_t;
|
||||
while (large_t.size != 0x80000000)
|
||||
large_t = large_t.array(2);
|
||||
do_check_throws(function() { large_t.array(2); }, Error);
|
||||
|
||||
} else {
|
||||
do_check_throws(function() { ctypes.int32_t.array(0xffffffffff); }, Error);
|
||||
do_check_throws(function() {
|
||||
ctypes.ArrayType(ctypes.int8_t, ctypes.UInt64("0xffffffffffffffff"));
|
||||
}, Error);
|
||||
do_check_throws(function() {
|
||||
ctypes.ArrayType(ctypes.int16_t, ctypes.UInt64("0x8000000000000000"));
|
||||
}, Error);
|
||||
|
||||
let large_t = ctypes.int8_t;
|
||||
while (large_t.size != 0x8000000000000000)
|
||||
large_t = large_t.array(2);
|
||||
do_check_throws(function() { large_t.array(2); }, Error);
|
||||
}
|
||||
|
||||
// Test that arrays ImplicitConvert to pointers.
|
||||
|
|
Загрузка…
Ссылка в новой задаче