From ea2c3a7d8a7459d5bec15834b1d50cf624e54e2b Mon Sep 17 00:00:00 2001 From: Igor Bukanov Date: Tue, 22 Dec 2009 23:50:44 +0300 Subject: [PATCH] bug 528645 - js_IsAboutToBeFinalized must check for static strings. r=wagnerg --- js/src/jsapi-tests/Makefile.in | 1 + js/src/jsapi-tests/testIntString.cpp | 6 +- .../jsapi-tests/testIsAboutToBeFinalized.cpp | 89 +++++++++++++++++++ js/src/jsgc.cpp | 3 + 4 files changed, 96 insertions(+), 3 deletions(-) create mode 100644 js/src/jsapi-tests/testIsAboutToBeFinalized.cpp diff --git a/js/src/jsapi-tests/Makefile.in b/js/src/jsapi-tests/Makefile.in index 057cec658b44..e338907d08c3 100644 --- a/js/src/jsapi-tests/Makefile.in +++ b/js/src/jsapi-tests/Makefile.in @@ -53,6 +53,7 @@ CPPSRCS = \ testDefineGetterSetterNonEnumerable.cpp \ testExtendedEq.cpp \ testIntString.cpp \ + testIsAboutToBeFinalized.cpp \ testLookup.cpp \ testPropCache.cpp \ testTrap.cpp \ diff --git a/js/src/jsapi-tests/testIntString.cpp b/js/src/jsapi-tests/testIntString.cpp index 79faadee5112..95a21e7b32f9 100644 --- a/js/src/jsapi-tests/testIntString.cpp +++ b/js/src/jsapi-tests/testIntString.cpp @@ -2,10 +2,10 @@ BEGIN_TEST(testIntString_bug515273) { - jsval v; - EVAL("'42';", &v); + jsvalRoot v(cx); + EVAL("'42';", v.addr()); - JSString *str = JSVAL_TO_STRING(v); + JSString *str = JSVAL_TO_STRING(v.value()); const char *bytes = JS_GetStringBytes(str); CHECK(strcmp(bytes, "42") == 0); return true; diff --git a/js/src/jsapi-tests/testIsAboutToBeFinalized.cpp b/js/src/jsapi-tests/testIsAboutToBeFinalized.cpp new file mode 100644 index 000000000000..6d0c31200e04 --- /dev/null +++ b/js/src/jsapi-tests/testIsAboutToBeFinalized.cpp @@ -0,0 +1,89 @@ +#include "tests.h" +#include "jsstr.h" + +static JSGCCallback oldGCCallback; + +static void **checkPointers; +static jsuint checkPointersLength; + +static JSBool +TestAboutToBeFinalizedCallback(JSContext *cx, JSGCStatus status) +{ + if (status == JSGC_MARK_END && checkPointers) { + for (jsuint i = 0; i != checkPointersLength; ++i) { + void *p = checkPointers[i]; + JS_ASSERT(p); + if (JS_IsAboutToBeFinalized(cx, p)) + checkPointers[i] = NULL; + } + } + + return !oldGCCallback || oldGCCallback(cx, status); +} + +BEGIN_TEST(testIsAboutToBeFinalized_bug528645) +{ + jsvalRoot root(cx); + + /* + * Check various types of GC things against JS_IsAboutToBeFinalized. + * Make sure to include unit and numeric strings to the set. + */ + EVAL("var x = 1.1; " + "[x + 0.1, ''+x, 'a', '42', 'something'.substring(1), " + "{}, [], new Function('return 10;'), ];", + root.addr()); + + JSObject *array = JSVAL_TO_OBJECT(root.value()); + JS_ASSERT(JS_IsArrayObject(cx, array)); + + JSBool ok = JS_GetArrayLength(cx, array, &checkPointersLength); + CHECK(ok); + + void **elems = (void **) malloc(sizeof(void *) * checkPointersLength); + CHECK(elems); + + size_t staticStrings = 0; + for (jsuint i = 0; i != checkPointersLength; ++i) { + jsval v; + ok = JS_GetElement(cx, array, i, &v); + CHECK(ok); + JS_ASSERT(JSVAL_IS_GCTHING(v)); + JS_ASSERT(!JSVAL_IS_NULL(v)); + elems[i] = JSVAL_TO_GCTHING(v); + if (JSString::isStatic(elems[i])) + ++staticStrings; + } + + oldGCCallback = JS_SetGCCallback(cx, TestAboutToBeFinalizedCallback); + checkPointers = elems; + JS_GC(cx); + + /* + * All GC things are rooted via the root holding the array containing them + * and TestAboutToBeFinalizedCallback must keep them as is. + */ + for (jsuint i = 0; i != checkPointersLength; ++i) + CHECK(checkPointers[i]); + + root = JSVAL_NULL; + JS_GC(cx); + + /* Everything is unrooted except unit strings. */ + for (jsuint i = 0; i != checkPointersLength; ++i) { + void *p = checkPointers[i]; + if (p) { + CHECK(JSString::isStatic(p)); + CHECK(staticStrings != 0); + --staticStrings; + } + } + CHECK(staticStrings == 0); + + checkPointers = NULL; + JS_SetGCCallback(cx, oldGCCallback); + free(elems); + + return true; +} +END_TEST(testIsAboutToBeFinalized_bug528645) diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index c31da3026fb4..9ce8d4a49856 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -900,6 +900,9 @@ js_IsAboutToBeFinalized(void *thing) JSGCArenaInfo *a; uint32 index, flags; + if (JSString::isStatic(thing)) + return false; + a = THING_TO_ARENA(thing); if (!a->list) { /*