DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Mercurial (5216dd412535)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 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;
}