Bug 899976 - GC: Fix unsafe references related to ToInt* functions - js engine changes r=sfink

This commit is contained in:
Jon Coppeard 2013-08-02 13:15:38 +01:00
Родитель 4ade1553db
Коммит 61d335141c
8 изменённых файлов: 62 добавлений и 80 удалений

Просмотреть файл

@ -508,9 +508,13 @@ class MOZ_STACK_CLASS MutableHandle : public js::MutableHandleBase<T>
}
T *address() const { return ptr; }
T get() const { return *ptr; }
const T& get() const { return *ptr; }
operator T() const { return get(); }
/*
* Return a reference so passing a MutableHandle<T> to something that takes
* a |const T&| is not a GC hazard.
*/
operator const T&() const { return get(); }
T operator->() const { return get(); }
private:

Просмотреть файл

@ -5709,12 +5709,12 @@ GenerateFFIInterpreterExit(ModuleCompiler &m, const ModuleCompiler::ExitDescript
}
static int32_t
ValueToInt32(JSContext *cx, Value *val)
ValueToInt32(JSContext *cx, MutableHandleValue val)
{
int32_t i32;
if (!ToInt32(cx, val[0], &i32))
if (!ToInt32(cx, val, &i32))
return false;
val[0] = Int32Value(i32);
val.set(Int32Value(i32));
return true;
}

Просмотреть файл

@ -6774,7 +6774,7 @@ AutoGCRooter::AutoGCRooter(ContextFriendFields *cx, ptrdiff_t tag)
#ifdef DEBUG
JS_PUBLIC_API(void)
JS::AssertArgumentsAreSane(JSContext *cx, const JS::Value &value)
JS::AssertArgumentsAreSane(JSContext *cx, HandleValue value)
{
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);

Просмотреть файл

