Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 28 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,18 @@ jobs:

- name: Install GCC
run: |
nix profile install nixpkgs#gcc14
nix profile install nixpkgs#gcc15
echo "$HOME/.nix-profile/bin" >> "$GITHUB_PATH"

# TODO: Currently builds are not fully hermetic. We will care about the state of the machine
# until we can invest in making this repo fully hermetic
- name: Print state
run: |
gcc --version
ulimit -s
cat /etc/os-release
which gcc

- name: Build postgres extension
run: |
cd examples/hello
Expand All @@ -96,13 +105,31 @@ jobs:
nix run .#xpg${{ matrix.pg-version }} -- --options "-c work_mem=8MB" psql -c "DO \$\$ BEGIN ASSERT current_setting('work_mem') = '8MB'; END \$\$;"

# test for cassert enabled build
rm -rf build-${{ matrix.pg-version }}
nix run .#xpg${{ matrix.pg-version }} -- --cassert psql -c "DO \$\$ BEGIN ASSERT current_setting('debug_assertions') = 'on'; END \$\$;"

# test for pg core test
rm -rf ./build-{{ matrix.pg-version }}
if [ "${{ matrix.pg-version }}" -ge 15 ]; then
nix run .#xpg${{ matrix.pg-version }} -- test-core
fi

- name: Test UBSAN reporting
run: |
cd examples/hello
rm -rf ./build-{{ matrix.pg-version }}

# run test with cassert and injected DIV_BY_ZERO error, print all stdout but exit non zero if
# expected error code not found
(HELLO_NULL_PTR_DEREF=1 nix run .#xpg${{ matrix.pg-version }} -- --cassert -v ${{ matrix.pg-version }} test 2>&1 || true) | awk '/runtime error: load of null pointer of type/ { found=1 } { print } END { if (!found) exit 1 }'

- name: Test ASAN reporting
run: |
cd examples/hello
# run test with cassert and injected OOB_WRITE error, print all stdout but exit non zero if
# expected error code not found
(HELLO_OOB_WRITE=1 nix run .#xpg${{ matrix.pg-version }} -- --cassert -v ${{ matrix.pg-version }} test 2>&1 || true) | awk '/SUMMARY: AddressSanitizer: heap-buffer-overflow/ { found=1 } { print } END { if (!found) exit 1 }'

- if: ${{ failure() }}
run: |
cd examples/hello
Expand Down
13 changes: 13 additions & 0 deletions examples/hello/src/hello.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,19 @@ Datum hello(PG_FUNCTION_ARGS){
StringInfoData buf;
initStringInfo(&buf);

// ASAN should flag this
if (getenv("HELLO_OOB_WRITE")) {
char *buf2 = (char *)malloc(4);
buf2[5] = 'A'; // Writing past the 4-byte heap buffer
free(buf2);
}

// UBSAN should flag this
if (getenv("HELLO_NULL_PTR_DEREF")) {
int *i = NULL;
printf("%d\n", *i);
}

appendStringInfoString(&buf, "hello ");
appendBinaryStringInfo(&buf, VARDATA_ANY(input), VARSIZE_ANY_EXHDR(input));

Expand Down
20 changes: 15 additions & 5 deletions nix/postgresql/generic.nix
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,15 @@ let

buildFlags = [ "world" ];

env.CFLAGS =
""
+ lib.optionalString cassertSupport "-fsanitize=undefined -fno-sanitize-recover=all -fno-omit-frame-pointer "
+ lib.optionalString (cassertSupport && stdenv.isDarwin) "-fno-sanitize=function"
# TODO: compiling with clang on darwin with -fsanitize=address results in a binary
# that never returns and pins at 100% CPU saturation of a single core. Possibly
# revisit the below if this ever gets fixed
+ lib.optionalString (cassertSupport && stdenv'.isLinux) "-fsanitize=address";

# Makes cross-compiling work when xml2-config can't be executed on the host.
# Fixed upstream in https://github.com/postgres/postgres/commit/0bc8cebdb889368abdf224aeac8bc197fe4c9ae6
env.NIX_CFLAGS_COMPILE =
Expand Down Expand Up @@ -300,11 +309,12 @@ let
# autodetection doesn't seem to able to find this, but it's there.
checkTarget = "check";

# PG 19+ embeds additional tool paths in installed artifacts, so keep the
# stricter gcc-wrapper reference check only for older versions for now.
disallowedReferences = lib.optionals (lib.versionOlder (lib.versions.major version) "19") [
stdenv'.cc
];
# Prevents hardcoded file paths referencing nix store in pg19
disallowedReferences =
lib.optionals (lib.versionOlder (lib.versions.major version) "19" && !cassertSupport)
[
stdenv'.cc
];

passthru =
let
Expand Down
20 changes: 15 additions & 5 deletions nix/xpg.nix
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,21 @@ let
${
if cassert then
''
if [ "$_arg_cassert" = on ]; then
export PATH=${ourPg."postgresql_${v}_cassert"}/bin:"$PATH"
else
export PATH=${ourPg."postgresql_${v}"}/bin:"$PATH"
fi
if [ "$_arg_cassert" = on ]; then
export PATH=${ourPg."postgresql_${v}_cassert"}/bin:"$PATH"

# See below links
# TODO: detect_stack_use_after_return in ASAN_OPTIONS can be removed after
# below patch lands and is backported, thought it will still need to
# remain for EOL'd versions
# https://www.postgresql.org/message-id/flat/2kk4z4odvuyrg7qlwjd7ft4eron4cle4btb33v4qatgsdkayir%40gj6e62rgsel4
# https://github.com/postgres/postgres/blob/51ae21aa313bb6b79ad914920279cd0d89e92220/.github/workflows/pg-ci.yml#L464

export UBSAN_OPTIONS="print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2"
export ASAN_OPTIONS="print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0"
else
export PATH=${ourPg."postgresql_${v}"}/bin:"$PATH"
fi
''
else
''
Expand Down
Loading