You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

118 lines
5.0 KiB

<h1 id="internalproperties">Internal properties</h1>
<p>Duktape supports non-standard <b>internal properties</b> which are
essentially hidden from user code. They can only be accessed by a
direct property read/write, and are never enumerated, serialized by
<code>JSON.stringify()</code> or returned from built-in functions such
as <code>Object.getOwnPropertyNames()</code>.</p>
<p>Duktape uses internal properties for various implementation specific
purposes, such as storing an object's finalizer reference, the internal
value held by <code>Number</code> and <code>Date</code>, etc. User code
can also use internal properties for its own purposes, e.g. to
store "hidden state" in objects, as long as the property names never
conflict with current or future Duktape internal keys (this is ensured
by the naming convention described below). User code should never try
to access Duktape's internal properties: the set of internal properties
used can change arbitrarily between versions.</p>
<p>Internal properties are distinguished from other properties by the
property key: if the byte representation of a property key begins with
a <code>0xFF</code> byte Duktape automatically treats the property as an
internal property. Such a string is referred to as an <b>internal string</b>.
The initial byte makes the key invalid UTF-8 (even invalid extended UTF-8),
which ensures that (1) internal properties never conflict with normal Unicode
property names and that (2) ordinary Ecmascript code cannot accidentally access
them. The initial prefix byte is often represented by an underscore in
documentation for readability, e.g. <code>_Value</code> is used instead
of <code>\xFFValue</code>.</p>
<p>The following naming convention is used. The convention ensures that
Duktape and user internal properties never conflict:</p>
<table>
<tr>
<th>Type</th>
<th>Example (C)</th>
<th>Bytes</th>
<th>Description</th>
</tr>
<tr>
<td>Duktape</td>
<td><code>"\xFF" "Value"</code></td>
<td><code>ff 56 61 6c 75 65</code></td>
<td>First character is always uppercase, followed by <code>[a-z0-9_]*</code>.</td>
</tr>
<tr>
<td>User</td>
<td><code>"\xFF" "myprop"</code></td>
<td><code>ff 6d 79 70 72 6f 70</code></td>
<td>First character must not be uppercase to avoid conflict with
current or future Duktape keys.</td>
</tr>
<tr>
<td>User</td>
<td><code>"\xFF\xFF" &lt;arbitrary&gt;</code></td>
<td><code>ff ff &lt;arbitrary&gt;</code></td>
<td>Double <code>0xFF</code> prefix followed by arbitrary data.</td>
</tr>
</table>
<p>In some cases the internal key needed by user code is not static, e.g.
it can be dynamically generated by serializing a pointer or perhaps the
bytes are from an external source. In this case it is safest to use
two <code>0xFF</code> prefix bytes as the example above shows.</p>
<div class="note">
Note that the <code>0xFF</code> prefix cannot be expressed as a valid
Ecmascript string. For example, the internal string <code>\xFFxyz</code>
would appear as the bytes <code>ff 78 79 7a</code> in memory, while the
Ecmascript string <code>"\u00ffxyz"</code> would be represented as the
CESU-8 bytes <code>c3 bf 78 79 7a</code> in memory.
</div>
<p>Creating an internal string is easy from C code:</p>
<pre class="c-code">
/* Create an internal string, which can then be used to read/write internal
* properties, and can be passed on to Ecmascript code like any other string.
* Terminating a string literal after a hex escape is safest to avoid some
* ambiguous cases like "\xffab".
*/
duk_push_string(ctx, "\xff" "myprop");
</pre>
<p>For more discussion on C string hex escaping, see
<a href="https://github.com/svaarala/duktape/blob/master/misc/c_hex_esc.c">c_hex_esc.c</a>.</p>
<p>Internal strings can also be created from Ecmascript code if one has access
to e.g. a buffer constructor or <code>Duktape.dec()</code> (this must be considered
in sandboxing):</p>
<pre class="ecmascript-code">
// Using Node.js Buffer
var buf = new Buffer(1);
buf[0] = 255;
var key1 = buf + 'myprop';
// Using Duktape.dec()
var key2 = String.fromBuffer(Duktape.dec('hex', 'ff6d7970726f70')); // \xFFmyprop
</pre>
<p>There's no special access control for internal properties: if user code has
access to the property name (string), it can read/write the property value.
Any code with the ability to create or use buffers can potentially create an
internal string by converting a buffer into a string. However, standard Ecmascript
code with no access to buffer values or ability to create them cannot create internal
strings (or any invalid UTF-8 strings in general). When sandboxing, ensure that
the sandboxed code has no access to the <code>Duktape</code> built-in or any
buffer values.</p>
<p>As a concrete example, the internal value of a <code>Date</code> can be
accessed as follows:</p>
<pre class="ecmascript-code">
// Print the internal timestamp of a Date instance. User code should NEVER
// actually do this because the internal properties may change between
// versions in an arbitrary manner!
var key = Duktape.dec('hex', 'ff56616c7565'); // \xFFValue
var dt = new Date(123456);
print('internal value is:', dt[key]); // prints 123456
</pre>