aboutsummaryrefslogtreecommitdiff
path: root/src/libexpr/print.hh
diff options
context:
space:
mode:
authorQyriad <qyriad@qyriad.me>2024-06-22 21:17:41 -0600
committerQyriad <qyriad@qyriad.me>2024-07-04 15:55:38 -0600
commit139cfdfb5309407694b92f5f710400a5bc03f313 (patch)
tree59d2963a4ce9dd42fd18795208a6646cbf0a742b /src/libexpr/print.hh
parent59bf6825ef34dd8951302fb033837c2658b2367d (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.hh30
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);
+};
+
}