From a8ea57dd634350d7304d2eb8e66042d418ec5c8f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?S=C3=A9bastien=20Villemot?= <sebastien@dynare.org>
Date: Wed, 27 Sep 2023 11:23:18 +0200
Subject: [PATCH] Fix illegal memory access when doing Ramsey

The preprocessor would try to write bytecode for the planner objective. But
bytecode only works when there are as many endogenous as equations, which is
not the case for the PlannerObjective object derived from StaticModel.
---
 src/DynamicModel.cc       | 4 ++++
 src/ModelEquationBlock.cc | 6 ++++++
 src/ModelEquationBlock.hh | 1 +
 src/StaticModel.cc        | 4 ++++
 src/StaticModel.hh        | 2 +-
 5 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/src/DynamicModel.cc b/src/DynamicModel.cc
index 171bd807..32e5f328 100644
--- a/src/DynamicModel.cc
+++ b/src/DynamicModel.cc
@@ -142,6 +142,10 @@ DynamicModel::operator=(const DynamicModel &m)
 void
 DynamicModel::writeDynamicBytecode(const string &basename) const
 {
+  /* Bytecode only works when there are with as many endogenous as equations.
+     (e.g. the constructor of FBEGINBLOCK_ makes this assumption) */
+  assert(static_cast<int>(equations.size()) == symbol_table.endo_nbr());
+
   // Determine the type of model (used for typing the single block)
   BlockSimulationType simulation_type;
   if (max_endo_lag > 0 && max_endo_lead > 0)
diff --git a/src/ModelEquationBlock.cc b/src/ModelEquationBlock.cc
index d2a0c1d8..12084797 100644
--- a/src/ModelEquationBlock.cc
+++ b/src/ModelEquationBlock.cc
@@ -37,6 +37,12 @@ PlannerObjective::computingPassBlock([[maybe_unused]] const eval_context_t &eval
   // Disable block decomposition on planner objective
 }
 
+void
+PlannerObjective::writeStaticBytecode([[maybe_unused]] const string &basename) const
+{
+  // Disable bytecode output, because there are not as many variables as equations
+}
+
 OrigRamseyDynamicModel::OrigRamseyDynamicModel(SymbolTable &symbol_table_arg,
                                                NumericalConstants &num_constants_arg,
                                                ExternalFunctionsTable &external_functions_table_arg,
diff --git a/src/ModelEquationBlock.hh b/src/ModelEquationBlock.hh
index 8efe6aaf..9f8536d4 100644
--- a/src/ModelEquationBlock.hh
+++ b/src/ModelEquationBlock.hh
@@ -41,6 +41,7 @@ protected:
 
 private:
   void computingPassBlock(const eval_context_t &eval_context, bool no_tmp_terms) override;
+  void writeStaticBytecode(const string &basename) const override;
 };
 
 class OrigRamseyDynamicModel : public DynamicModel
diff --git a/src/StaticModel.cc b/src/StaticModel.cc
index fb15c881..6760a492 100644
--- a/src/StaticModel.cc
+++ b/src/StaticModel.cc
@@ -102,6 +102,10 @@ StaticModel::StaticModel(const DynamicModel &m) :
 void
 StaticModel::writeStaticBytecode(const string &basename) const
 {
+  /* Bytecode only works when there are with as many endogenous as equations.
+     (e.g. the constructor of FBEGINBLOCK_ makes this assumption) */
+  assert(static_cast<int>(equations.size()) == symbol_table.endo_nbr());
+
   // First write the .bin file
   int u_count_int { writeBytecodeBinFile(basename + "/model/bytecode/static.bin", false) };
 
diff --git a/src/StaticModel.hh b/src/StaticModel.hh
index 5e98f28f..8df4d084 100644
--- a/src/StaticModel.hh
+++ b/src/StaticModel.hh
@@ -60,7 +60,7 @@ private:
   void writeStaticBlockBytecode(const string &basename) const;
 
   //! Writes the code of the model in virtual machine bytecode
-  void writeStaticBytecode(const string &basename) const;
+  virtual void writeStaticBytecode(const string &basename) const;
 
   //! Computes jacobian and prepares for equation normalization
   /*! Using values from initval/endval blocks and parameter initializations:
-- 
GitLab