Skip to content

Fixed memory leak with String objects#307

Merged
Zylann merged 1 commit intogodotengine:masterfrom
aqnuep:string_memory_leak_fix
Aug 15, 2020
Merged

Fixed memory leak with String objects#307
Zylann merged 1 commit intogodotengine:masterfrom
aqnuep:string_memory_leak_fix

Conversation

@aqnuep
Copy link
Contributor

@aqnuep aqnuep commented Jun 21, 2019

The member _godot_string should never be straight out overwritten ever without
first destroying the underlying string object's memory. This change solves the
problem through the introduction of a new private constructor to create String
objects with a pre-existing godot_string handle.

@2shady4u
Copy link
Contributor

2shady4u commented Aug 2, 2019

You aren't obeying the Clang format and therefore your build fails.
Could you update your commit to adhere to this format?

Copy link
Contributor

@2shady4u 2shady4u left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Following edits should be made to obey the Clang format rules

@aqnuep
Copy link
Contributor Author

aqnuep commented Aug 2, 2019

Sorry, I didn't notice, but I'll fix the issues.

@aqnuep aqnuep force-pushed the string_memory_leak_fix branch from fc7239a to a3e7696 Compare August 3, 2019 18:46
@aqnuep
Copy link
Contributor Author

aqnuep commented Aug 3, 2019

Fixed. Thanks for taking a look at this!

@Calinou
Copy link
Member

Calinou commented Mar 19, 2020

Should this pull request be merged now that #333 has been merged?

cc @BastiaanOlij

@BastiaanOlij
Copy link
Collaborator

Sounds like a plan if someone can resolve the conflicts.
Not sure how we can best go about testing whether this now works correctly

@aqnuep aqnuep force-pushed the string_memory_leak_fix branch 3 times, most recently from b1ce289 to d995f93 Compare March 22, 2020 12:02
@aqnuep
Copy link
Contributor Author

aqnuep commented Mar 22, 2020

Should be conflict-free now, but let's see the checks.

@Zylann
Copy link
Collaborator

Zylann commented Jun 5, 2020

About testing, I'm thinking of this #413

@Zylann
Copy link
Collaborator

Zylann commented Aug 14, 2020

I'm trying to reproduce a case of memory leak, but not getting one so far.
I called this many times per frame:

void NativeTest::test_create_strings() {
	String::num_int64(42);
}

What code should I use to reproduce the original problem?

After some digging in Godot codebase, it turns out String() constructor does nothing. And its only member, CowData<CharType>, also has a default constructor that does nothing more than setting a pointer to nullptr (that pointer representing the full data of a godot_string). So no heap allocation occurs when String() is created without argument, and no leak happened when we overwrote _godot_string.

Although, it is true that from an API standpoint it should be used properly, even if default construction happen to allocate nothing.
I'm ok to merge but there are missing functions in your PR, as commented below.


void String::operator+=(const String &s) {
_godot_string = godot::api->godot_string_operator_plus(&_godot_string, &s._godot_string);
*this = String(godot::api->godot_string_operator_plus(&_godot_string, &s._godot_string));
Copy link
Collaborator

@Zylann Zylann Aug 14, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Creating a new string on += looses a big advantage += normally has: exploiting capacity, instead of reallocating an entire buffer for every line, or every character being inserted at the end. If it's not available in the C API we may have to ask for it.
Can't do much in this PR but need to keep track of it

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I'm aware of it. Unfortunately we have to live with that limitation for now AFAICT.

return godot::api->godot_string_naturalnocasecmp_to(&_godot_string, &p_str._godot_string);
}

String String::dedent() const {
Copy link
Collaborator

@Zylann Zylann Aug 14, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where did those functions go?
They were added after b895d3c but maybe you didn't rebase on the right version?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry about that. It looks like somehow that got removed unintentionally during rebasing and I didn't notice it. I'll fix it in a moment.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI, not sure what caused the merging issue here, because in my local version those new functions were untouched. Anyway, I did a forced push to resolve this problem.

@Zylann Zylann added the enhancement This is an enhancement on the current functionality label Aug 14, 2020
@aqnuep
Copy link
Contributor Author

aqnuep commented Aug 15, 2020

What code should I use to reproduce the original problem?

The problematic API that caused memory leaks was the "+=" operator which, unlike all other modification operations, replaced the "_godot_string" member's value without first destroying its previously held godot_string object.

All the other APIs I modified return a new String object, so there my changes only really make a refactoring effort for simpler and more unified code (previously things were done differently in a few cases).

However, the "+=" operator does in-place modification of the String object (needing an in-place replacement of the underlying godot_string object due to lack of a "+=" operator in the C API), and the previous code didn't take care of destroying the old value held, thus leaking that memory at every call.

The member _godot_string should never be straight out overwritten ever without
first destroying the underlying string object's memory. This change solves the
problem through the introduction of a new private constructor to create String
objects with a pre-existing godot_string handle.
@aqnuep aqnuep force-pushed the string_memory_leak_fix branch from d995f93 to 0939d0f Compare August 15, 2020 07:49
@Zylann Zylann merged commit 756c1e1 into godotengine:master Aug 15, 2020
@Zylann
Copy link
Collaborator

Zylann commented Aug 15, 2020

Thanks!

@Zylann Zylann mentioned this pull request Aug 15, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement This is an enhancement on the current functionality

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants