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.
 
 
 
 
 
 

100 lines
3.1 KiB

/*
* There was an interesting bug up to Duktape 0.11.0, reported by Greg Burns.
*
* With certain object property add/delete sequences the object property entry
* part can grow without bound, even though the object only has a limited
* number of actually used properties.
*
* The root cause of this issue is the duk_hobject_props.c object entry part
* resize algorithm which computes the new entry part size based on the
* current allocated size (not *used size*). Suppose that the entry part
* for keys looks as follows ('.' is unused):
*
* [..........x]
*
* if the object entry part is resized, a larger one is allocated with keys
* compacted:
*
* [x...............]
*
* with a suitable insert/delete sequence (like the simple one below), you
* can then again reach the case:
*
* [...............x]
*
* ... and resize to:
*
* [x......................]
*
* and so on.
*
* The fix for this issue is to count the "used keys" explicitly before
* computing a new size for the object. The actual reallocation primitive
* will run through the keys anyway to compact (and possibly rehash) them,
* so this is not a major issue performance-wise.
*/
/*===
without compaction
entry count < 100: true
entry count < 100: true
with compaction
entry count < 100: true
entry count < 100: true
===*/
function objectEntryPartResizeTest(doCompact) {
var sparse = { 0: 0 };
var i;
var t, entryCount, entryNext;
for (i = 1; i < 10000; i++) {
sparse[i] = i;
delete sparse[i - 1];
if (doCompact) {
/* If the object is forcibly compacted, the undesired entry
* part behavior disappears even in Duktape 0.11.0 and prior.
*/
Duktape.compact(sparse);
}
}
/* Here the object entry part has been resized multiple times. We
* don't know the exact size, but since there is only one used key
* we can more or less safely assume the entry part should be smaller
* than 100 entries.
*
* NOTE: the "entry next" value is not the count of non-NULL key
* entries in the entry part. It's simply the next index to use
* when adding a new key, and is not necessarily 1 here.
*/
t = Duktape.info(sparse);
//print(t);
entryCount = t[5]; // version dependent, property entry allocated count
entryNext = t[6]; // version dependent, property entry next index
//print('entry next:', entryNext);
//print('entry count:', entryCount);
print('entry count < 100:', (entryCount < 100));
/* With the bug present, a compaction "fixes" the object. */
Duktape.compact(sparse);
t = Duktape.info(sparse);
//print(t);
entryCount = t[5]; // version dependent, property entry allocated count
entryNext = t[6]; // version dependent, property entry next index
//print('entry next:', entryNext);
//print('entry count:', entryCount);
print('entry count < 100:', (entryCount < 100));
}
try {
print('without compaction');
objectEntryPartResizeTest(false);
print('with compaction');
objectEntryPartResizeTest(true);
} catch (e) {
print(e);
}