diesel-rs / diesel

A safe, extensible ORM and Query Builder for Rust
https://diesel.rs
Apache License 2.0
12.76k stars 1.07k forks source link

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

Closed alwinc closed 11 months ago

alwinc commented 1 year ago

Setup

Linux Ubuntu 20.04.6 LTS 64Bit

Versions

Feature Flags

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

weiznich commented 1 year ago

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

alwinc commented 1 year ago

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

weiznich commented 1 year ago

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).

weiznich commented 1 year ago

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.

alwinc commented 1 year ago

@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.

weiznich commented 1 year ago

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

alwinc commented 1 year ago

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.

weiznich commented 1 year ago

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

weiznich commented 11 months ago

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

WuJiY commented 10 months ago

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