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

Avoid accessing uninitialized settings in own init #11117

Merged
merged 1 commit into from
Jul 17, 2024

Conversation

L-as
Copy link
Member

@L-as L-as commented Jul 16, 2024

The default value for the setting was evaluated by calling a method on the object being currently constructed, so we were using it before all fields were initialized.

This has been fixed by making the called method static, and not using the previously used fields at all.

But functionality hasn't changed!
The fields were usually always zero (by chance?) anyway, meaning the conditional path was always taken.

Thus the current logic has been kept, the code simplified, and UB removed.

This was found with the helper of UBSan.

Priorities and Process

Add 👍 to pull requests you find important.

The Nix maintainer team uses a GitHub project board to schedule and track reviews.

The default value for the setting was evaluated by
calling a method on the object _being currently constructed_,
so we were using it before all fields were initialized.

This has been fixed by making the called method static,
and not using the previously used fields at all.

But functionality hasn't changed!
The fields were usually always zero (by chance?) anyway,
meaning the conditional path was always taken.

Thus the current logic has been kept, the code simplified,
and UB removed.

This was found with the helper of UBSan.
@Ericson2314
Copy link
Member

CC @roberth and @fricklerhandwerk who have been tracking down this big connundrum

Copy link
Member

@Ericson2314 Ericson2314 left a comment

Choose a reason for hiding this comment

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

I think we should instead fix this by changing the field order so those other two settings are initialized first.

Is that ugly has hell? Yes absolutely. But I think that is more correct for now, and a better solution can come from the settings system redoing.

Copy link
Member

@roberth roberth left a comment

Choose a reason for hiding this comment

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

Good cleanup.
I don't think it truly affects our work on #9574, so that's ok.

@@ -69,11 +69,9 @@ Strings EvalSettings::getDefaultNixPath() const
}
};

if (!restrictEval && !pureEval) {
Copy link
Member

Choose a reason for hiding this comment

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

I wasn't aware how problematic this conditional was, but in my mental model it was always initialized to those three elements anyway, because we looked at it from the perspective of the initialization of the settings object anyway, of which we were aware that it was not in a properly loaded state yet. But yeah, it's worse; not even properly initialized, but in effect it doesn't matter which it is.

off-topic: I'd much prefer a good ol' infinite recursion over this stateful mess :D

Copy link
Member Author

Choose a reason for hiding this comment

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

Indeed, an option would be to make all settings (virtual) methods, such that they can compute.

Copy link
Member

Choose a reason for hiding this comment

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

That'd be alright, and a call depth limit could replace tBlackhole in this comparison.

@L-as
Copy link
Member Author

L-as commented Jul 16, 2024

@Ericson2314 But that would change the logic, and I'm not sure we even want that. It has caused no issues until now. Why would you change the default depending on whether restrict-eval or pure-eval are enabled?

Also, I'm not familiar with how settings are read:
Are they read at construction time or set later?
In the latter case, we wouldn't be able to do this in the default constructor anyway, no?

@roberth
Copy link
Member

roberth commented Jul 16, 2024

I think we should instead fix this by changing the field order so those other two settings are initialized first.

IIUC they'd only be in an initialized state; not a loaded / parsed state, so it'd just give a false sense of correctness.

@L-as L-as mentioned this pull request Jul 16, 2024
@edolstra
Copy link
Member

Can you check that this doesn't reintroduce the issue described in #7911?

(PR #7871 also fixes the getDefaultNixPath() issue but IIRC it causes some behavior change.)

@fricklerhandwerk
Copy link
Contributor

@edolstra the change here indeed doesn't change behavior, and we'll add tests with #11079 to ensure the right things end up happening. @Ericson2314 I suggest we merge small increments now, because redoing the settings system is a big chunk of work.

@fricklerhandwerk fricklerhandwerk merged commit 464e592 into NixOS:master Jul 17, 2024
11 checks passed
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

Successfully merging this pull request may close these issues.

5 participants