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

Test and Fixed for SharedPtr leak #46

Merged
merged 6 commits into from
Oct 1, 2023

Conversation

elcritch
Copy link
Contributor

See #45.

@elcritch elcritch mentioned this pull request Sep 15, 2023
@elcritch elcritch changed the title Test for SharedPtr leak Test and Fixed for SharedPtr leak Sep 16, 2023
if p.container != nil:
# this `fetchSub` returns current val then subs
# so count == 1 means we're the last
if p.container.counter.fetchSub(1, Release) == 1:
Copy link
Member

Choose a reason for hiding this comment

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

Returning the current value and then decrementing sounds like an unnatural CPU instruction. Are you sure this generates good code?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Most of the atomics I've seen return the value after modification.

I haven't looked at the generated code but figure the C intrinsics are correct. Looks like ARM64 does some sort of register locking and the operations inside are flexible: https://stackoverflow.com/a/35218319 Maybe there's performance implications? I sorta thought they had specific atomic instructions, but sounds like x86_64 does something similar. Though this guy seems a bit different: https://devblogs.microsoft.com/oldnewthing/20220811-00/?p=106963

The std/atomics version does the decrement and returns the result. It took me a bit to figure out the difference. Both work and pass tests.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Contributor Author

@elcritch elcritch Sep 17, 2023

Choose a reason for hiding this comment

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

Ah, I think I get it a bit. The release mode makes the atomic register-load strictly ordered, so returning that value (the original) makes sense whereas the atomic register-write at the end isn't as strict.

I think doing sub_fetch would need to have acquire mode. The names seem sorta backwards to me.

@elcritch
Copy link
Contributor Author

@Araq any word on this?

It'd be nice to get the standard repo stable since I am also getting memory allocator corruption when using the master branch.

I suspect use after frees. I don't have the time to prove it, but this branch works like a charm.

There's probably a sequence where one thread gets 0 thinking its ready to free, but before doing so another takes it's first copy that'd lead to a double free or use-after-free.

@Araq
Copy link
Member

Araq commented Sep 29, 2023

Rename it back to val please.

@elcritch
Copy link
Contributor Author

Rename it back to val please.

Ah, that was my favorite part. Ok done.

threading/smartptrs.nim Outdated Show resolved Hide resolved
threading/smartptrs.nim Outdated Show resolved Hide resolved
threading/smartptrs.nim Outdated Show resolved Hide resolved
Change back to zero based count to restore good behavior with `default()`
threading/smartptrs.nim Outdated Show resolved Hide resolved
@Araq Araq merged commit 7c033b9 into nim-lang:master Oct 1, 2023
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants