Does the compiler interprets assert! as an optimization hint?

58 points barbouk

I am facing a weird bug in my program which reproduces 100% but is quite hard to extract in a standalone program, as it involves making 2 successives OIDC logins. The code mentionned below is part of a function that pops up a browser, starts a local HTTP server on a static port and expects an interactive OIDC login from the user, with a redirect. The goal being to get back the OIDC code returned through that interactive browser sequence. The \serve()\\ function below is what serves the HTTP browser requests.

I have a problem that only happens when I run two successive - but distinct - OIDC logins. The local HTTP server is closed, destroyed and another one is started for the second login. There is no reuse of resources in-between logins.

The problem is described in the code segment hereafter:

#[derive(Debug)]
struct Service {
    tx_params: Mutex<Option<Sender<AuthorizationInfo>>>,
}

impl Service {
    fn new(
        tx_params: tokio::sync::oneshot::Sender<AuthorizationInfo>,
    ) -> Arc<Self> {
        Arc::new(Self {
            tx_params: Mutex::new(Some(tx_params)),
        })
    }

    async fn serve(self: Arc<Self>, req: Request<Body>) -> Result<Response<Body>, hyper::Error> {
        debug!("received callback request: {req:?}");

        // This oneshot channel Sender would be used with a `.take()` to send back the received OIDC code outside the HTTP request handling code...
        let mut tx_params = self.tx_params.lock().await;

        warn!("1: {}", tx_params.is_some());

        // Removing this assert causes BOTH logs to print "false"...
        // Putting it back causes both logs to print "true"...
        assert!(tx_params.is_some());

        warn!("2: {}", tx_params.is_some());

        // Some more irrelevant code that doesn't use `tx_params` at all.
    }
}

I am a bit at a loss understand what could happen here: the \tx\\_params\\ field is created as an \Option::Some(..)\\ and no other code path can make it not be \Option::Some(..)\\.

When I receive a request in the handler I lock the mutex and display whether the option is \Some\\ or \None\\.

In my tests, I happen to trigger that code path twice in a quick sequence. The first time, everything works as expected and \tx\\_params\\ is \Some\\ regardless of the presence of the \assert!\\. The second time, 100% of the time, and only if the \assert!\\ isn't there, the second run will show it to be \None\\. This second run involves a completely different instance of \Service\\ (NOT the same instance). There is no reuse of instances in-between the two invokations.

No what bothers me is that the bug disappears completely if I put that nonsensical \assert!\\. I am at loss understand what could happen here. Did I just stumble on a weird compiler bug?

(I realize I likely don't give enough information for anyone to provide a definite answer : I will keep trying to make it a reproducible, isolate sample).