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 fmt when constructor already does it #3720

Merged
merged 4 commits into from Apr 20, 2022

Conversation

Ericson2314
Copy link
Member

@Ericson2314 Ericson2314 commented Jun 18, 2020

We have a larger problem that passing computed strings to the first
variable argument of many exception constructors is unsafe because that
first variable argument is interpreted not as a plain string, but format
string, and if it contains '%' boost::format will abort, since there are
no arguments to the format string.

In this particular instance '%' was used as part of an escape code in a
URL, which, when the download failed, caused Nix to abort displaying the
FileTransferError.

#3724 will fix the underlying issue. This is just a cleanup for brevity's sake.

Most of the changes are very straight forward, but I did refactor a bit more aggressively with the SQLite errors, taking SysError my guide.

CC @bburdette

@matthewbauer
Copy link
Member

matthewbauer commented Jun 18, 2020

There are a few similar cases in:

(most of those won't have a percent though, but best to be safe)

@edolstra
Copy link
Member

This is a regression compared to 2.3, where both throw Error("foo %s") and throw Error(fmt("foo %s")) printed error: foo %s. This is because we had a specialisation for fmt:

/* A helper for formatting strings. ‘fmt(format, a_0, ..., a_n)’ is
   equivalent to ‘boost::format(format) % a_0 % ... %
   ... a_n’. However, ‘fmt(s)’ is equivalent to ‘s’ (so no %-expansion
   takes place). */

inline std::string fmt(const std::string & s)
{
    return s;
}

...

We should restore that specialisation.

@Ericson2314 Ericson2314 changed the title Prevent '%' in URL from causing crashes WIP: Restore specialization that makes single string arg not a format string Jun 19, 2020
@Ericson2314
Copy link
Member Author

#3724 is better to fix the underlying issue, so I'll make this just a duplicate formatting cleanup.

@Ericson2314 Ericson2314 changed the title WIP: Restore specialization that makes single string arg not a format string WIP: Use constructor rather than adittional fmt for tidyness Jun 21, 2020
@Ericson2314 Ericson2314 changed the title WIP: Use constructor rather than adittional fmt for tidyness WIP: Use constructor rather than additional fmt for tidiness Jun 21, 2020
@Ericson2314 Ericson2314 changed the title WIP: Use constructor rather than additional fmt for tidiness Avoid fmt when constructor already does it Jun 21, 2020
@Ericson2314 Ericson2314 changed the title Avoid fmt when constructor already does it WIP: Avoid fmt when constructor already does it Jun 21, 2020
@Ericson2314
Copy link
Member Author

Guess clang has different semantics around protected here.

@Ericson2314
Copy link
Member Author

Huh, this is the second PR of mine where there are weird perl issues.

@edolstra
Copy link
Member

What do the SQLite changes do?

@Ericson2314
Copy link
Member Author

@edolstra they shouldn't have any observable effect.

The idea is the helper function takes var args like the error constructors, formatiting the users format string. Also, the errors themselves store the original information (error number and extended error number) should somebody want to display the information differently.

With @bburdette's approval, I would complete the process of separating structure and presentation by making SysError and thse SQLite errors just store the user's original hintformat value, and then render the boilerplate stuff (with the strerr and similiar for the error numbers, and shortened message for the SQLite is busy) on demand when the exception is caught and rendered near main.

@stale
Copy link

stale bot commented Feb 12, 2021

I marked this as stale due to inactivity. → More info

@stale stale bot added the stale label Feb 12, 2021
@stale
Copy link

stale bot commented Apr 16, 2022

I closed this issue due to inactivity. → More info

@Ericson2314
Copy link
Member Author

I think this is till a good cleanup. Rebased it.

There is a correctnes issue here, but NixOS#3724 will fix that. This is just
a cleanup for brevity's sake.
@Ericson2314 Ericson2314 changed the title WIP: Avoid fmt when constructor already does it Avoid fmt when constructor already does it Apr 19, 2022
Copy link
Member

@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.

I think this is till a good cleanup

Indeed, thanks for the rebase :)

There’s just an issue with the sqlite stuff where you introduce a nasty little footgun. Other than that 👍

int errNo, extendedErrNo;

template<typename... Args>
[[noreturn]] static void throw_(sqlite3 * db, const std::string & fs, const Args & ... args);
Copy link
Member

Choose a reason for hiding this comment

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

Unless I’m missing something, this is very fragile since the definition of the templated function isn’t in the header − so only the instances of the template that happen to be used in sqlite.cc will be available outside (which happens to be the case because the only usages outside of sqlite.cc seem to be whith args being a single string)

Copy link
Member Author

Choose a reason for hiding this comment

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

Oh good catch!

Copy link
Member Author

Choose a reason for hiding this comment

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

Fixed this.

Copy link
Member Author

Choose a reason for hiding this comment

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

Fixed it an even better way!

This ensures that use-sites properly trigger new monomorphisations on
one hand, and on the other hand keeps the main `sqlite.hh` clean and
interface-only. I think that is good practice in general, but in this
situation in particular we do indeed have `sqlite.hh` users that don't
need the `throw_` function.
The templating is very superficial
Copy link
Member

@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.

Looks good now :)

Set to merge once the CI is green ✔️

@thufschmitt thufschmitt merged commit 9345b4e into NixOS:master Apr 20, 2022
@Ericson2314 Ericson2314 deleted the fix-url-format branch April 20, 2022 19:54
@orbekk
Copy link
Contributor

orbekk commented Apr 21, 2022

I wonder if this may have broken the build (run link:

error: builder for '/nix/store/diz7s7lkp2an9aa8vrwb225mbghgksfn-nix-2.9.0pre20220420_9345b4e.drv' failed with exit code 2;
       last 10 log lines:
       >   CXX    src/libstore/remote-store.o
       > src/libstore/sqlite.cc:28:20: error: calling a protected constructor of class 'nix::SQLiteBusy'
       >         auto exp = SQLiteBusy(path, err, exterr, std::move(hf));
       >                    ^
       > src/libstore/sqlite.hh:122:23: note: declared protected here
       > MakeError(SQLiteBusy, SQLiteError);
       >                       ^
       > 1 error generated.
       > make: *** [mk/patterns.mk:3: src/libstore/sqlite.o] Error 1
       > make: *** Waiting for unfinished jobs....
       For full logs, run 'nix log /nix/store/diz7s7lkp2an9aa8vrwb225mbghgksfn-nix-2.9.0pre20220420_9345b4e.drv'.

@thufschmitt
Copy link
Member

I wonder if this may have broken the build

It did indeed :/ Looking at it right now

@Ericson2314
Copy link
Member Author

Thanks for fixing!

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

Successfully merging this pull request may close these issues.

None yet

5 participants