@ -75,9 +75,9 @@ class JS_PUBLIC_API(AutoCheckRequestDepth)
* Also check that GC would be safe at this point.
*/
JS_PUBLIC_API(void)
AssertArgumentsAreSane(JSContext *cx, const Value &v);
AssertArgumentsAreSane(JSContext *cx, JS::Handle<JS::Value> v);
#else
inline void AssertArgumentsAreSane(JSContext *cx, const Value &v) {
inline void AssertArgumentsAreSane(JSContext *cx, JS::Handle<JS::Value> v) {
/* Do nothing */
}
#endif /* DEBUG */
@ -1600,35 +1600,32 @@ JS_ValueToUint64(JSContext *cx, jsval v, uint64_t *ip);
namespace js {
/* DO NOT CALL THIS. Use JS::ToInt16. */
extern JS_PUBLIC_API(bool)
ToUint16Slow(JSContext *cx, const JS::Value &v, uint16_t *out);
ToUint16Slow(JSContext *cx, JS::Handle<JS::Value> v, uint16_t *out);
/* DO NOT CALL THIS. Use JS::ToInt32. */
extern JS_PUBLIC_API(bool)
ToInt32Slow(JSContext *cx, const JS::Value &v, int32_t *out);
ToInt32Slow(JSContext *cx, JS::Handle<JS::Value> v, int32_t *out);
/* DO NOT CALL THIS. Use JS::ToUint32. */
extern JS_PUBLIC_API(bool)
ToUint32Slow(JSContext *cx, const JS::Value &v, uint32_t *out);
ToUint32Slow(JSContext *cx, JS::Handle<JS::Value> v, uint32_t *out);
/* DO NOT CALL THIS. Use JS::ToInt64. */
extern JS_PUBLIC_API(bool)
ToInt64Slow(JSContext *cx, const JS::Value &v, int64_t *out);
ToInt64Slow(JSContext *cx, JS::Handle<JS::Value> v, int64_t *out);
/* DO NOT CALL THIS. Use JS::ToUint64. */
extern JS_PUBLIC_API(bool)
ToUint64Slow(JSContext *cx, const JS::Value &v, uint64_t *out);
ToUint64Slow(JSContext *cx, JS::Handle<JS::Value> v, uint64_t *out);
} /* namespace js */
namespace JS {
JS_ALWAYS_INLINE bool
ToUint16(JSContext *cx, const JS::Value &v, uint16_t *out)
ToUint16(JSContext *cx, JS::Handle<JS::Value> v, uint16_t *out)
{
AssertArgumentsAreSane(cx, v);
{
js::SkipRoot skip(cx, &v);
js::MaybeCheckStackRoots(cx);
}
js::MaybeCheckStackRoots(cx);
if (v.isInt32()) {
*out = uint16_t(v.toInt32());
@ -1638,13 +1635,10 @@ ToUint16(JSContext *cx, const JS::Value &v, uint16_t *out)
}
JS_ALWAYS_INLINE bool
ToInt32(JSContext *cx, const JS::Value &v, int32_t *out)
ToInt32(JSContext *cx, JS::Handle<JS::Value> v, int32_t *out)
{
AssertArgumentsAreSane(cx, v);
{
js::SkipRoot root(cx, &v);
js::MaybeCheckStackRoots(cx);
}
js::MaybeCheckStackRoots(cx);
if (v.isInt32()) {
*out = v.toInt32();
@ -1654,13 +1648,10 @@ ToInt32(JSContext *cx, const JS::Value &v, int32_t *out)
}
JS_ALWAYS_INLINE bool
ToUint32(JSContext *cx, const JS::Value &v, uint32_t *out)
ToUint32(JSContext *cx, JS::Handle<JS::Value> v, uint32_t *out)
{
AssertArgumentsAreSane(cx, v);
{
js::SkipRoot root(cx, &v);
js::MaybeCheckStackRoots(cx);
}
js::MaybeCheckStackRoots(cx);
if (v.isInt32()) {
*out = uint32_t(v.toInt32());
@ -1670,13 +1661,10 @@ ToUint32(JSContext *cx, const JS::Value &v, uint32_t *out)
}
JS_ALWAYS_INLINE bool
ToInt64(JSContext *cx, const JS::Value &v, int64_t *out)
ToInt64(JSContext *cx, JS::Handle<JS::Value> v, int64_t *out)
{
AssertArgumentsAreSane(cx, v);
{
js::SkipRoot skip(cx, &v);
js::MaybeCheckStackRoots(cx);
}
js::MaybeCheckStackRoots(cx);
if (v.isInt32()) {
*out = int64_t(v.toInt32());
@ -1687,13 +1675,10 @@ ToInt64(JSContext *cx, const JS::Value &v, int64_t *out)
}
JS_ALWAYS_INLINE bool
ToUint64(JSContext *cx, const JS::Value &v, uint64_t *out)
ToUint64(JSContext *cx, JS::Handle<JS::Value> v, uint64_t *out)
{
AssertArgumentsAreSane(cx, v);
{
js::SkipRoot skip(cx, &v);
js::MaybeCheckStackRoots(cx);
}
js::MaybeCheckStackRoots(cx);
if (v.isInt32()) {
/* Account for sign extension of negatives into the longer 64bit space. */

Просмотреть файл

@ -1007,7 +1007,6 @@ IsDuckTypedErrorObject(JSContext *cx, HandleObject exnObject, const char **filen
JSBool
js_ReportUncaughtException(JSContext *cx)
{
jsval roots[6];
JSErrorReport *reportp, report;
if (!JS_IsExceptionPending(cx))
@ -1017,8 +1016,8 @@ js_ReportUncaughtException(JSContext *cx)
if (!JS_GetPendingException(cx, exn.address()))
return false;
PodArrayZero(roots);
AutoArrayRooter tvr(cx, ArrayLength(roots), roots);
AutoValueVector roots(cx);
roots.resize(6);
/*
* Because ToString below could error and an exception object could become
@ -1048,18 +1047,12 @@ js_ReportUncaughtException(JSContext *cx)
(exnObject->is<ErrorObject>() || IsDuckTypedErrorObject(cx, exnObject, &filename_str)))
{
RootedString name(cx);
if (JS_GetProperty(cx, exnObject, js_name_str, tvr.handleAt(2)) &&
JSVAL_IS_STRING(roots[2]))
{
name = JSVAL_TO_STRING(roots[2]);
}
if (JS_GetProperty(cx, exnObject, js_name_str, roots.handleAt(2)) && roots[2].isString())
name = roots[2].toString();
RootedString msg(cx);
if (JS_GetProperty(cx, exnObject, js_message_str, tvr.handleAt(3)) &&
JSVAL_IS_STRING(roots[3]))
{
msg = JSVAL_TO_STRING(roots[3]);
}
if (JS_GetProperty(cx, exnObject, js_message_str, roots.handleAt(3)) && roots[3].isString())
msg = roots[3].toString();
if (name && msg) {
RootedString colon(cx, JS_NewStringCopyZ(cx, ": "));
@ -1077,22 +1070,22 @@ js_ReportUncaughtException(JSContext *cx)
str = msg;
}
if (JS_GetProperty(cx, exnObject, filename_str, tvr.handleAt(4))) {
JSString *tmp = ToString<CanGC>(cx, HandleValue::fromMarkedLocation(&roots[4]));
if (JS_GetProperty(cx, exnObject, filename_str, roots.handleAt(4))) {
JSString *tmp = ToString<CanGC>(cx, roots.handleAt(4));
if (tmp)
filename.encodeLatin1(cx, tmp);
}
uint32_t lineno;
if (!JS_GetProperty(cx, exnObject, js_lineNumber_str, tvr.handleAt(5)) ||
!ToUint32(cx, roots[5], &lineno))
if (!JS_GetProperty(cx, exnObject, js_lineNumber_str, roots.handleAt(5)) ||
!ToUint32(cx, roots.handleAt(5), &lineno))
{
lineno = 0;
}
uint32_t column;
if (!JS_GetProperty(cx, exnObject, js_columnNumber_str, tvr.handleAt(5)) ||
!ToUint32(cx, roots[5], &column))
if (!JS_GetProperty(cx, exnObject, js_columnNumber_str, roots.handleAt(5)) ||
!ToUint32(cx, roots.handleAt(5), &column))
{
column = 0;
}

Просмотреть файл

@ -1534,7 +1534,7 @@ js::ToNumberSlow(JSContext *cx, Value v, double *out)
* conversion. Return converted value in *out on success, false on failure.
*/
JS_PUBLIC_API(bool)
js::ToInt64Slow(JSContext *cx, const Value &v, int64_t *out)
js::ToInt64Slow(JSContext *cx, const HandleValue v, int64_t *out)
{
JS_ASSERT(!v.isInt32());
double d;
@ -1553,7 +1553,7 @@ js::ToInt64Slow(JSContext *cx, const Value &v, int64_t *out)
* conversion. Return converted value in *out on success, false on failure.
*/
JS_PUBLIC_API(bool)
js::ToUint64Slow(JSContext *cx, const Value &v, uint64_t *out)
js::ToUint64Slow(JSContext *cx, const HandleValue v, uint64_t *out)
{
JS_ASSERT(!v.isInt32());
double d;
@ -1568,7 +1568,7 @@ js::ToUint64Slow(JSContext *cx, const Value &v, uint64_t *out)
}
JS_PUBLIC_API(bool)
js::ToInt32Slow(JSContext *cx, const Value &v, int32_t *out)
js::ToInt32Slow(JSContext *cx, const HandleValue v, int32_t *out)
{
JS_ASSERT(!v.isInt32());
double d;
@ -1583,7 +1583,7 @@ js::ToInt32Slow(JSContext *cx, const Value &v, int32_t *out)
}
JS_PUBLIC_API(bool)
js::ToUint32Slow(JSContext *cx, const Value &v, uint32_t *out)
js::ToUint32Slow(JSContext *cx, const HandleValue v, uint32_t *out)
{
JS_ASSERT(!v.isInt32());
double d;
@ -1598,7 +1598,7 @@ js::ToUint32Slow(JSContext *cx, const Value &v, uint32_t *out)
}
JS_PUBLIC_API(bool)
js::ToUint16Slow(JSContext *cx, const Value &v, uint16_t *out)
js::ToUint16Slow(JSContext *cx, const HandleValue v, uint16_t *out)
{
JS_ASSERT(!v.isInt32());
double d;

Просмотреть файл

@ -1994,9 +1994,9 @@ END_CASE(JSOP_BINDNAME)
#define BITWISE_OP(OP) \
JS_BEGIN_MACRO \
int32_t i, j; \
if (!ToInt32(cx, regs.sp[-2], &i)) \
if (!ToInt32(cx, regs.stackHandleAt(-2), &i)) \
goto error; \
if (!ToInt32(cx, regs.sp[-1], &j)) \
if (!ToInt32(cx, regs.stackHandleAt(-1), &j)) \
goto error; \
i = i OP j; \
regs.sp--; \
@ -2123,9 +2123,9 @@ END_CASE(JSOP_GE)
#define SIGNED_SHIFT_OP(OP) \
JS_BEGIN_MACRO \
int32_t i, j; \
if (!ToInt32(cx, regs.sp[-2], &i)) \
if (!ToInt32(cx, regs.stackHandleAt(-2), &i)) \
goto error; \
if (!ToInt32(cx, regs.sp[-1], &j)) \
if (!ToInt32(cx, regs.stackHandleAt(-1), &j)) \
goto error; \
i = i OP (j & 31); \
regs.sp--; \

Просмотреть файл

@ -189,7 +189,8 @@ JSBool
ArrayBufferObject::class_constructor(JSContext *cx, unsigned argc, Value *vp)
{
int32_t nbytes = 0;
if (argc > 0 && !ToInt32(cx, vp[2], &nbytes))
CallArgs args = CallArgsFromVp(argc, vp);
if (argc > 0 && !ToInt32(cx, args[0], &nbytes))
return false;
if (nbytes < 0) {
@ -205,7 +206,7 @@ ArrayBufferObject::class_constructor(JSContext *cx, unsigned argc, Value *vp)
JSObject *bufobj = create(cx, uint32_t(nbytes));
if (!bufobj)
return false;
vp->setObject(*bufobj);
args.rval().setObject(*bufobj);
return true;
}
@ -1829,30 +1830,29 @@ class TypedArrayObjectTemplate : public TypedArrayObject
class_constructor(JSContext *cx, unsigned argc, Value *vp)
{
/* N.B. this is a constructor for protoClass, not fastClass! */
JSObject *obj = create(cx, argc, JS_ARGV(cx, vp));
CallArgs args = CallArgsFromVp(argc, vp);
JSObject *obj = create(cx, args);
if (!obj)
return false;
vp->setObject(*obj);
args.rval().setObject(*obj);
return true;
}
static JSObject *
create(JSContext *cx, unsigned argc, Value *argv)
create(JSContext *cx, const CallArgs& args)
{
/* N.B. there may not be an argv[-2]/argv[-1]. */
/* () or (number) */
uint32_t len = 0;
if (argc == 0 || ValueIsLength(argv[0], &len))
if (args.length() == 0 || ValueIsLength(args[0], &len))
return fromLength(cx, len);
/* (not an object) */
if (!argv[0].isObject()) {
if (!args[0].isObject()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_TYPED_ARRAY_BAD_ARGS);
return NULL;
}
RootedObject dataObj(cx, &argv[0].toObject());
RootedObject dataObj(cx, &args.get(0).toObject());
/*
* (typedArray)
@ -1869,8 +1869,8 @@ class TypedArrayObjectTemplate : public TypedArrayObject
int32_t byteOffset = 0;
int32_t length = -1;
if (argc > 1) {
if (!ToInt32(cx, argv[1], &byteOffset))
if (args.length() > 1) {
if (!ToInt32(cx, args[1], &byteOffset))
return NULL;
if (byteOffset < 0) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
@ -1878,8 +1878,8 @@ class TypedArrayObjectTemplate : public TypedArrayObject
return NULL;
}
if (argc > 2) {
if (!ToInt32(cx, argv[2], &length))
if (args.length() > 2) {
if (!ToInt32(cx, args[2], &length))
return NULL;
if (length < 0) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,