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

XCTRuntimePrecondition results in a memory leak #13

Open
1 task done
Supereg opened this issue Jun 5, 2024 · 2 comments
Open
1 task done

XCTRuntimePrecondition results in a memory leak #13

Supereg opened this issue Jun 5, 2024 · 2 comments
Labels
bug Something isn't working

Comments

@Supereg
Copy link
Member

Supereg commented Jun 5, 2024

Description

When using XCTRuntimePrecondition the precondition methods are overridden and redirected to call neverReturn() which loops forever (see here). This will result in the DispatchWorkItem created in the XCTRuntimePrecondition method to run forever. Fundamentally, this will result in all resources captured by the closures passed to precondition methods to leak over the runtime of the program (refer to here).

Reproduction

Here is a short code example on how to reproduce the issue and to illustrate how this issue is unexpected.

class Test1 {}
func method1(instance: Test1) {
    precondition(instance === Test1(), "The instances was captured in this string as well \(instance)")
}

func foo() {
    let test = Test1()
    print(CFGetRetainCount(test)) // prints 2
    
    try XCTRuntimePrecondition {
        method1(instance: test)
    }

    print(CFGetRetainCount(test)) // prints now 4 instead of 2
    // test will not be deallocated when returning from method foo
}

Expected behavior

Ideally it should not leak memory. Refer to additional context for a discussion.

Additional context

As the source code comment explains in neverReturn(), this seems to be the only option to produce a Never return type. The issue is more about criticizing that this side effect is not documented. Such a memory leak is unexpected especially as we are overloading standard library functions which can go unnoticed.
At the same time the issue should serve as a resource to point at in documentation to explain the issue in great detail and illustrate the possible side effects in testing setups.

Code of Conduct

  • I agree to follow this project's Code of Conduct and Contributing Guidelines
@Supereg Supereg added the bug Something isn't working label Jun 5, 2024
@PSchmiedmayer
Copy link
Member

Thanks for documenting this @Supereg. Just to clarify this here: The memory leak only happens within a testing environment when using XCTRuntimePrecondition so this doesn't affect any production use cases and as test cases are very ephemeral it might not have a longer-lasting impact, even on the system under test?

Agree that some documentation around this might be very helpful!

@Supereg
Copy link
Member Author

Supereg commented Jun 6, 2024

Thanks for documenting this @Supereg. Just to clarify this here: The memory leak only happens within a testing environment when using XCTRuntimePrecondition so this doesn't affect any production use cases and as test cases are very ephemeral it might not have a longer-lasting impact, even on the system under test?

Agree that some documentation around this might be very helpful!

Yes. Important thing to clarify. This issue is only present in a testing environment and when suing e.g. XCTRuntimePrecondition. It doesn't affect production use cases.
I was actively testing deallocation of Modules in StanfordSpezi/Spezi#105 and this is where I uncovered this issue and lost an hour debugging this.
So generally, I would recommend to use XCTRuntimePrecondition test in complete isolation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants