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

Using asan-enabled libpq is impossible due to inability to pass linker options to cc #70

Open
alexanderlaw opened this issue Jan 7, 2025 · 7 comments

Comments

@alexanderlaw
Copy link

When trying to use asan-enabled libpq (as a part of a complete postgres build), compiled as follows:

CC=gcc CFLAGS="-Og -fsanitize=address -fsanitize=undefined -fno-sanitize-recover" \
LDFLAGS="-fsanitize=address -fsanitize=undefined -static-libasan -static-libubsan" \
./configure --prefix=/home/vagrant/pg --enable-debug --enable-cassert -q && \
make -j8 -s && ASAN_OPTIONS=detect_leaks=0 make -s check && make -s install

I've stumbled upon the inability to use this libpq with pq-sys. Please look at a simple demo script:

cargo new pq-sys-test

cd pq-sys-test

echo 'pq-sys = "0.6"' >>Cargo.toml

echo 'extern crate pq_sys;

fn main() {
    unsafe {
        pq_sys::PQinitSSL(1);
    }
    println!("OK");
}
' >src/main.rs

PQ_LIB_DIR="/home/vagrant/pg/lib" cargo build

which fails for me with the following errors:

...
   Compiling pq-sys-test v0.1.0 (/home/vagrant/pq-sys-test)
error: linking with `cc` failed: exit status: 1
  |
  = note: LC_ALL="C" PATH="..." VSLANG="1033" "cc" ...

  = note: /usr/bin/ld: /home/vagrant/pg/lib/libpq.so: undefined reference to `__asan_poison_stack_memory'
          /usr/bin/ld: /home/vagrant/pg/lib/libpq.so: undefined reference to `__asan_init'
...
  = note: some `extern` functions couldn't be found; some native libraries may need to be installed or have their path specified
  = note: use the `-l` flag to specify native libraries to link
  = note: use the `cargo:rustc-link-lib` directive to specify the native libraries to link with Cargo (see https://doc.rust-lang.org/cargo/reference/build-scripts.html#rustc-link-lib)

error: could not compile `pq-sys-test` (bin "pq-sys-test") due to 1 previous error

I guess, this issue can be resolved with something like:

    println!("cargo:rustc-link-arg=-fsanitize=address");
    println!("cargo:rustc-link-arg=-fsanitize=undefined");
    println!("cargo:rustc-link-arg=-static-libasan");
    println!("cargo:rustc-link-arg=-static-libubsan");

Probably an additional environment variable like PQ_LINK_OPTIONS="-fsanitize=address -fsanitize=undefined -static-libasan -static-libubsan" could work?

(The same procedure completes successfully with postgres compiled without sanitizers enabled.)

@weiznich
Copy link
Collaborator

weiznich commented Jan 7, 2025

I'm happy to accept a PR for this as long as it contains a sufficient amount of documentation.

@alexanderlaw
Copy link
Author

Thank you for paying attention to this!

But after some experiments, I've discovered that those options don't work. The only way to use such libpq, that I've found, is to use static library and specify sanitizer libs explicitly, and also specify additional postgres libs:

--- a/build.rs
+++ b/build.rs
@@ -111,6 +111,11 @@ fn main() {
     println!("cargo:rustc-link-lib=pq");
     println!("cargo:rerun-if-env-changed=PQ_LIB_STATIC");
     println!("cargo:rerun-if-env-changed=TARGET");
+    println!("cargo:rustc-link-lib=asan");
+    println!("cargo:rustc-link-lib=ubsan");
+    println!("cargo:rustc-link-lib=pgport");
+    println!("cargo:rustc-link-lib=pgcommon");
+    println!("cargo:rustc-link-lib=pgcommon_shlib");
 
$ cargo clean; PQ_LIB_STATIC=1 PQ_LIB_DIR="/home/vagrant/pg/lib" cargo test
...
running 14 tests
test bindings::bindgen_test_layout_PQArgBlock ... ok
test bindings::bindgen_test_layout_PQArgBlock__bindgen_ty_1 ... ok
test bindings::bindgen_test_layout__G_fpos64_t ... ok
test bindings::bindgen_test_layout__G_fpos_t ... ok
test bindings::bindgen_test_layout__IO_FILE ... ok
test bindings::bindgen_test_layout__IO_cookie_io_functions_t ... ok
test bindings::bindgen_test_layout__PQconninfoOption ... ok
test bindings::bindgen_test_layout__PQprintOpt ... ok
test bindings::bindgen_test_layout___fsid_t ... ok
test bindings::bindgen_test_layout___mbstate_t ... ok
test bindings::bindgen_test_layout___mbstate_t__bindgen_ty_1 ... ok
test bindings::bindgen_test_layout___va_list_tag ... ok
test bindings::bindgen_test_layout_pgNotify ... ok
test bindings::bindgen_test_layout_pgresAttDesc ... ok

test result: ok. 14 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.03s

     Running tests/smoke.rs (target/debug/deps/smoke-4d2c864b79117680)

running 1 test
test test_ssl_init ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

So it's not clear to me yet how this can be resolved — maybe with something like PQ_EXTRA_LIBS="asan ubsan ..."...

@weiznich
Copy link
Collaborator

weiznich commented Jan 8, 2025

If you goal is to purely have a Asan enabled libpq build you can try to use the same approach as diesel: https://github.com/diesel-rs/diesel/blob/master/.github/workflows/ci.yml#L341-L344

@alexanderlaw
Copy link
Author

Thanks for the reference, but I think they still use standard libpq installed above:
sudo apt-get install -y libpq-dev postgresql valgrind
and asan is enabled only for Rust code.

@weiznich
Copy link
Collaborator

weiznich commented Jan 8, 2025

That command builds its own copy of libpq with sanitizer support enabled. The important bit is the pq-src/with-asan feature in combination with the bundled build. The rust side Asan setup is required as well.

The relevant building code is here: https://github.com/sgrif/pq-sys/blob/master/pq-src/build.rs#L200

@alexanderlaw
Copy link
Author

Thank you for the explanation!

The approach with the bundled libpq really works for diesel test, but unfortunately, the "diesel" crate doesn't export such a feature (postgres-bundle-asan or alike), only "diesel-cli" does (and even it exports postgres-bundle, not postgres-bundle-asan). So the question "how to use (prebuilt) asan-enabled libpq" looks still open to me (except for static linking, described above).

@weiznich
Copy link
Collaborator

weiznich commented Jan 9, 2025

You don't need these features to exist on diesel. Crate features are additive, which means you can just add the relevant crate (pq-sys and pq-src in this case) to your Cargo.toml file and enable the features directly there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants