PingPongStackOverflowTest.cpp [plain text]
#include "config.h"
#include "PingPongStackOverflowTest.h"
#include "InitializeThreading.h"
#include "JSContextRefPrivate.h"
#include "JavaScript.h"
#include "Options.h"
#include <wtf/text/StringBuilder.h>
using JSC::Options;
static JSGlobalContextRef context = nullptr;
static int nativeRecursionCount = 0;
static bool PingPongStackOverflowObject_hasInstance(JSContextRef context, JSObjectRef constructor, JSValueRef possibleValue, JSValueRef* exception)
{
UNUSED_PARAM(context);
UNUSED_PARAM(constructor);
JSStringRef hasInstanceName = JSStringCreateWithUTF8CString("hasInstance");
JSValueRef hasInstance = JSObjectGetProperty(context, constructor, hasInstanceName, exception);
JSStringRelease(hasInstanceName);
if (!hasInstance)
return false;
int countAtEntry = nativeRecursionCount++;
JSValueRef result = 0;
if (nativeRecursionCount < 100) {
JSObjectRef function = JSValueToObject(context, hasInstance, exception);
result = JSObjectCallAsFunction(context, function, constructor, 1, &possibleValue, exception);
} else {
StringBuilder builder;
builder.appendLiteral("dummy.valueOf([0]");
for (int i = 1; i < 35000; i++) {
builder.appendLiteral(", [");
builder.appendNumber(i);
builder.appendLiteral("]");
}
builder.appendLiteral(");");
JSStringRef script = JSStringCreateWithUTF8CString(builder.toString().utf8().data());
result = JSEvaluateScript(context, script, NULL, NULL, 1, exception);
JSStringRelease(script);
}
--nativeRecursionCount;
if (nativeRecursionCount != countAtEntry)
printf(" ERROR: PingPongStackOverflow test saw a recursion count mismatch\n");
return result && JSValueToBoolean(context, result);
}
JSClassDefinition PingPongStackOverflowObject_definition = {
0,
kJSClassAttributeNone,
"PingPongStackOverflowObject",
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
PingPongStackOverflowObject_hasInstance,
NULL,
};
static JSClassRef PingPongStackOverflowObject_class(JSContextRef context)
{
UNUSED_PARAM(context);
static JSClassRef jsClass;
if (!jsClass)
jsClass = JSClassCreate(&PingPongStackOverflowObject_definition);
return jsClass;
}
int testPingPongStackOverflow()
{
bool failed = false;
JSC::initializeThreading();
Options::initialize();
auto origSoftReservedZoneSize = Options::softReservedZoneSize();
auto origReservedZoneSize = Options::reservedZoneSize();
auto origUseLLInt = Options::useLLInt();
auto origMaxPerThreadStackUsage = Options::maxPerThreadStackUsage();
Options::softReservedZoneSize() = 128 * KB;
Options::reservedZoneSize() = 64 * KB;
#if ENABLE(JIT)
Options::useLLInt() = false;
#endif
const char* scriptString =
"var count = 0;" \
"PingPongStackOverflowObject.hasInstance = function f() {" \
" return (undefined instanceof PingPongStackOverflowObject);" \
"};" \
"PingPongStackOverflowObject.__proto__ = undefined;" \
"undefined instanceof PingPongStackOverflowObject;";
JSValueRef exception = nullptr;
JSStringRef script = JSStringCreateWithUTF8CString(scriptString);
nativeRecursionCount = 0;
context = JSGlobalContextCreateInGroup(nullptr, nullptr);
JSObjectRef globalObject = JSContextGetGlobalObject(context);
ASSERT(JSValueIsObject(context, globalObject));
JSObjectRef PingPongStackOverflowObject = JSObjectMake(context, PingPongStackOverflowObject_class(context), NULL);
JSStringRef PingPongStackOverflowObjectString = JSStringCreateWithUTF8CString("PingPongStackOverflowObject");
JSObjectSetProperty(context, globalObject, PingPongStackOverflowObjectString, PingPongStackOverflowObject, kJSPropertyAttributeNone, NULL);
JSStringRelease(PingPongStackOverflowObjectString);
unsigned stackSize = 32 * KB;
Options::maxPerThreadStackUsage() = stackSize + Options::softReservedZoneSize();
exception = nullptr;
JSEvaluateScript(context, script, nullptr, nullptr, 1, &exception);
JSGlobalContextRelease(context);
context = nullptr;
JSStringRelease(script);
if (!exception) {
printf("FAIL: PingPongStackOverflowError not thrown in PingPongStackOverflow test\n");
failed = true;
} else if (nativeRecursionCount) {
printf("FAIL: Unbalanced native recursion count: %d in PingPongStackOverflow test\n", nativeRecursionCount);
failed = true;
} else {
printf("PASS: PingPongStackOverflow test.\n");
}
Options::softReservedZoneSize() = origSoftReservedZoneSize;
Options::reservedZoneSize() = origReservedZoneSize;
Options::useLLInt() = origUseLLInt;
Options::maxPerThreadStackUsage() = origMaxPerThreadStackUsage;
return failed;
}