From 6747f2130e90ccf85f374e9d97df0e5ca6497229 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?S=C3=A9bastien=20Villemot?= <sebastien@dynare.org>
Date: Fri, 1 Sep 2023 14:50:38 +0200
Subject: [PATCH] Perfect foresight: fix illegal memory read with bytecode +
 endval_steady

The exogenous steady state vector was passed as a row-vector to
evaluate_steady_state, thus leading to an incorrectly-sized matrix passed to
bytecode when checking the steady state on the dynamic model (when different
from the static model).
---
 matlab/evaluate_steady_state.m                        | 11 ++++++++++-
 .../perfect_foresight_solver.m                        |  6 +++---
 2 files changed, 13 insertions(+), 4 deletions(-)

diff --git a/matlab/evaluate_steady_state.m b/matlab/evaluate_steady_state.m
index c23f562adc..0f48675f35 100644
--- a/matlab/evaluate_steady_state.m
+++ b/matlab/evaluate_steady_state.m
@@ -56,6 +56,15 @@ if isoctave && options.solve_algo == 11
     error(['STEADY: you can''t use solve_algo = %u under Octave'],options.solve_algo)
 end
 
+% To ensure that the z and zx matrices constructed by repmat and passed to bytecode
+% are of the right size.
+if size(ys_init, 2) > 1
+    error('ys_init must be a column-vector')
+end
+if size(exo_ss, 2) > 1
+    error('exo_ss must be a column-vector')
+end
+
 info = 0;
 check = 0;
 
@@ -458,7 +467,7 @@ if M.static_and_dynamic_models_differ
     % computed on the *static* one
     if options.bytecode
         z = repmat(ys,1,M.maximum_lead + M.maximum_lag + 1);
-        zx = repmat([exo_ss'], M.maximum_lead + M.maximum_lag + 1, 1);
+        zx = repmat(exo_ss', M.maximum_lead + M.maximum_lag + 1, 1);
         r = bytecode('dynamic','evaluate', z, zx, params, ys, 1);
     else
         r = feval([M.fname '.sparse.dynamic_resid'], repmat(ys, 3, 1), exo_ss, params, ys);
diff --git a/matlab/perfect-foresight-models/perfect_foresight_solver.m b/matlab/perfect-foresight-models/perfect_foresight_solver.m
index d412afb301..97f53848fd 100644
--- a/matlab/perfect-foresight-models/perfect_foresight_solver.m
+++ b/matlab/perfect-foresight-models/perfect_foresight_solver.m
@@ -108,7 +108,7 @@ end
 if ~options_.simul.endval_steady && ~isempty(ys0_)
     terminal_condition_is_a_steady_state = true;
     for j = lastperiods
-        endval_resid = evaluate_static_model(oo_.endo_simul(:,j), oo_.exo_simul(j,:), M_.params, M_, options_);
+        endval_resid = evaluate_static_model(oo_.endo_simul(:,j), oo_.exo_simul(j,:)', M_.params, M_, options_);
         if norm(endval_resid, 'Inf') > options_.simul.steady_tolf
             terminal_condition_is_a_steady_state = false;
             break
@@ -160,7 +160,7 @@ function local_success = create_scenario(share)
         % Effectively compute the terminal steady state
         for j = lastperiods
             % First use the terminal steady of the previous homotopy iteration as guess value (or the contents of the endval block if this is the first iteration)
-            [oo_.endo_simul(:, j), ~, info] = evaluate_steady_state(oo_.endo_simul(:, j), oo_.exo_simul(j, :), M_, options_, true);
+            [oo_.endo_simul(:, j), ~, info] = evaluate_steady_state(oo_.endo_simul(:, j), oo_.exo_simul(j, :)', M_, options_, true);
             if info(1)
                 % If this fails, then try again using the initial steady state as guess value
                 if isempty(ys0_)
@@ -168,7 +168,7 @@ function local_success = create_scenario(share)
                 else
                     guess_value = ys0_;
                 end
-                [oo_.endo_simul(:, j), ~, info] = evaluate_steady_state(guess_value, oo_.exo_simul(j, :), M_, options_, true);
+                [oo_.endo_simul(:, j), ~, info] = evaluate_steady_state(guess_value, oo_.exo_simul(j, :)', M_, options_, true);
                 if info(1)
                     % If this fails again, give up and restore last periods in oo_.endo_simul
                     oo_.endo_simul(:, lastperiods) = saved_ss;
-- 
GitLab