From fe83933b1d0ecbd06a6b7c0437471d0b99b8d16e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?S=C3=A9bastien=20Villemot?= <sebastien@dynare.org>
Date: Thu, 2 Mar 2023 15:55:51 +0100
Subject: [PATCH] Bugfix: undefined behaviour in
 AbstractExternalFunctionNode::prepareForDerivation()
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Input and output ranges should not overlap when calling std::set_union(),
otherwise the behaviour is undefined.

It seems that in this precise case the computation would still be
correct (though inefficient), because of the properties of std::set or because
of the specific implementation in libstdc++. But it’s better to be on the safe
side.
---
 src/ExprNode.cc | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/src/ExprNode.cc b/src/ExprNode.cc
index 09f40905..81ba65f4 100644
--- a/src/ExprNode.cc
+++ b/src/ExprNode.cc
@@ -6758,11 +6758,15 @@ AbstractExternalFunctionNode::prepareForDerivation()
 
   non_null_derivatives = arguments.at(0)->non_null_derivatives;
   for (int i = 1; i < static_cast<int>(arguments.size()); i++)
-    set_union(non_null_derivatives.begin(),
-              non_null_derivatives.end(),
-              arguments.at(i)->non_null_derivatives.begin(),
-              arguments.at(i)->non_null_derivatives.end(),
-              inserter(non_null_derivatives, non_null_derivatives.begin()));
+    {
+      set<int> non_null_derivatives_tmp;
+      set_union(non_null_derivatives.begin(),
+                non_null_derivatives.end(),
+                arguments.at(i)->non_null_derivatives.begin(),
+                arguments.at(i)->non_null_derivatives.end(),
+                inserter(non_null_derivatives_tmp, non_null_derivatives_tmp.begin()));
+      non_null_derivatives = move(non_null_derivatives_tmp);
+    }
 
   preparedForDerivation = true;
 }
-- 
GitLab