Search code examples
sslrust

Rust reporting "borrowed value does not live long enough" incorrectly?


I have the following construction:

    let data = std::fs::read(args.base).expect("Could not read base file");
    for pem in Pem::iter_from_buffer(&data) {
        let cert = pem.expect("Reading next PEM block failed").clone();
        let x509 = cert.parse_x509().expect("Error decoding x.509 cert");
        certlist.push(x509);
    }

When compiled, I have the following error:

error[E0597]: `cert` does not live long enough
  --> src/main.rs:25:20
   |
24 |         let cert = pem.expect("Reading next PEM block failed").clone();
   |             ---- binding `cert` declared here
25 |         let x509 = cert.parse_x509().expect("Error decoding x.509 cert");
   |                    ^^^^ borrowed value does not live long enough
26 |         certlist.push(x509);
   |         -------- borrow later used here
27 |     }
   |     - `cert` dropped here while still borrowed

This seems strange to me because I'm not using cert on line 26, rather a derivative which should maintain a reference, and which hasn't errored (because I expected it away).

Furthermore, this is effectively a cut/paste from example code for the x509_parser Pem component, which makes me wonder about the quality of the docs.

I can't seem to figure out how to force the cert variable to live longer. Lexically, it's within the same for block - I'm not calling any functions that would cause errors as far as I can tell.


Solution

  • This seems strange to me because I'm not using cert on line 26, rather a derivative which should maintain a reference

    You are correct, the x509 keeps references to data from pem. This is a problem when storing it in certlist since it is outside the for-loop. The pem is destroyed at the end of each iteration while you are trying to preserve the x509 beyond it.

    The documentation you linked to reinforces this:

    Note that all methods require to store the Pem object in a variable, mainly because decoding the PEM object requires allocation of buffers, and that the lifetime of X.509 certificates will be bound to these buffers.

    A solution would be to persist the pems in a separate list. Something like this:

    let data = std::fs::read(args.base).expect("Could not read base file");
    
    let mut pemlist = vec![];
    for pem in Pem::iter_from_buffer(&data) {
        let pem = pem.expect("Reading next PEM block failed");
        pemlist.push(pem);
    }
    
    let mut certlist = vec![];
    for pem in &pemlist {
        let x509 = pem.parse_x509().expect("Error decoding x.509 cert");
        certlist.push(x509);
    }