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

postgresql: split -lib and -dev outputs cleanly #294504

Merged
merged 6 commits into from
Aug 24, 2024

Conversation

wolfgangwalther
Copy link
Contributor

@wolfgangwalther wolfgangwalther commented Mar 9, 2024

Description of changes

TLDR: This splits outputs for the postgresql package cleanly, using a minimum of patching and/or nuking of references. Instead, dead references to other store paths are removed at compile and link time. The minimal -lib output is then added as a top-level libpq package.

This builds on my previous work in #292993 and #293996 and contains commits from those two branches. Please ignore the first ~20 commits here and provide feedback for those in the two other PRs. This PR starts with treewide: prepare pg_config moving to dev. This commit (by @jtojnar) and the 4 commits after (by @SuperSandro2000) were cherry-picked from #179962. Compared to #179962, the approach taken in this PR is simpler and requires far less patching of postgresql source code. In fact, the overall size of patches is reduced compared to before and fewer references needed to be removed afterwards.

While the most work here involved splitting the -dev output, a clean -lib output comes with that naturally. Thus, this PR replaces #179962 and #273175. The cleaned up lib output was discussed in #61580 (comment) (@thoughtpolice). With this output available, it's easy to create a top-level attribute libpq pointing to the latest version's lib output automatically as suggested by @danbst in #61580 (comment), which should resolve #61580 (@nh2). A true separate libpq package as proposed in #234470 (@szlend) would then not be necessary. This PR will be followed-up by another PR to build postgresql v16+ based on meson instead of autotools as mentioned in #292993 (comment). With a bit of patching (of which I have a working PoC already), this will allow us to build postgresql (at least libpq, but possibly even more) in pkgsStatic - which is probably the biggest thing that didn't work so far and why a separate libpq package was asked for in the first place.

After the split, the outputs contain the following:

  • default out:
    • All binaries, except pg_config and ecpg which are in the dev output. The default output thus includes both server-side and client-side binaries.
    • All contrib/core extension related files: server-libraries, extension control files etc.
  • lib:
    • libpq
    • libecpg, including libecpg_compat and libpgtypes
    • theoretically the /share/locale folders, if there were any built, which is not the case right now
  • doc and man as before
  • dev:
    • all header files in /include (both server and client)
    • the pgxs infrastructure to build extensions
    • static support libraries libpgport*.a, libpgcommon*.a and libpgfeutils.a
    • pkg-config files
    • ecpg and pg_config binaries as mentioned above

pg_config outputs all paths correctly. Example:

BINDIR = /nix/store/cc6n22zq8xg30d04km0l5ablzn3c8sw6-postgresql-13.14/bin
DOCDIR = /nix/store/i3wz2pp3xdxr36ydawhp4zvgfg96v1xm-postgresql-13.14-doc/share/doc/postgresql
HTMLDIR = /nix/store/i3wz2pp3xdxr36ydawhp4zvgfg96v1xm-postgresql-13.14-doc/share/doc/postgresql
INCLUDEDIR = /nix/store/0mn3a190bwza34dpgnaiwmhm2b9v30xp-postgresql-13.14-dev/include
PKGINCLUDEDIR = /nix/store/0mn3a190bwza34dpgnaiwmhm2b9v30xp-postgresql-13.14-dev/include
INCLUDEDIR-SERVER = /nix/store/0mn3a190bwza34dpgnaiwmhm2b9v30xp-postgresql-13.14-dev/include/server
LIBDIR = /nix/store/1785qgnghmk01k9q4x5bysywb6alrsfs-postgresql-13.14-lib/lib
PKGLIBDIR = /nix/store/cc6n22zq8xg30d04km0l5ablzn3c8sw6-postgresql-13.14/lib
LOCALEDIR = /nix/store/1785qgnghmk01k9q4x5bysywb6alrsfs-postgresql-13.14-lib/share/locale
MANDIR = /nix/store/ad6qwl677y7x9bcrrxps4sfvchdjk03f-postgresql-13.14-man/share/man
SHAREDIR = /nix/store/cc6n22zq8xg30d04km0l5ablzn3c8sw6-postgresql-13.14/share/postgresql
SYSCONFDIR = /etc/postgresql
PGXS = /nix/store/0mn3a190bwza34dpgnaiwmhm2b9v30xp-postgresql-13.14-dev/lib/pgxs/src/makefiles/pgxs.mk

