diff options
Diffstat (limited to 'js/src/jsapi-tests/testIsAboutToBeFinalized.cpp')
-rw-r--r-- | js/src/jsapi-tests/testIsAboutToBeFinalized.cpp | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/js/src/jsapi-tests/testIsAboutToBeFinalized.cpp b/js/src/jsapi-tests/testIsAboutToBeFinalized.cpp new file mode 100644 index 0000000..4846277 --- /dev/null +++ b/js/src/jsapi-tests/testIsAboutToBeFinalized.cpp @@ -0,0 +1,136 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=99: + */ + +#include "tests.h" +#include "jsstr.h" + +static JSGCCallback oldGCCallback; + +static void **checkPointers; +static jsuint checkPointersLength; +static size_t checkPointersStaticStrings; + +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); +} + +/* + * NativeFrameCleaner write to sink so a compiler nwould not be able to optimze out + * the buffer memset there. + */ +volatile void *ptrSink; + +static JS_NEVER_INLINE void +NativeFrameCleaner() +{ + char buffer[1 << 16]; + memset(buffer, 0, sizeof buffer); + ptrSink = buffer; +} + +BEGIN_TEST(testIsAboutToBeFinalized_bug528645) +{ + /* + * Due to the conservative GC we use separated never-inline function to + * test rooted elements. + */ + CHECK(createAndTestRooted()); + NativeFrameCleaner(); + + 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(checkPointersStaticStrings != 0); + --checkPointersStaticStrings; + } + } + CHECK(checkPointersStaticStrings == 0); + + free(checkPointers); + checkPointers = NULL; + JS_SetGCCallback(cx, oldGCCallback); + + return true; +} + +JS_NEVER_INLINE bool createAndTestRooted(); + +END_TEST(testIsAboutToBeFinalized_bug528645) + +JS_NEVER_INLINE bool +cls_testIsAboutToBeFinalized_bug528645::createAndTestRooted() +{ + 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, 'a', '123456789', 'something'.substring(1), " + "{}, [], new Function('return 10;'), <xml/>];", + root.addr()); + + JSObject *array = JSVAL_TO_OBJECT(root.value()); + JS_ASSERT(JS_IsArrayObject(cx, array)); + + JSBool ok = JS_GetArrayLength(cx, array, &checkPointersLength); + CHECK(ok); + + checkPointers = (void **) malloc(sizeof(void *) * checkPointersLength); + CHECK(checkPointers); + + checkPointersStaticStrings = 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)); + checkPointers[i] = JSVAL_TO_GCTHING(v); + if (JSString::isStatic(checkPointers[i])) + ++checkPointersStaticStrings; + } + + oldGCCallback = JS_SetGCCallback(cx, TestAboutToBeFinalizedCallback); + 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]); + + /* + * Overwrite the registers and stack with new GC things to avoid false + * positives with the finalization test. + */ + EVAL("[]", root.addr()); + + array = JSVAL_TO_OBJECT(root.value()); + JS_ASSERT(JS_IsArrayObject(cx, array)); + + jsuint tmp; + CHECK(JS_GetArrayLength(cx, array, &tmp)); + CHECK(ok); + + return true; +} + |