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: data race on client/server shutdown #1228

Closed
wants to merge 1 commit into from

Conversation

tyler92
Copy link
Contributor

@tyler92 tyler92 commented Aug 18, 2024

There is a data race with quite simple scenario:

int main()
{
    const Pistache::Address address("localhost", Pistache::Port(0));

    Pistache::Http::Endpoint server(address);
    Pistache::Rest::Router router;
    server.setHandler(router.handler());

    auto flags       = Pistache::Tcp::Options::ReuseAddr;
    auto server_opts = Pistache::Http::Endpoint::options().flags(flags).threads(1);
    server.init(server_opts);
    server.serveThreaded();

    Pistache::TcpClient client;
    client.connect(Pistache::Address("localhost", server.getPort()));
    client.send(input);

    server.shutdown();
    return 0;
}

Address sanitizer report: asan.txt
As far as I understood it's not legal to modify SyncImpl::handlers_ before SyncImpl::run is finished. So the fix joins worker threads before SyncImpl::handlers_ invalidation.

I'm not sure the fix is correct from the original design point of view, but on my local machine, ASAN is happy with the provided example.
I think the following issues are related: #842 #1018 #539

@kiplingw
Copy link
Member

Hey @tyler92. Thanks for the PR. Question for you. Isn't serveThreaded() intended to not block by design?

@tyler92
Copy link
Contributor Author

tyler92 commented Aug 18, 2024

Hey @tyler92. Thanks for the PR. Question for you. Isn't serveThreaded() intended to not block by design?

Hi. Yes, you are right. So in my example, I launch the server with serveThreaded, make a request, and shut down the server immediately. This scenario is used for unit tests, fuzzing testing, etc. The problem is that there is a data race and if these tests are running with address/thread sanitizer, they will fail due to sanitizer warning.

@kiplingw
Copy link
Member

Might the solution then be to change the unit tests to use the blocking version instead?

@tyler92
Copy link
Contributor Author

tyler92 commented Aug 18, 2024

As a workaround - yes, it's possible.

But we still have a problem with the current solution: how to stop the server after serveThreaded without a data race?

@kiplingw
Copy link
Member

But isn't that the expected behaviour though? If the user requested to start the server asynchronously?

@tyler92
Copy link
Contributor Author

tyler92 commented Aug 18, 2024

If a user called serveThreaded - of course the expected behavior is that the server started asynchronously.

But even in this scenario the user should be able to stop and destroy the server correctly, without data races and other memory issues. Right now it's now possible as far as I could see

@kiplingw
Copy link
Member

Ok, that makes sense. I'll wait to hear @Tachi107 and @dgreatwood's thoughts.

@tyler92
Copy link
Contributor Author

tyler92 commented Aug 18, 2024

OK. Just for clarification - I don't insist on my solution, probably there is a more correct way to achieve the same result

@dgreatwood
Copy link
Contributor

dgreatwood commented Aug 18, 2024 via email

@dgreatwood
Copy link
Contributor

dgreatwood commented Aug 20, 2024 via email

@tyler92
Copy link
Contributor Author

tyler92 commented Aug 21, 2024

#1229 (comment)

I haven't looked at the other proposed changes in tests/tcp_client.h, though they look logical at first glance.

Yes, it's a "bonus" change that fixes FD leak, but I can PR it separately

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.

3 participants