diesel-rs/diesel

Segmentation Fault in R2D2 postgres (interrupted by signal 11: SIGSEGV)

alwinc opened this issue · 10 comments

Setup

Linux Ubuntu 20.04.6 LTS 64Bit

Versions

  • Rust: 1.73.0 STABLE
  • Diesel: 2.1.3
  • Database: Postgres SQL 12.16
  • Operating System Linux Ubuntu 20.04.6 LTS 64Bit

Feature Flags

  • diesel: ["postgres", "r2d2"]

Problem Description

When attempting to connect to postgres with connection pooling via r2d2 there appears to be a SIGSEGV fault

    let manager = ConnectionManager::<PgConnection>::new("postgres://name:pass@localhost:5432/db");

    Pool::builder()
        .min_idle(None)
        .max_size(9)
        .test_on_check_out(true)
        .build(manager).unwrap()

Diving further in it appears to crash at a segment of unsafe code
src->pg->connection->raw
line 24

impl RawConnection {
    pub(super) fn establish(database_url: &str) -> ConnectionResult<Self> {
        let connection_string = CString::new(database_url)?;
        let connection_ptr = unsafe { PQconnectdb(connection_string.as_ptr()) }; <-- SIGSEGV fault here ?
        let connection_status = unsafe { PQstatus(connection_ptr) };

I get returned

Process finished with exit code 139 (interrupted by signal 11: SIGSEGV)

What are you trying to accomplish?

Establish a connection pool to postgres db via r2d2 on latest version of diesel and rust

What is the expected output?

Not a SIGSEGV

What is the actual output?

Process finished with exit code 139 (interrupted by signal 11: SIGSEGV)

Are you seeing any additional errors?

Panics at this point

Steps to reproduce

Unsure if there are cargo conflicts causing this issue?
Copy a copy of Cargo.toml

actix = "^0.13.0"
actix-broker = "0.4.3"
actix-cors = "0.6.3"
actix-files = "0.6.2"
actix-http = "3.2.2"
actix-rt = "~2.8.0"
actix-service = "2.0.2"
actix-web = { version = "~4.3.1", features = ["openssl"] }
actix-web-actors = "4.1.0"
anyhow = "1.0.55"
chrono = "0.4"
config = { version = "0.13" }
diesel = { version = "2.1.3", features = ["postgres", "r2d2"] }
derivative = "2.2.0"
dotenv = "0.15.0"
env_logger = "0.10.0"
futures = "0.3.1"
hex = "0.4.3"
hmac = "0.12.1"
lazy_static = "1.4.0"
libmath = "0.2"
log = "0.4"
log-panics = { version = "2.0.0", features = ["with-backtrace"] }
log4rs = "1.2.0"
openssl = { version = "0.10.42", features = ["vendored"] }
priority-queue = "1.3.1"
rand = "0.8.5"
reqwest = { version = "0.11.3", features = ["default-tls", "blocking", "json"] }
options_core = { path = "../options-core" }
serde = { version = "1.0.125", features = ["derive"] }
serde_json = "1.0.64"
serde_qs = "0.12.0"
sha2 = "0.10.6"
strum = "0.24"
strum_macros = "0.24"
tokio = { version = "1.6.0", features = ["time", "rt", "macros"] }
tokio-tungstenite = { version = "0.20", features = ["native-tls"] }
url = "2.0.0"
uuid = { version = "1.3.1", features = ["v4"] }
wait-for-me = "0.2.0"

The full function

fn dbconnect() -> Pool<ConnectionManager<PgConnection>> {
    let config_result = EnvConfig::new();
    if config_result.is_err() { panic!("Unable to parse Config - [{:?}]", config_result); }
    let config = config_result.unwrap();

    let database_url = config.database.url; // postgres://name:pass@localhost:5432/db
    let pool_size = config.database.max_pool_size;

    let manager = ConnectionManager::<PgConnection>::new(database_url.clone());

    Pool::builder()
        .min_idle(None)
        .max_size(pool_size)
        .test_on_check_out(true)
        .build(manager).unwrap()
}

Checklist

  • This issue can be reproduced on Rust's stable channel. (Your issue will be
    closed if this is not the case)
  • This issue can be reproduced without requiring a third party crate

Thanks for filling this bug report. As of now that reads pretty hard to reproduce, therefore I would like to ask if you can provide a reproducing example as docker image? Otherwise I fear that we cannot do much here

Yes I'll try and put together an image. Any suspicions as to what the cause might be at a high level? I notice it creates a Cstring and when it gets to the offending line 24, I get a segfault... *shrugs

As this kind of setup works for a lot of workload (including for example crates.io) I do not have any suspicions what might be wrong there (or if that's even an issue in diesel).

I had another look at your dependency list and noticed this line:

openssl = { version = "0.10.42", features = ["vendored"] }

This might be problematic, as diesel depends on libpq, which is linked dynamically. Libpq depends on openssl. If you now link a different openssl version statically that might result in such segfaults.

@weiznich
Found something - It seems that upgrading Config to version 0.13.3 caused this error https://crates.io/crates/config/0.13.3.
Not sure how - but I downgraded that crate to 0.10.1 refactored to use different config file format and it works fine.

Strange that this error pops up on Diesel end.

Can you try if the error goes away when you disable the "vendored" flag for openssl?

Can you try if the error goes away when you disable the "vendored" flag for openssl?

Yes did give that a go - as well as removed the entire dependency after realizing it was not required explicitly and it still causes SIGSEGV.

Hmm, that's interesting. It still would be interesting to have some minimal example of that crash.

Closed as we don't have a reproducing example for this issue.

I had another look at your dependency list and noticed this line:

openssl = { version = "0.10.42", features = ["vendored"] }

This might be problematic, as diesel depends on libpq, which is linked dynamically. Libpq depends on openssl. If you now link a different openssl version statically that might result in such segfaults.

It works when I remove the "vendored" features
Or display the mem leak