One thing that is still missing right now, is that the -dev/lib folder must be added to the pkg-config file, so that libpgcommon, libpgport etc. can be found. It's still unclear to me whether we need to add this to some other parts of the pg_config output, too, to make it possible for pg_config-based builds to actually find those static libraries. This should work, see comment below. I think this question was also raised by @szlend in #273175 (comment).

Maintainer ping, if not mentioned above already: @globin @marsam @ivan @Ma27

Things done

I built all 5 versions (12-16) with and without JIT support, with glibc (default) and via pkgsMusl. I also built .tests for the glibc variants (musl didn't work for me for unrelated reasons). I built all extensions with various versions (which resulted in #294457). This works very well, so far.

What I did not build, yet, is any downstream packages actually depending on postgresql and the new -dev output. This will be the next step, but I would like to put this PR out for feedback already.

  • Built on platform(s)
    • x86_64-linux
    • aarch64-linux
    • x86_64-darwin
    • aarch64-darwin
  • For non-Linux: Is sandboxing enabled in nix.conf? (See Nix manual)
    • sandbox = relaxed
    • sandbox = true
  • Tested, as applicable:
  • Tested compilation of all packages that depend on this change using nix-shell -p nixpkgs-review --run "nixpkgs-review rev HEAD". Note: all changes have to be committed, also see nixpkgs-review usage
  • Tested basic functionality of all binary files (usually in ./result/bin/)
  • 24.05 Release Notes (or backporting 23.05 and 23.11 Release notes)
    • (Package updates) Added a release notes entry if the change is major or breaking
    • (Module updates) Added a release notes entry if the change is significant
    • (Module addition) Added a release notes entry if adding a new NixOS module
  • Fits CONTRIBUTING.md.

Add a 👍 reaction to pull requests you find important.

@github-actions github-actions bot added 6.topic: python 6.topic: nixos Issues or PRs affecting NixOS modules, or package usability issues specific to NixOS 8.has: documentation This PR adds or changes documentation 8.has: module (update) This PR changes an existing module in `nixos/` 6.topic: ruby labels Mar 9, 2024
@Ma27 Ma27 marked this pull request as draft March 9, 2024 16:52
@Ma27
Copy link
Member

Ma27 commented Mar 9, 2024

Converting to a draft until the base PRs are merged.

@Ma27
Copy link
Member

Ma27 commented Mar 9, 2024

Compared to #179962, the approach taken in this PR is simpler and requires far less patching of postgresql source code. In fact, the overall size of patches is reduced compared to before and fewer references needed to be removed afterwards.

Yeah, from a first glance I prefer this PR over the alternatives.
But I think the refactorings are still a good idea, so I'll focus on them for now.

@wolfgangwalther wolfgangwalther mentioned this pull request Mar 10, 2024
13 tasks
@wolfgangwalther
Copy link
Contributor Author

With this output available, it's easy to create a top-level attribute libpq pointing to the latest version's lib output automatically

I don't think this libpq -> postgresql_latest.lib top-level attribute will actually work. IIUC, when passing postgresql as a buildInput, it is actually using lib.getDev behind the scenes, to use the dev output of the postgresql package. But this won't work with this kind of libpq package - because lib.getDev postgresql.lib does not return the -dev output, but still only the -lib output. Without any of the headers, pkg-config files and static libraries... linking against libpq will certainly fail.

Of course the fix is simple - just make libpq point to postgresql_latest directly and not the lib output, which will have everything we actually wanted to, now that the outputs are split cleanly.

@wolfgangwalther
Copy link
Contributor Author

One thing that is still missing right now, is that the -dev/lib folder must be added to the pkg-config file, so that libpgcommon, libpgport etc. can be found.

I wonder how this would work before this PR anyway. Currently, those libraries are in the default output, but neither pg_config nor the pkg-config files have any mention of the default output's /lib directory.

When I remove those libraries entirely, then postgresql.pkgs.pg_auto_failover fails to build, because of missing libpgport and libpgcommon. But, even after moving those libs to the -dev output, the build succeeds. The linker flags look like this, though:

...
-L /nix/store/fnqpsn19nlyh45inikngy896fzf92d4z-postgresql-15.6/lib
-L /nix/store/gp2rvnn2xmm6k9iws48f7kcjgjd1wzrw-postgresql-15.6-lib/lib
-L/nix/store/70y8lpggw1jxmkgcmxfpp769z1y2cnpb-libxml2-2.12.5/lib
-L/nix/store/5wzi64qpd6i1zn3bsg9vm0l2l2n85m25-lz4-1.9.4/lib
-L/nix/store/9l0rfic1ax0ywx63qb97wyhycpcmy1cx-zstd-1.5.5/lib
...

No mention of the -dev output anywhere, but it still works fine.

Without knowing exactly what the magic behind the scenes does here, I conclude that this will work just fine without pg_config / pkg-config returning another -dev/lib folder.

@szlend
Copy link
Member

szlend commented Mar 16, 2024

I don't think this libpq -> postgresql_latest.lib top-level attribute will actually work. IIUC, when passing postgresql as a buildInput, it is actually using lib.getDev behind the scenes, to use the dev output of the postgresql package. But this won't work with this kind of libpq package - because lib.getDev postgresql.lib does not return the -dev output, but still only the -lib output. Without any of the headers, pkg-config files and static libraries... linking against libpq will certainly fail.

Yep, I came to the same conclusion a while back.

Of course the fix is simple - just make libpq point to postgresql_latest directly and not the lib output, which will have everything we actually wanted to, now that the outputs are split cleanly.

I don't think this is a great solution either. I would find it pretty surprising if installing libpq included the entire postgresql server. In that case I'd rather just not have a libpq package ta all.

Alternatively I could see libpq be a variant of the posgresql package with a few overrides that make it skip building the server bits. But iirc the package maintainers were against this idea.

One thing that is still missing right now, is that the -dev/lib folder must be added to the pkg-config file, so that libpgcommon, libpgport etc. can be found.

I wonder how this would work before this PR anyway. Currently, those libraries are in the default output, but neither pg_config nor the pkg-config files have any mention of the default output's /lib directory.

This is one of the reason I still think a separate libpq package is the right move. This is just not solvable in any reasonable way with a single package with multiple outputs. pg_config can only refer to one lib, and there are two of them. It's as simple as that.

@wolfgangwalther
Copy link
Contributor Author

Just realized I lost the commit to make other packages use the -dev output when manually looking for pg_config along the way, when splitting of the "make libpq a package" related changes. I'm working on a PR to fix that.

wolfgangwalther added a commit to wolfgangwalther/nixpkgs that referenced this pull request Aug 24, 2024
This was supposed to happen in NixOS#294504, but the commit was accidentally
left out when splitting off some libpq-related changes. Originated in
NixOS#179962, by Sandro.

Co-authored-by: Sandro Jäckel <sandro.jaeckel@gmail.com>
Co-authored-by: Wolfgang Walther <walther@technowledgy.de>
@trofi
Copy link
Contributor

trofi commented Aug 25, 2024

Bisect says 435f51c postgresql: split dev output broke NixOS manual build in staging as:

$ nix build -f nixos config.system.build.manual.manualHTML -L

nixos-manual-html> Traceback (most recent call last):
nixos-manual-html>   File "/nix/store/4yyh0fh7h6yhwcgsppdffxfz9q2ismnx-nixos-render-docs-0.0/lib/python3.12/site-packages/nixos_render_docs/manual.py", line 128, in _parse_included_blocks
nixos-manual-html>     tokens = self._parse(f.read(), auto_id_prefix=prefix)
nixos-manual-html>              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
nixos-manual-html>   File "/nix/store/4yyh0fh7h6yhwcgsppdffxfz9q2ismnx-nixos-render-docs-0.0/lib/python3.12/site-packages/nixos_render_docs/manual.py", line 526, in _parse
nixos-manual-html>     tokens = super()._parse(src,auto_id_prefix=auto_id_prefix)
nixos-manual-html>              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
nixos-manual-html>   File "/nix/store/4yyh0fh7h6yhwcgsppdffxfz9q2ismnx-nixos-render-docs-0.0/lib/python3.12/site-packages/nixos_render_docs/manual.py", line 80, in _parse
nixos-manual-html>     check_structure(self._current_type[-1], tokens)
nixos-manual-html>   File "/nix/store/4yyh0fh7h6yhwcgsppdffxfz9q2ismnx-nixos-render-docs-0.0/lib/python3.12/site-packages/nixos_render_docs/manual_structure.py", line 84, in check_structure
nixos-manual-html>     raise RuntimeError(f"heading in line {token.map[0] + 1} does not have an id")
nixos-manual-html> RuntimeError: heading in line 366 does not have an id
nixos-manual-html> The above exception was the direct cause of the following exception:
nixos-manual-html> Traceback (most recent call last):
nixos-manual-html>   File "/nix/store/4yyh0fh7h6yhwcgsppdffxfz9q2ismnx-nixos-render-docs-0.0/lib/python3.12/site-packages/nixos_render_docs/manual.py", line 128, in _parse_included_blocks
nixos-manual-html>     tokens = self._parse(f.read(), auto_id_prefix=prefix)
nixos-manual-html>              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
nixos-manual-html>   File "/nix/store/4yyh0fh7h6yhwcgsppdffxfz9q2ismnx-nixos-render-docs-0.0/lib/python3.12/site-packages/nixos_render_docs/manual.py", line 526, in _parse
nixos-manual-html>     tokens = super()._parse(src,auto_id_prefix=auto_id_prefix)
nixos-manual-html>              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
nixos-manual-html>   File "/nix/store/4yyh0fh7h6yhwcgsppdffxfz9q2ismnx-nixos-render-docs-0.0/lib/python3.12/site-packages/nixos_render_docs/manual.py", line 100, in _parse
nixos-manual-html>     self._parse_included_blocks(token, args)
nixos-manual-html>   File "/nix/store/4yyh0fh7h6yhwcgsppdffxfz9q2ismnx-nixos-render-docs-0.0/lib/python3.12/site-packages/nixos_render_docs/manual.py", line 132, in _parse_included_blocks
nixos-manual-html>     raise RuntimeError(f"processing included file {path} from line {lnum}") from e
nixos-manual-html> RuntimeError: processing included file /nix/store/48631l3hj5l06lygdbjiccwsqq47zmwh-postgresql.md from line 83
nixos-manual-html> The above exception was the direct cause of the following exception:
nixos-manual-html> Traceback (most recent call last):
nixos-manual-html>   File "/nix/store/4yyh0fh7h6yhwcgsppdffxfz9q2ismnx-nixos-render-docs-0.0/lib/python3.12/site-packages/nixos_render_docs/manual.py", line 36, in convert
nixos-manual-html>     tokens = self._parse(infile.read_text())
nixos-manual-html>              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
nixos-manual-html>   File "/nix/store/4yyh0fh7h6yhwcgsppdffxfz9q2ismnx-nixos-render-docs-0.0/lib/python3.12/site-packages/nixos_render_docs/manual.py", line 526, in _parse
nixos-manual-html>     tokens = super()._parse(src,auto_id_prefix=auto_id_prefix)
nixos-manual-html>              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
nixos-manual-html>   File "/nix/store/4yyh0fh7h6yhwcgsppdffxfz9q2ismnx-nixos-render-docs-0.0/lib/python3.12/site-packages/nixos_render_docs/manual.py", line 100, in _parse
nixos-manual-html>     self._parse_included_blocks(token, args)
nixos-manual-html>   File "/nix/store/4yyh0fh7h6yhwcgsppdffxfz9q2ismnx-nixos-render-docs-0.0/lib/python3.12/site-packages/nixos_render_docs/manual.py", line 132, in _parse_included_blocks
nixos-manual-html>     raise RuntimeError(f"processing included file {path} from line {lnum}") from e
nixos-manual-html> RuntimeError: processing included file configuration/configuration.md from line 41
nixos-manual-html> The above exception was the direct cause of the following exception:
nixos-manual-html> Traceback (most recent call last):
nixos-manual-html>   File "/nix/store/4yyh0fh7h6yhwcgsppdffxfz9q2ismnx-nixos-render-docs-0.0/lib/python3.12/site-packages/nixos_render_docs/__init__.py", line 49, in main
nixos-manual-html>     manual.run_cli(args)
nixos-manual-html>   File "/nix/store/4yyh0fh7h6yhwcgsppdffxfz9q2ismnx-nixos-render-docs-0.0/lib/python3.12/site-packages/nixos_render_docs/manual.py", line 704, in run_cli
nixos-manual-html>     _run_cli_html(args)
nixos-manual-html>   File "/nix/store/4yyh0fh7h6yhwcgsppdffxfz9q2ismnx-nixos-render-docs-0.0/lib/python3.12/site-packages/nixos_render_docs/manual.py", line 696, in _run_cli_html
nixos-manual-html>     md.convert(args.infile, args.outfile)
nixos-manual-html>   File "/nix/store/4yyh0fh7h6yhwcgsppdffxfz9q2ismnx-nixos-render-docs-0.0/lib/python3.12/site-packages/nixos_render_docs/manual.py", line 523, in convert
nixos-manual-html>     super().convert(infile, outfile)
nixos-manual-html>   File "/nix/store/4yyh0fh7h6yhwcgsppdffxfz9q2ismnx-nixos-render-docs-0.0/lib/python3.12/site-packages/nixos_render_docs/manual.py", line 41, in convert
nixos-manual-html>     raise RuntimeError(f"failed to render manual {infile}") from e
nixos-manual-html> RuntimeError: failed to render manual manual.md
nixos-manual-html> error:
nixos-manual-html>      failed to render manual manual.md
nixos-manual-html> caused by:
nixos-manual-html>      processing included file configuration/configuration.md from line 41
nixos-manual-html> caused by:
nixos-manual-html>      processing included file /nix/store/48631l3hj5l06lygdbjiccwsqq47zmwh-postgresql.md from line 83
nixos-manual-html> caused by:
nixos-manual-html>      heading in line 366 does not have an id

@trofi
Copy link
Contributor

trofi commented Aug 25, 2024

Looks like the header needs an anchor. This seems to be enough to workaround build failure:

--- a/nixos/modules/services/databases/postgresql.md
+++ b/nixos/modules/services/databases/postgresql.md
@@ -366 +366 @@ evaluates to `"foobar"`.
-## Notable differences to upstream
+## Notable differences to upstream {#foo}

@trofi
Copy link
Contributor

trofi commented Aug 25, 2024

Proposed the fix as:

wolfgangwalther added a commit to wolfgangwalther/nixpkgs that referenced this pull request Sep 19, 2024
We introduced LTO in NixOS#294504. At that time, we still needed to use LLVM
/ lld to make this work on darwin. For this to work for extensions, they
would need to set CFLAGS=-fuse-ld=lld, too. However, since NixOS#307880
landed, we don't need to do this anymore in the first place, LTO just
works out of the box on darwin.

Resolves NixOS#342362
@wolfgangwalther wolfgangwalther mentioned this pull request Sep 29, 2024
4 tasks
@kirillrdy
Copy link
Member

hi, I have a very strange performance regression after this PR,

sorry cant provide sql file, but it's just a restore dump of somewhat small db ( 100Mb )

before this PR

time PGHOST=/tmp psql foo < dump.sql
real	0m1.876s
user	0m0.024s
sys	0m0.070s

after this PR

time PGHOST=/tmp psql foo < dump.sql
real	0m3.000s
user	0m0.024s
sys	0m0.050s

so far I've bisected it to this lines

    __structuredAttrs = true;

    outputChecks.lib = {
      disallowedReferences = [ "out" "doc" "man" ];
    };

commenting those lines restores performance, no idea why.

this is for non jit version of postgres_16, interestingly postgres_16_jit performs same as prior to this PR postgres_16, but i looked into closure, there is no llvm or anything and SELECT pg_jit_available() ; returns false

thoughts ? it would be good if someone else can verify this regression

@wolfgangwalther
Copy link
Contributor Author

@kirillrdy Are you on darwin or linux?

__structuredAttrs = true;

Once you take this away, some other settings in the derivation will be affected (I can't pinpoint which exactly, will have to test). So this doesn't need to be about structuredAttrs directly, but possibly about something else that is disabled with it.

@kirillrdy
Copy link
Member

@kirillrdy Are you on darwin or linux?

__structuredAttrs = true;

Once you take this away, some other settings in the derivation will be affected (I can't pinpoint which exactly, will have to test). So this doesn't need to be about structuredAttrs directly, but possibly about something else that is disabled with it.

thanks for quick response,

i am on x86_64-linux. Yes it's __structuredAttrs, not sure what it affects, I've tried removing items from

outputChecks.lib = {
      disallowedReferences = [];
    };

but no difference.

@Ma27
Copy link
Member

Ma27 commented Nov 1, 2024

Just to be clear, the absence of __structuredAttrs = true; is sufficient to speed this up?
Which commit did you reproduce that on? Would like to have the same nixpkgs state when trying to reproduce it.

I must say, I guess I'll look into it because I really want to know how this could happen 🙃

@kirillrdy
Copy link
Member

@Ma27 thank you for showing interest in this
here is repo to reproduce the issue
https://github.com/kirillrdy/pg_regression/blob/main/regres.nix
I've included sql file so you should be able to just clone and nix-build regres.nix

base commit is 7797728, and commit without structured attrs is kirillrdy@5afb38a I had to comment out outputChecks.lib as well because it doesn't eval, but if you comment out just outputChecks.lib the regression is still there

@wolfgangwalther
Copy link
Contributor Author

Thanks for the reproducer, that will save me quite a bit of time trying to set one up myself. Will try to look into that tomorrow as well.

@Ma27
Copy link
Member

Ma27 commented Nov 1, 2024

Congratulations, you've found a nasty stdenv bug.
I have a working patch, but I'm way too tired now, so I'd like to take a fresh look tomorrow and file a PR then.

Ma27 added a commit to Ma27/nixpkgs that referenced this pull request Nov 2, 2024
A while ago `postgresql` switched to using structured attrs[1]. In the
PR it was reported that this made postgresql notably slower when
importing SQL dumps[2].

After a bit of debugging it turned out that the hardening was entirely
missing and the following combination of settings was the culprit:

    hardeningEnable = [ "pie" ];
    __structuredAttrs = true;

I.e. the combination of custom hardening settings and structured attrs.

What happened here is that internally, the default and enabled hardening
flags get written into NIX_HARDENING_ENABLE. However, the value is a list
and the setting is not in the `env` section. This means that in the
structured-attrs case we get something like

    declare -ax NIX_HARDENING_ENABLE=([0]="bindnow" [1]="format" [2]="fortify" [3]="fortify3" [4]="pic" [5]="relro" [6]="stackprotector" [7]="strictoverflow" [8]="zerocallusedregs" [9]="pie")

i.e. an actual array rather than a string with all hardening flags being
space-separated which is what the hardening code of the cc-wrapper
expects[3].

This only happens if `hardeningEnable` or `hardeningDisable` are
explicitly set by a derivation: if none of those are set,
`NIX_HARDENING_ENABLE` won't be set by `stdenv.mkDerivation` and the
default hardening flags are configured by the setup hook of the
cc-wrapper[4].

In other words, this _only_ applies to derivations that have both custom
hardening settings _and_ `__structuredAttrs = true;`.

I figured that it's far easier to just write a space-separated string
for NIX_HARDENING_ENABLE into `env` if needed rather than changing the
code in `add-hardening.sh` which would've caused a full rebuild. The
flags are well-known identifiers anyways, so there's no risk of issues
coming from missing escapes.

[1] NixOS#294504
[2] NixOS#294504 (comment)
[3] https://github.com/NixOS/nixpkgs/blob/cf3e5d3744dc26c3498aa5dadfa0e078c632cede/pkgs/build-support/cc-wrapper/add-hardening.sh#L9
[4] https://github.com/NixOS/nixpkgs/blob/cf3e5d3744dc26c3498aa5dadfa0e078c632cede/pkgs/build-support/cc-wrapper/setup-hook.sh#L114
@Ma27
Copy link
Member

Ma27 commented Nov 2, 2024

See #353131.

Ma27 added a commit to Ma27/nixpkgs that referenced this pull request Nov 2, 2024
… true;`

Replaces / Closes NixOS#353131

A while ago `postgresql` switched to using structured attrs[1]. In the
PR it was reported that this made postgresql notably slower when
importing SQL dumps[2].

After a bit of debugging it turned out that the hardening was entirely
missing and the following combination of settings was the culprit:

    hardeningEnable = [ "pie" ];
    __structuredAttrs = true;

I.e. the combination of custom hardening settings and structured attrs.

What happened here is that internally the default and enabled hardening
flags get written into `NIX_HARDENING_ENABLE`. However, the value is a list
and the setting is not in the `env` section. This means that in the
structured-attrs case we get something like

    declare -ax NIX_HARDENING_ENABLE=([0]="bindnow" [1]="format" [2]="fortify" [3]="fortify3" [4]="pic" [5]="relro" [6]="stackprotector" [7]="strictoverflow" [8]="zerocallusedregs" [9]="pie")

i.e. an actual array rather than a string with all hardening flags being
space-separated which is what the hardening code of the cc-wrapper
expects[3].

This only happens if `hardeningEnable` or `hardeningDisable` are
explicitly set by a derivation: if none of those are set,
`NIX_HARDENING_ENABLE` won't be set by `stdenv.mkDerivation` and the
default hardening flags are configured by the setup hook of the
cc-wrapper[4].

In other words, this _only_ applies to derivations that have both custom
hardening settings _and_ `__structuredAttrs = true;`.

All values of `NIX_HARDENING_ENABLE` are well-known, so we don't have to
worry about escaping issues. Just forcing it to a string by
concatenating the list everytime solves the issue without additional
issues like eval errors when inheriting `env` from a structuredAttrs
derivation[5]. The price we're paying is a full rebuild.

[1] NixOS#294504
[2] NixOS#294504 (comment)
[3] https://github.com/NixOS/nixpkgs/blob/cf3e5d3744dc26c3498aa5dadfa0e078c632cede/pkgs/build-support/cc-wrapper/add-hardening.sh#L9
[4] https://github.com/NixOS/nixpkgs/blob/cf3e5d3744dc26c3498aa5dadfa0e078c632cede/pkgs/build-support/cc-wrapper/setup-hook.sh#L114
[5] NixOS@1e84a7f
@fpringle
Copy link

With a bit of patching (of which I have a working PoC already), this will allow us to build postgresql (at least libpq, but possibly even more) in pkgsStatic - which is probably the biggest thing that didn't work so far and why a separate libpq package was asked for in the first place.

@wolfgangwalther did you manage to find a way to build libpq in pkgsStatic?

@wolfgangwalther
Copy link
Contributor Author

With a bit of patching (of which I have a working PoC already), this will allow us to build postgresql (at least libpq, but possibly even more) in pkgsStatic - which is probably the biggest thing that didn't work so far and why a separate libpq package was asked for in the first place.

@wolfgangwalther did you manage to find a way to build libpq in pkgsStatic?

Yes, see #345289.

@fpringle
Copy link

With a bit of patching (of which I have a working PoC already), this will allow us to build postgresql (at least libpq, but possibly even more) in pkgsStatic - which is probably the biggest thing that didn't work so far and why a separate libpq package was asked for in the first place.

@wolfgangwalther did you manage to find a way to build libpq in pkgsStatic?

Yes, see #345289.

Thanks very much :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
6.topic: nixos Issues or PRs affecting NixOS modules, or package usability issues specific to NixOS 8.has: changelog 8.has: documentation This PR adds or changes documentation 8.has: module (update) This PR changes an existing module in `nixos/` 8.has: package (new) This PR adds a new package 10.rebuild-darwin: 501+ 10.rebuild-darwin: 2501-5000 10.rebuild-linux: 501+ 10.rebuild-linux: 5001+ 11.by: package-maintainer This PR was created by the maintainer of the package it changes
Projects
None yet
Development

Successfully merging this pull request may close these issues.