Skip to content

Remove the usage of VLAs in the code#7348

Merged
thufschmitt merged 11 commits intoNixOS:masterfrom
thufschmitt:dont-use-vlas
Nov 16, 2023
Merged

Remove the usage of VLAs in the code#7348
thufschmitt merged 11 commits intoNixOS:masterfrom
thufschmitt:dont-use-vlas

Conversation

@thufschmitt
Copy link
Member

@thufschmitt thufschmitt commented Nov 25, 2022

Although Variable-length arrays are allowed by the C standard, they are frowned
upon, and aren't valid C++ (gcc accepts them a non-standard extension) and clang apparently does the same which is why they work here). So better get rid of them altogether.

Depends on #7346.

@edolstra
Copy link
Member

I think statically sized arrays or small_vector should be avoided in functions that can be executed recursively. E.g.

                Value * vArgs[64];

in callFunction() adds 512 bytes of stack space to function calls, which adds up quickly for deeply recursive Nix code.

To be honest I don't really share the concerns over VLAs. We've used them for years without any issues. The zero-length VLA issue seems a bit language lawyering.

@nixos-discourse
Copy link

This pull request has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/2022-12-09-nix-team-meeting-minutes-15/23951/1

@tomberek
Copy link
Contributor

TODO (from meeting):

  • check eval impacts
  • update stack overflow test

@fricklerhandwerk
Copy link
Contributor

Discussed in Nix team meeting 2022-12-19:

  • @edolstra: we have a test that checks the stack, but it's disabled because it blows the stack
  • @thufschmitt will add benchmarks to test evaluation speed.

@nixos-discourse
Copy link

This pull request has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/2022-12-19-nix-team-meeting-minutes-18/24121/1

@fricklerhandwerk fricklerhandwerk added the contributor-experience Developer experience for Nix contributors label Mar 3, 2023
Théophane Hufschmitt and others added 3 commits November 16, 2023 12:27
VLAs are a dangerous feature, and their usage triggers an undefined
behavior since theire size can be zero in some cases.
So replace them with `boost::small_vector`s which fit the same goal but
are safer.

It's also incidentally consistently 1% faster on the benchmarks.
There's generally no strict reason for using them, and they are somewhat
fishy, so let's avoid them.
@roberth roberth requested a review from edolstra as a code owner November 16, 2023 11:29
@github-actions github-actions bot added the with-tests Issues related to testing. PRs with tests have some priority label Nov 16, 2023
@roberth
Copy link
Member

roberth commented Nov 16, 2023

I think statically sized arrays or small_vector should be avoided in functions that can be executed recursively.

I've reduced the numbers significantly. Most significantly, 4 is enough for normal lambda calls. I expect the primops to contribute less to stack depth by number of nested invocations, so these use larger numbers, albeit reduced from what was originally in the PR.
This reduction is fine, because for large numbers the allocation is amortized to insignificance, and in many cases the data size is small anyway.

TODO (from meeting):

  • check eval impacts

This is infinitely faster on expressions where these VLAs caused stack overflows.

  • update stack overflow test

I find this somewhat pointless since the code does not allocate variable amounts of stack space anymore. Yes, tests are good, but these would be expensive, especially in terms of maintaining them because it involves developing non-trivial test support code for it. Silvan could attest that this is non-trivial. I'd rather focus that effort on more impactful testing improvements.

@roberth roberth added the bug label Nov 16, 2023
@roberth
Copy link
Member

roberth commented Nov 16, 2023

bug label: Fixes a stack overflow: NixOS/nixpkgs#214021 (comment)

Copy link
Member Author

@thufschmitt thufschmitt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for taking over this @roberth !

Looks good to me, although I think this deserves some benchmarks (IIRC, the original version had a small impact depending on the sizes chosen)

This makes stack usage significantly more compact, allowing larger
amounts of data to be processed on the same stack.

PrimOp functions with more than 8 positional (curried) arguments
should use an attrset instead.
Clang warned that the expanded code used to have a buffer overflow.
Very strange, but also very avoidable.
Try to stay away from stack overflows.

These small vectors use stack space. Most instances will not need
to allocate because in general most things are small, and large
things are worth heap allocating.

16 * 3 * word = 384 bytes is still quite a bit, but these functions
tend not to be part of deep recursions.
128 is still beyond the point where the allocation overhead is
insignificant, but we don't anticipate to overflow for these
use cases, so it's fine.
@roberth
Copy link
Member

roberth commented Nov 16, 2023

deserves some benchmarks

That would be great, but I can only treat this as a bugfix unfortunately.
Based on your earlier measurement I feel confident that this is not a performance regression.

@thufschmitt
Copy link
Member Author

Based on your earlier measurement I feel confident that this is not a performance regression.

I wasn't, but I hyperfined it and there's zero visible difference on nix search nixpkgs firefox. So I should have 😛

@thufschmitt thufschmitt merged commit ac4431e into NixOS:master Nov 16, 2023
@edolstra
Copy link
Member

This broke the buildNoGC job: https://hydra.nixos.org/build/241067941 which is blocking the new release.

@roberth roberth mentioned this pull request Nov 17, 2023
@roberth
Copy link
Member

roberth commented Nov 17, 2023

This broke the buildNoGC job: https://hydra.nixos.org/build/241067941 which is blocking the new release.

tebowy pushed a commit to tebowy/nix that referenced this pull request Jul 11, 2024
Remove the usage of VLAs in the code

(cherry picked from commit ac4431e)
Change-Id: Ifbf5fbfc2e27122362a2aaea4b62c7cf3ca46b1a
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug contributor-experience Developer experience for Nix contributors with-tests Issues related to testing. PRs with tests have some priority

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

7 participants