diff options
author | Qyriad <qyriad@qyriad.me> | 2024-06-22 21:17:41 -0600 |
---|---|---|
committer | Qyriad <qyriad@qyriad.me> | 2024-07-04 15:55:38 -0600 |
commit | 139cfdfb5309407694b92f5f710400a5bc03f313 (patch) | |
tree | 59d2963a4ce9dd42fd18795208a6646cbf0a742b /src/libexpr/print.hh | |
parent | 59bf6825ef34dd8951302fb033837c2658b2367d (diff) |
add an ExprPrinter class, like ValuePrinter
To be used Shortly
Change-Id: I9def7975aa55f251eb8486391677771f7352d7ce
Diffstat (limited to 'src/libexpr/print.hh')
-rw-r--r-- | src/libexpr/print.hh | 30 |
1 files changed, 30 insertions, 0 deletions
diff --git a/src/libexpr/print.hh b/src/libexpr/print.hh index 42826d94d..3deaa33d4 100644 --- a/src/libexpr/print.hh +++ b/src/libexpr/print.hh @@ -15,6 +15,8 @@ namespace nix { +struct Expr; + class EvalState; struct Value; @@ -50,6 +52,12 @@ void printValue(EvalState & state, std::ostream & str, Value & v, PrintOptions o /** * A partially-applied form of `printValue` which can be formatted using `<<` * without allocating an intermediate string. + * This class should not outlive the eval state or it will UAF. + * FIXME: This should take `nix::ref`s, to avoid that, but our eval methods all have + * EvalState &, not ref<EvalState>, and constructing a new shared_ptr to data that + * already has a shared_ptr is a much bigger footgun. In the current architecture of + * libexpr, using a ValuePrinter after an EvalState has been destroyed would be + * pretty hard. */ class ValuePrinter { friend std::ostream & operator << (std::ostream & output, const ValuePrinter & printer); @@ -73,4 +81,26 @@ std::ostream & operator<<(std::ostream & output, const ValuePrinter & printer); template<> fmt_internal::HintFmt & fmt_internal::HintFmt::operator%(const ValuePrinter & value); +/** + * A partially-applied form of Expr::show(), which can be formatted using `<<` + * without allocating an intermediate string. + * This class should not outlive the eval state or it will UAF. + * FIXME: This should take `nix::ref`s, to avoid that, but our eval methods all have + * EvalState &, not ref<EvalState>, and constructing a new shared_ptr to data that + * already has a shared_ptr is a much bigger footgun. In the current architecture of + * libexpr, using an ExprPrinter after an EvalState has been destroyed would be + * pretty hard. + */ +class ExprPrinter +{ + /** The eval state used to get symbols. */ + EvalState const & state; + /** The expression to print. */ + Expr const & expr; + +public: + ExprPrinter(EvalState const & state, Expr const & expr) : state(state), expr(expr) { } + friend std::ostream & operator << (std::ostream & output, ExprPrinter const & printer); +}; + } |