Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GDScript 2.0: Stack overflow in setter #47662

Closed
Blackiris opened this issue Apr 6, 2021 · 2 comments · Fixed by #47672
Closed

GDScript 2.0: Stack overflow in setter #47662

Blackiris opened this issue Apr 6, 2021 · 2 comments · Fixed by #47672

Comments

@Blackiris
Copy link
Contributor

Godot version:
4.0 c647e41

OS/device including version:
Archlinux

Issue description:
The following code provoke a Stack Overflow (Stack Size: 1024)

class_name OnOffObject
extends Node3D

var objname : String:
	set(val):
		objname = val
		pass

func _ready():
	objname = "aa"
	print("Name:"+ objname)

Steps to reproduce:
Open the reproduction project and launch it

Minimal reproduction project:
SetterStackOverflow.zip

Analysis
It is obvious that the bug happens because, in the setter, the assignment objname = val is replaced by the setter itself, creating an infinite calls (until it reaches 1024).
I thought it was a mistake in my code, but I have complied with the example defined in godotengine/godot-proposals#844 (see warns_when_changed).

The reason is that in gdscript_compiler, when parsing the setter (_parse_setter_getter > _parse_block > _parse_expression), the compiler replace the var assignment with its corresponding setter:

bool has_setter = false;
bool is_in_setter = false;
StringName setter_function;
if (assignment->assignee->type == GDScriptParser::Node::IDENTIFIER) {
StringName var_name = static_cast<const GDScriptParser::IdentifierNode *>(assignment->assignee)->name;
if (!codegen.locals.has(var_name) && codegen.script->member_indices.has(var_name)) {
setter_function = codegen.script->member_indices[var_name].setter;
if (setter_function != StringName()) {
has_setter = true;
is_in_setter = setter_function == codegen.function_name;
target.mode = GDScriptCodeGenerator::Address::MEMBER;
target.address = codegen.script->member_indices[var_name].index;
}
}
}

Don't know if there is a way to disable this replacement only if it is dealing with the same setter code.

@Blackiris
Copy link
Contributor Author

Blackiris commented Apr 6, 2021

Well, in fact it is trying to detect if is is in the setter with the line:
is_in_setter = setter_function == codegen.function_name;

However, in my case, codegen.function_name is not defined... I will have a look at how it could happen.

[EDIT] In _parse_function, there is the line:
codegen.function_name = func_name;
But not in _parse_setter_getter, where func_name is computed but not set in codegen.function_name

@Blackiris
Copy link
Contributor Author

In _parse_setter_getter, just after the block:

StringName func_name;

if (p_is_setter) {
	func_name = "@" + p_variable->identifier->name + "_setter";
} else {
	func_name = "@" + p_variable->identifier->name + "_getter";
}

I can confirm that adding the following line fixes the issue:
codegen.function_name = func_name;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants