-
Notifications
You must be signed in to change notification settings - Fork 235
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 stack overflow on audio change #285
Fix stack overflow on audio change #285
Conversation
2ea902b
to
99c0c36
Compare
Ok I managed to reproduce it as per the above. My goal is to determine a correlation between the length of I added the following right at the start of fn drop(&mut self) {
let mut count = 0;
let mut cursor = self.next.lock().unwrap().clone();
loop {
if let Frame::Data(data) = &*cursor.clone() {
let next = data.next.lock().unwrap();
cursor = next.clone();
} else {
break;
}
count += 1;
}
println!("count: {}", count);
return;
... ...to measure the length of the chain. As an added bonus, the above code runs every time one of the nested No crash:
Crash:
Then I got rid of the |
Drop
for FrameData
0650ba2
to
a68f146
Compare
The types `Frame` and `FrameData` are mutually recursive, and the incidental linked lists that can be formed as a result can be long (at least in the order of thousands of elements). As a result, when a frame is deallocated, rust appears to recursively call `drop_in_place` down the list, causing stack overflows for long lists.
a68f146
to
b1606ee
Compare
Squashed fix up commits and rebased onto the tip of master |
@nicokoch any thoughts on whether this change is ok to merge? Would you like me to rebase it onto master? |
Bump? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok except for detail. Sorry for the delay.
// the `next` field will contain a `Frame::End`, or an `Arc` with additional references, | ||
// so the depth of recursive drops will be bounded. | ||
loop { | ||
if let Ok(arc_next) = self.next.get_mut() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be turned into a while let, no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This has sat unreviewed for more than a year. I'm merging despite the small issue. Subsequent PRs for improvement are welcome!
Thanks for the merge @est31! I'll make the change you suggested in a subsequent PR. |
The types
Frame
andFrameData
are mutually recursive, and theincidental linked lists that can be formed as a result can be long (at
least in the order of thousands of elements). As a result, when a frame
is deallocated, rust appears to recursively call
drop_in_place
downthe list, causing stack overflows for long lists.
Addresses #283
This problem is hard to reproduce. I've tried constructing toy programs to no avail. The only way I've managed to trigger it is running https://github.com/stevebob/slime99/
graphical
oransi-terminal
crates with the--audio
flag (audio is disabled by default because of exactly this problem). Start a new game and leave it on the first floor for ~5 minutes, then walk down the stairs. The track will switch and sometimes there will be a stack overflow on the "rodio audio processing" thread.I was able to reliably reproduce the problem last night, but I'm trying to again now (after changing nothing) and it's not happening. Something something phase of the moon. In other words, I'm not satisfied with my testing of this patch thus far. I'm opening this PR now to start a discussion. Is there a way to construct a long chain of
Frame
->FrameData
->Frame
->...? I think doing so would reliably trigger this problem.