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

Fix TrackCache memory crash #85266

Merged
merged 1 commit into from Nov 23, 2023
Merged

Conversation

KoBeWi
Copy link
Member

@KoBeWi KoBeWi commented Nov 23, 2023

Fixes #85250
Fixes #85233

@akien-mga
Copy link
Member

There's a bunch of errors with GCC and Clang, see https://github.com/godotengine/godot/pull/85266/files or the CI logs.

case Animation::TYPE_VALUE: {
AnimationMixer::TrackCacheValue *src = static_cast<AnimationMixer::TrackCacheValue *>(p_cache);
AnimationMixer::TrackCacheValue *tc = memnew(AnimationMixer::TrackCacheValue);
memcpy((void *)tc, src, sizeof(AnimationMixer::TrackCacheValue));
Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure it'll be safe to ignore this warning, I don't think it's overly careful saying not to memcpy virtual classes

Copy link
Member Author

Choose a reason for hiding this comment

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

How it should be handled otherwise?

Copy link
Member

Choose a reason for hiding this comment

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

With a copy constructor or copy assignment, as per the error suggestion I'd say

Copy link
Member Author

Choose a reason for hiding this comment

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

From what I understand, this is only a problem if we ever add a new cache type that inherits a subtype AND the new type will use an existing enum value. It's unlikely and that would be a bug in itself, so it's not really a concern IMO.

Copy link
Member

Choose a reason for hiding this comment

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

As long as the copying of the vtable is safe

One point further: is it really safe to memcpy a HashMap? Will it perform copy construction of that? Otherwise the pointers might be incorrect

Copy link
Member

Choose a reason for hiding this comment

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

How do you mean? The audio track cache has a hash map in it, how is it not copied? The classes are copied here?

Copy link
Member

Choose a reason for hiding this comment

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

If that is a problem, it may be safe not to copy for the audio, method, and animation tracks although I think the more problem is that the Reset track is allowed for them in the first place.

Copy link
Member

Choose a reason for hiding this comment

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

It's be safe to copy just as long as you do a copy with the constructor and not just a raw copy of the memory, copying the memory stored in a hash map is unsafe as it uses raw data

This is what the first error that was popping up was about, it warns when the copy constructor isn't trivial, i.e. POD or like

Copy link
Member

Choose a reason for hiding this comment

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

I haven't tested it as I'm not able to right now but my assumption here is that the members of these classes are copied wholesale byte by byte, but the problem with that is that at least HashMap is going to be unsafe if it is copied that way, as it handles memory by pointers, in the "best" case the resulting copied map would share data with the original, which at minimum causes problems with manipulation of one, might cause crashes due to invalid pointer access in the worst case

I also am not sure it's safe to memcpy a Ref as it should do refcounting and I suspect you'd have a double-reference in two elements, so no additional referencing would happen, causing extra freeing

I'd simply suggest copy constructors be added, it's simple enough and safe

Copy link
Member

Choose a reason for hiding this comment

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

I agree so much with @AThousandShips that I've made #85302.

scene/animation/animation_mixer.cpp Outdated Show resolved Hide resolved
scene/animation/animation_mixer.cpp Outdated Show resolved Hide resolved
Copy link
Member

@TokageItLab TokageItLab left a comment

Choose a reason for hiding this comment

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

There is concern about the safety of memcpy with virtual above, but the major crash problem should have been resolved for now.

@KoBeWi KoBeWi force-pushed the copy_more_RAM branch 2 times, most recently from 8f63b3e to e28ff3f Compare November 23, 2023 19:06
@akien-mga
Copy link
Member

Tested on Linux with GCC, I confirm this fixes the MRP in #85233.

The concerns outlined by @AThousandShips above still need further consideration, but given that this seems to fix the crashes on Windows and Linux without apparent further regression, I'm merging it already to include into the 4.2-rc2 build I'm starting now.

Worse cast if there's some data corruption with the way hashmaps are copied, it shouldn't be worse than what we currently have before this PR. 💦

@akien-mga akien-mga merged commit e6c8d40 into godotengine:master Nov 23, 2023
15 checks passed
@akien-mga
Copy link
Member

Thanks!

@KoBeWi KoBeWi deleted the copy_more_RAM branch November 23, 2023 23:56
@AThousandShips
Copy link
Member

AThousandShips commented Nov 24, 2023

Crossing my fingers it won't cause any problems, not familiar enough with it to test it specifically, but the thing to look out for is likely data loss, and the likely most visible error would be the safety check failing in SafeRefcount due to duplication, without increment, might also break Vector and Variant as they are also refcounted and could cause unbalanced decrement

Fortunately fixing it is trivial if there are issues, just add some copy constructors (might not even need explicit ones) and use memnew(Type(*old)) instead

Can throw together something when I have the time (likely not until tomorrow) just to be safe going forward, the change should be free for most of the cases as most of the types are trivially copyable

For some context, see here

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

Successfully merging this pull request may close these issues.

Random crash when saving scene Crash on reimport when applying AnimatedValueBackups from an Apply Reset
5 participants