Titanium JIRA Archive
Titanium SDK/CLI (TIMOB)

[TIMOB-23609] Windows: read-only properties incorrectly identify themselves as configurable

GitHub Issuen/a
TypeBug
PriorityCritical
StatusClosed
ResolutionNot Our Bug
Resolution Date2016-07-05T10:12:52.000+0000
Affected Version/sn/a
Fix Version/sn/a
ComponentsWindows
Labelsn/a
ReporterChristopher Williams
AssigneeKota Iguchi
Created2016-07-01T20:38:32.000+0000
Updated2017-03-24T18:55:45.000+0000

Description

Properties like apiName on all proxies, or Ti.App.version are marked as read-only properties in our docs. That means the user should not be able to overwrite their values or delete them.On Windows, we cannot delete the property, but the common way of checking is to look at the configurable value of the property descriptor. That is oddly reporting true (which should mean it can be deleted).
var target = Ti.API,
    propName = 'apiName';


while (!Object.prototype.hasOwnProperty.call(target, propName)) {
    target = Object.getPrototypeOf(target); // go up the prototype chain
    if (!target) {
        alert('Failed!');
    }
}

Ti.API.info(JSON.stringify(Object.getOwnPropertyDescriptor(Object(target), propName)));


Ti.API.info(Ti.API.apiName);
delete Ti.API.apiName;
Ti.API.info(Ti.API.apiName);

Comments

  1. Christopher Williams 2016-07-01

    Note that the linked ticket for iOS may also have the same behavior? Maybe it's just reporting configurable: true but isn't actually able to be deleted?
  2. Kota Iguchi 2016-07-05

    Confirmed that JavaScriptCore doesn't handle enumerable and configurable well with getOwnPropertyDescriptor even on OS X. I assume it doesn't work well on iOS too. Found WebKit bug reports related to this: https://bugs.webkit.org/show_bug.cgi?id=158116 https://bugs.webkit.org/show_bug.cgi?id=151348 Maybe related: https://github.com/adobe/webkit/blob/master/Source/JavaScriptCore/API/JSCallbackObjectFunctions.h#L216 *Test Code*
       #include <iostream>
       #include <JavaScriptCore/JavaScriptCore.h>
       #include <cassert>
       
       static JSValueRef GetX(JSContextRef ctx, JSObjectRef object, JSStringRef propertyNameJS, JSValueRef* exception)
       {
       	return JSValueMakeNumber(ctx, 101.0);
       }
       
       static JSStaticValue staticValues[] = {
       	{
       		"X", GetX, nullptr,
       		// writable: false, configurable: false, enumerable: false
       		kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete  /* | kJSPropertyAttributeDontEnum */
       	},
           {0,0,0,0}
       };
       
       int main(int argc, const char * argv[]) {
       	auto group = JSContextGroupCreate();
       	auto ctx = JSGlobalContextCreateInGroup(group, nullptr);
       	auto global = JSContextGetGlobalObject(ctx);
       	
       	auto definition = kJSClassDefinitionEmpty;
       	definition.staticValues = staticValues;
       	auto myClass = JSClassCreate(&definition);
       	
       	auto myClassObject = JSObjectMake(ctx, myClass, nullptr);
       	
       	JSStringRef myClassName = JSStringCreateWithUTF8CString("MyClass");
       	JSObjectSetProperty(ctx, global, myClassName, myClassObject, kJSPropertyAttributeNone, nullptr);
       	JSStringRelease(myClassName);
       
       	JSStringRef strX = JSStringCreateWithUTF8CString("X");
       	assert(JSObjectHasProperty(ctx, myClassObject, strX));
       	auto propX = JSObjectGetProperty(ctx, myClassObject, strX, nullptr);
       	assert(JSValueIsNumber(ctx, propX));
       	JSStringRelease(strX);
       	
       	
       	JSStringRef script = JSStringCreateWithUTF8CString(R"JS(
           var target = MyClass, propName = 'X';
           while (!Object.prototype.hasOwnProperty.call(target, propName)) {
               target = Object.getPrototypeOf(target);
           }
           if (target) {
             Object.getOwnPropertyDescriptor(Object(target), propName);
           } else {
       		{};
           }
       	)JS");
       
       	JSStringRef writable = JSStringCreateWithUTF8CString("writable");
       	JSStringRef enumerable = JSStringCreateWithUTF8CString("enumerable");
       	JSStringRef configurable = JSStringCreateWithUTF8CString("configurable");
       
       	auto result = JSValueToObject(ctx, JSEvaluateScript(ctx, script, global, nullptr, 0, nullptr), nullptr);
       	JSObjectHasProperty(ctx, result, writable);
       	JSObjectHasProperty(ctx, result, enumerable);
       	JSObjectHasProperty(ctx, result, configurable);
       	
       	//
       	// enumerable and configurable go wrong. Even on OS X.
       	//
       
       	// Maybe related?
       	// https://bugs.webkit.org/show_bug.cgi?id=158116
       	// https://bugs.webkit.org/show_bug.cgi?id=151348
       	// https://github.com/adobe/webkit/blob/master/Source/JavaScriptCore/API/JSCallbackObjectFunctions.h#L216
       	
       	// writable should return false, because we did specify kJSPropertyAttributeReadOnly
       	assert(!JSValueToBoolean(ctx, JSObjectGetProperty(ctx, result, writable, nullptr)));
       	
       	// enumerable should return true, because we didn't specifykJSPropertyAttributeDontEnum
       	assert(JSValueToBoolean(ctx, JSObjectGetProperty(ctx, result, enumerable, nullptr)));
       
       	// configurable should return false, because we did specify kJSPropertyAttributeDontDelete
       	assert(!JSValueToBoolean(ctx, JSObjectGetProperty(ctx, result, configurable, nullptr)));
       	
       	JSStringRelease(writable);
       	JSStringRelease(enumerable);
       	JSStringRelease(configurable);
       	
       	JSGlobalContextRelease(ctx);
       	
       	return 0;
       }
       
  3. Ewan Harris 2016-08-16

    [~kota] [~cwilliams] as this is resolved as not our bug, could the fix version be removed. Thanks!
  4. Lee Morris 2017-03-24

    Closing ticket with reference to the previous comments.

JSON Source