My favorites | Sign in
Logo
                
Search
for
Updated Sep 25, 2009 by mikesamuel
Labels: Phase-Design
ObjectProperties  
How caja.js protects access to properties

Object properties and access

Background

EcmaScript Objects are collections of named properties. o.foo specifies the foo property of the object referenced by o. Some properties can be read and set, some can only be read, and some don't show up when enumerated via a for (... in ...) loops.

ECMAScript 262 Edition 3 (hereafter ES3) defines "property attributes" in section 8.6.1.

8.6.1 Property Attributes A property can have zero or more attributes from the following set:

Attribute Description
ReadOnly The property is a read-only property. Attempts by ES3 code to write to the property will be ignored. (Note, however, that in some cases the value of a property with the ReadOnly attribute may change over time because of actions taken by the host environment; therefore "ReadOnly" does not mean "constant and unchanging"!)
DontEnum The property is not to be enumerated by a for-in enumeration (section 12.6.4).
DontDelete Attempts to delete the property will be ignored. See the description of the delete operator in section 11.4.1.

ES3 defines no way for user code to manipulate these attributes, but Caja whitelists access to object properties, and so some properites (e.g. the "eval" property of all objects in Firefox) are inaccessible from Caja. Containers can choose to expose properties to Caja code by granting access on a property-by-property basis.

As described at NiceNeighbor, array index properties, and the length property are always readable.

Methods as Properties

ES3 methods are simply properties containing function objects. These functions are not bound to the object they are called on, until the time the function is called using the special obj.method(<params>) or equivalent obj[methodName](<params>) syntax, or the reflective method.call(obj, <params>) syntax.

Caja Attributes

In addition to the ReadOnly, DontEnum, DontDelete, caja adds the CanCall attribute. We also make the attribute names positive since we whitelist

Attribute Description
CanCall Can the property be called?
CanDelete Can the property be deleted? This attribute is presumed to be allowed by anyone who can create the property in the first place, since deletion is the dual of creation. CanDelete == !(DontDelete)
CanEnum Makes the property show up in for (... in ...) loops. CanEnum == !(DontEnum)
CanRead Makes the property visible.
CanSet Makes the property editable. CanSet == !(ReadOnly)

CanDelete implies CanSet. CanSet implies CanEnum. CanEnum implies CanRead.

Object Types

We determine property attributes differently for two types of objects.

JSON Objects

All Arrays and Objects are JSON objects. Their properties are assumed to be editable, readable, enumerable, and deletable by any code that can access them (modulo freezing below), and have no distinction between public and private properties.

Constructed Objects

A constructed object is any object created from a class. Constructed objects have private properties that are not accessible except to their constructor and methods. Private properties have names that end in _, so foo_ is a private property name, but foo is a public property name.

A constructed object's properties are not deletable via its public API, but can be created, set, or deleted via constructors and methods which can access its private API.

Private properties are not enumerable except via the private API.

The private API is accessed via this, so for (var k in this) will enumerate over both public and private properties, but for (var k in o) will not include private properties. Caja does not allow functions that reference this to be called cross-class.

Frozen Objects

A frozen object is one that has been rendered immutable (not-transitively) via caja.freeze(). It cannot be modified by cajoled code, so this operation removes any fasttracked CanSet attributes. Both constructed objects and JSON objects can be frozen.

Granting Access

The container can grant access to certain code. For example, caja.js grants access to the length property of arrays and array-like objects via ___.allowRead(Object.prototype, 'length').

Other caja.js methods set the above property attributes. Public clients cannot be granted access to a constructed object's private API.

Granting read access does not guarantee that the property value will be read unchanged -- unattached methods will be bound when read.

Fasttrack Attributes

For efficiency, we store the fact that a certain property attribute is set. We never store the fact that CanEnum attribute is set, since we never check it, and we never store the fact that CanDelete is set, since deletes invalidate all fasttrack attributes.

The diagrams below show how basic operations (C_alls, D_eletes, R_eads, S_ets) affect fasttrack attributes.

In both diagrams, arrows represent the basic operations, and ovals specify which fasttrack attributes are set. Arrows from a box to an oval mean that that transition can start from any oval in the box. Since the whole purpose of a fasttrack attribute is to let us skip runtime checks, if an oval has fx set, then there will be no outbound X transition since that transition will never be set.

Note that a read of an unattached method never sets a fasttrack bit since reading an unattached method involves returning a bound version of the method.


Sign in to add a comment