Closed connor4312 closed 1 year ago
Seems like an issue for node-tree-sitter
Your code accesses these properties on the prototype which doesn't make sense, but it of course shouldn't segfault.
The issue is that it calls this code:
but on a prototype, this
is an empty object:
/tmp/tree-sitter-typescript$ node
Welcome to Node.js v20.4.0.
Type ".help" for more information.
> class SyntaxNode {
... constructor(tree) {
... this.tree = tree;
... }
...
... get type() {
... console.log(this)
... }
... }
undefined
>
> const sn = new SyntaxNode({'a': 22222})
undefined
> sn.type
SyntaxNode { tree: { a: 22222 } }
undefined
> Object.getPrototypeOf(sn).type
{}
undefined
so it calls marshalNode({})
:
and tries to set an ArrayBuffer of 6 integers to undefined
(whatever that becomes) 6 (NODE_FIELD_COUNT
) times
I think throwing some kind of error in this case is fine, but a segfault is not. In this case of the issue, the debugger will try to access the getter to see if there's a type that it should show. Maybe it shouldn't, that would be a good patch to have. But accesses are already wrapped in a try/catch and throwing an error is quite reasonable in this case.
Closed in #109.
Thanks for reporting this, I also ran into this issue constantly while working with tree-sitter in VSCode.
I checked that no other properties of the prototypes can segfault with this:
diff --git a/test/node_test.js b/test/node_test.js
index b81c47b..b2e6490 100644
--- a/test/node_test.js
+++ b/test/node_test.js
@@ -412,12 +412,92 @@ describe("Node", () => {
});
describe("VSCode", () => {
- it("shouldn't segfault when accessing properties on the prototype", () => {
+ it("shouldn't segfault when accessing properties/methods on prototype", () => {
+ const parserPrototype = Object.getPrototypeOf(parser);
+ const parserMethods = [
+ // C++ methods
+ "getLogger",
+ "setLogger",
+ "printDotGraphs",
+ // Overwritten methods
+ "setLanguage",
+ "parse",
+ // Node methods
+ "getLanguage",
+ ]
+ // for (const property of parserProperties) {
+ // assert.throws(() => { parserPrototype[property]; }, TypeError)
+ // }
+ for (const method of parserMethods) {
+ try {
+ parserPrototype[method];
+ } catch {}
+ }
+
+
const tree = parser.parse('2 + 2');
+ const treePrototype = Object.getPrototypeOf(tree);
+ const treeProperties = [
+ "rootNode"
+ ]
+ const treeMethods = [
+ // C++
+ "edit",
+ // "rootNode",
+ "printDotGraph",
+ "getChangedRanges",
+ "getEditedRange",
+ "_cacheNode",
+ "_cacheNodes",
+ // Redefined
+ "edit",
+ // Node
+ "walk",
+ ]
+ for (const property of treeProperties) {
+ assert.throws(() => { treePrototype[property]; }, TypeError)
+ }
+ for (const method of treeMethods) {
+ assert.throws(treePrototype[method], TypeError)
+ }
+
+ const treeCursorPrototype = Object.getPrototypeOf(tree.walk());
+ const treeCursorProperties = [
+ // C++
+ "startIndex",
+ "endIndex",
+ "nodeType",
+ "nodeIsNamed",
+ "nodeIsMissing",
+ "currentFieldName",
+
+ // Redefined
+ "currentNode",
+ "startPosition",
+ "endPosition",
+ ]
+ const treeCursorMethods = [
+ // C++
+ "gotoParent",
+ "gotoFirstChild",
+ "gotoFirstChildForIndex",
+ "gotoNextSibling",
+ // Redefined
+ "reset",
+ ]
+ for (const property of treeCursorProperties) {
+ try {
+ treeCursorPrototype[property]
+ } catch {}
+ }
+ for (const method of treeCursorMethods) {
+ assert.throws(treeCursorPrototype[method], TypeError)
+ }
+
const nodePrototype = Object.getPrototypeOf(tree.rootNode);
// const nodePrototype = tree.rootNode.__proto__;
- const properties = [
+ const nodeProperties = [
"type",
"typeId",
"isNamed",
@@ -440,11 +520,7 @@ describe("Node", () => {
"previousSibling",
"previousNamedSibling",
];
- for (const property of properties) {
- assert.throws(() => { nodePrototype[property]; }, TypeError)
- }
-
- const methods = [
+ const nodeMethods = [
"hasChanges",
"hasError",
"isMissing",
@@ -462,7 +538,10 @@ describe("Node", () => {
"descendantForPosition",
"closest",
];
- for (const method of methods) {
+ for (const property of nodeProperties) {
+ assert.throws(() => { nodePrototype[property]; }, TypeError)
+ }
+ for (const method of nodeMethods) {
assert.throws(nodePrototype[method], TypeError)
}
});
But the properties that start out as native code and then are replaced with JS code that calls the original native code might segfault if they are made accessible as they might need to be for #53.
First, clone tree-sitter-typescript
then run the following code
First reported in https://github.com/microsoft/vscode-js-debug/issues/1537?notification_referrer_id=NT_kwDOACIKybI1NDY2NzAyNjkxOjIyMzA5ODU#issuecomment-1504099813