Skip to content

Instantly share code, notes, and snippets.

@tjw
Created February 14, 2018 23:40
Show Gist options
  • Save tjw/7a1762612527a5be6b5fdc41d7d50fa9 to your computer and use it in GitHub Desktop.
Save tjw/7a1762612527a5be6b5fdc41d7d50fa9 to your computer and use it in GitHub Desktop.
Regression in JSObjectSetPrototype for the global object in a context.
/*
swift SetPrototype.swift
On 10.13.4, the result is 'undefined', but it should be '5'.
*/
import Foundation
import JavaScriptCore
var definition:JSClassDefinition = kJSClassDefinitionEmpty
definition.attributes = JSClassAttributes(kJSClassAttributeNoAutomaticPrototype)
definition.className = ("Foo" as NSString).utf8String
let classRef = JSClassCreate(&definition)!
let ctx = JSGlobalContextCreate(classRef)
let originalGlobalObject = JSContextGetGlobalObject(ctx)!
let prototype = JSObjectMake(ctx, nil, nil)!
JSObjectSetPrototype(ctx, originalGlobalObject, prototype)
// In 10.13.3 and earlier, setting the prototype on the global object made the context return a new global object
let updatedGlobalObject = JSContextGetGlobalObject(ctx)!
if originalGlobalObject != updatedGlobalObject {
print("global object changed from \(originalGlobalObject) to \(updatedGlobalObject))")
}
// Add a property to the prototype
let valueName = JSStringCreateWithCFString("value" as CFString);
do {
var exception: JSValueRef? = nil
JSObjectSetProperty(ctx, prototype, valueName, JSValueMakeNumber(ctx, 5.0), UInt32(kJSPropertyAttributeNone), &exception)
guard exception == nil else {
fatalError("Unable to set property")
}
}
// Get the property via a script that should find the property via the prototype chain from the global object.
let scriptString = JSStringCreateWithCFString("this.value;" as CFString)
var scriptException: JSValueRef? = nil
guard let resultRef = JSEvaluateScript(ctx, scriptString, updatedGlobalObject, nil, 0, &scriptException) else {
if let exc = scriptException {
let excString = JSValueToStringCopy(ctx, exc, nil)
fatalError("execution failed: \(JSStringCopyCFString(kCFAllocatorDefault, excString)!)")
} else {
fatalError("execution failed")
}
}
// Should find the `5` in the prototype chain. Does before 10.13.4 beta.
if let resultString = JSValueToStringCopy(ctx, resultRef, nil) {
print("resultString: \(JSStringCopyCFString(kCFAllocatorDefault, resultString)!)")
} else {
print("failed to get resultString")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment