Skip to content
This repository was archived by the owner on Apr 3, 2024. It is now read-only.

Commit c0f3350

Browse files
author
Matt Loring
committed
Display error for native properties/getters
This prevents native properties/getters from being reported as undefined when we are unable to check their values for fear of executing stateful code.
1 parent 215d748 commit c0f3350

File tree

2 files changed

+67
-10
lines changed

2 files changed

+67
-10
lines changed

lib/state.js

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ var semver = require('semver');
2626

2727
var StatusMessage = require('./apiclasses.js').StatusMessage;
2828

29+
var BUFFER_FULL_MESSAGE_INDEX = 0;
30+
var NATIVE_PROPERTY_MESSAGE_INDEX = 1;
31+
var GETTER_MESSAGE_INDEX = 2;
32+
2933
// TODO: document this file
3034

3135
// returns an object with three fields: stacksframes,
@@ -79,13 +83,17 @@ function StateResolver(execState, expressions, config) {
7983
this.evaluatedExpressions_ = [];
8084
this.totalSize_ = 0;
8185

82-
// The 0-th object in the variable table is a sentinel 'buffer full' error
83-
// message value
84-
this.rawVariableTable_ = [ null ];
85-
this.resolvedVariableTable_ = [
86+
this.rawVariableTable_ = [ null, null, null ];
87+
this.resolvedVariableTable_ = [];
88+
this.resolvedVariableTable_[BUFFER_FULL_MESSAGE_INDEX] =
89+
{ status: new StatusMessage(StatusMessage.VARIABLE_VALUE,
90+
'Max data size reached', true) };
91+
this.resolvedVariableTable_[NATIVE_PROPERTY_MESSAGE_INDEX] =
92+
{ status: new StatusMessage(StatusMessage.VARIABLE_VALUE,
93+
'Native properties are not available', true) };
94+
this.resolvedVariableTable_[GETTER_MESSAGE_INDEX] =
8695
{ status: new StatusMessage(StatusMessage.VARIABLE_VALUE,
87-
'Buffer full', true) }
88-
];
96+
'Properties with getters are not available', true) };
8997
}
9098

9199

@@ -114,7 +122,7 @@ StateResolver.prototype.capture = function() {
114122
}
115123

116124
// Now resolve the variables
117-
var index = 1; // skip the sentinel value
125+
var index = 3; // skip the sentinel values
118126
while (index < that.rawVariableTable_.length && // NOTE: length changes in loop
119127
that.totalSize_ < that.config_.capture.maxDataSize) {
120128
assert(!that.resolvedVariableTable_[index]); // shouldn't have it resolved yet
@@ -145,7 +153,7 @@ StateResolver.prototype.trimVariableTable_ = function(fromIndex, frames) {
145153
variables.forEach(function (variable) {
146154
if (variable.varTableIndex && variable.varTableIndex >= fromIndex) {
147155
// make it point to the sentinel 'buffer full' value
148-
variable.varTableIndex = 0;
156+
variable.varTableIndex = BUFFER_FULL_MESSAGE_INDEX;
149157
}
150158
if (variable.members) {
151159
processBufferFull(variable.members);
@@ -365,7 +373,7 @@ StateResolver.prototype.resolveMirrorSlow_ = function(mirror) {
365373
keys = keys.slice(0, that.config_.capture.maxProperties);
366374
}
367375
var members = keys.map(function(prop) {
368-
return that.resolveVariable_(prop, mirror.property(prop).value());
376+
return that.resolveMirrorProperty_(mirror.property(prop));
369377
});
370378

371379
return {
@@ -386,11 +394,23 @@ StateResolver.prototype.resolveMirrorFast_ = function(mirror) {
386394
};
387395
};
388396
StateResolver.prototype.getMirrorProperties_ = function(mirror) {
389-
var numProperties = this.config_.capture.maxProperties || 1000;
397+
var numProperties = this.config_.capture.maxProperties;
390398
var namedProperties = mirror.properties(1, numProperties);
391399
var indexedProperties = mirror.properties(2, numProperties);
392400
return namedProperties.concat(indexedProperties);
393401
};
394402
StateResolver.prototype.resolveMirrorProperty_ = function(property) {
403+
if (property.isNative()) {
404+
return {
405+
name: property.name(),
406+
varTableIndex: NATIVE_PROPERTY_MESSAGE_INDEX
407+
};
408+
}
409+
if (property.hasGetter()) {
410+
return {
411+
name: property.name(),
412+
varTableIndex: GETTER_MESSAGE_INDEX
413+
};
414+
}
395415
return this.resolveVariable_(property.name(), property.value());
396416
};

test/test-v8debugapi.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
/*3*/function foo(n) {
44
/*4*/ return n+42;
55
/*5*/}
6+
/*6*/function getterObject() {
7+
/*7*/ var hasGetter = { _a: 5, get a() { return this._a; } };
8+
/*8*/ return hasGetter.a;
9+
/*9*/}
610
/**
711
* Copyright 2015 Google Inc. All Rights Reserved.
812
*
@@ -332,7 +336,40 @@ describe('v8debugapi', function() {
332336
});
333337
process.nextTick(function() {foo(3);});
334338
});
339+
});
340+
341+
it('should report error for native prop or getter', function(done) {
342+
var bp = {
343+
id: 'fake-id-124',
344+
location: { path: 'test-v8debugapi.js', line: 8 },
345+
expressions: ['process.env', 'hasGetter']
346+
};
347+
api.set(bp, function(err) {
348+
assert.ifError(err);
349+
api.wait(bp, function(err) {
350+
assert.ifError(err);
351+
352+
var procEnv = bp.evaluatedExpressions[0];
353+
assert.equal(procEnv.name, 'process.env');
354+
var envVal = bp.variableTable[procEnv.varTableIndex];
355+
envVal.members.forEach(function(member) {
356+
assert(bp.variableTable[member.varTableIndex].status.isError);
357+
});
358+
var hasGetter = bp.evaluatedExpressions[1];
359+
var getterVal = bp.variableTable[hasGetter.varTableIndex];
360+
assert(getterVal.members.some(function(m) {
361+
return m.value === '5';
362+
}));
363+
assert(getterVal.members.some(function(m) {
364+
var resolved = bp.variableTable[m.varTableIndex];
365+
return resolved && resolved.status.isError;
366+
}));
335367

368+
api.clear(bp);
369+
done();
370+
});
371+
process.nextTick(function() {getterObject();});
372+
});
336373
});
337374

338375
it('should capture without values for invalid watch expressions', function(done) {

0 commit comments

Comments
 (0)