From 2e8d9af241ea37fe12d4520c126b71beb228e5f0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Del=20Pino?= <stephane.delpino44@gmail.com>
Date: Tue, 7 Jun 2022 17:55:41 +0200
Subject: [PATCH] Forbid implicit conversion of negative integer to N or (N)
 arguments

- add missing non-negativity check for tuples of N that are
initialized by a single value
- add related tests
---
 .../BuiltinFunctionProcessor.hpp              | 15 ++++++++--
 .../FunctionArgumentConverter.hpp             |  5 ++++
 tests/test_BuiltinFunctionProcessor.cpp       | 29 +++++++++++++++++++
 3 files changed, 47 insertions(+), 2 deletions(-)

diff --git a/src/language/node_processor/BuiltinFunctionProcessor.hpp b/src/language/node_processor/BuiltinFunctionProcessor.hpp
index 4e5583adb..7e5a112b4 100644
--- a/src/language/node_processor/BuiltinFunctionProcessor.hpp
+++ b/src/language/node_processor/BuiltinFunctionProcessor.hpp
@@ -52,14 +52,25 @@ class BuiltinFunctionProcessor : public INodeProcessor
     ExecutionPolicy context_exec_policy{exec_policy,
                                         ExecutionPolicy::Context{-1, std::make_shared<ExecutionPolicy::Context::Values>(
                                                                        m_argument_converters.size())}};
+
     if (m_argument_converters.size() == 1) {
-      m_argument_converters[0]->convert(context_exec_policy, m_argument_node.execute(context_exec_policy));
+      try {
+        m_argument_converters[0]->convert(context_exec_policy, m_argument_node.execute(context_exec_policy));
+      }
+      catch (std::domain_error& e) {
+        throw ParseError(e.what(), m_argument_node.begin());
+      }
     } else {
       AggregateDataVariant argument_values{
         std::get<AggregateDataVariant>(m_argument_node.execute(context_exec_policy))};
 
       for (size_t i = 0; i < m_argument_converters.size(); ++i) {
-        m_argument_converters[i]->convert(context_exec_policy, std::move(argument_values[i]));
+        try {
+          m_argument_converters[i]->convert(context_exec_policy, std::move(argument_values[i]));
+        }
+        catch (std::domain_error& e) {
+          throw ParseError(e.what(), m_argument_node.children[i]->begin());
+        }
       }
     }
 
diff --git a/src/language/node_processor/FunctionArgumentConverter.hpp b/src/language/node_processor/FunctionArgumentConverter.hpp
index 3f7b941af..769bcd9ef 100644
--- a/src/language/node_processor/FunctionArgumentConverter.hpp
+++ b/src/language/node_processor/FunctionArgumentConverter.hpp
@@ -222,6 +222,11 @@ class FunctionTupleArgumentConverter final : public IFunctionArgumentConverter
             }
           } else if constexpr (std::is_convertible_v<ValueT, ContentType> and not is_tiny_vector_v<ContentType> and
                                not is_tiny_matrix_v<ContentType>) {
+            if constexpr (std::is_same_v<ContentType, uint64_t> and std::is_same_v<ValueT, int64_t>) {
+              if (v < 0) {
+                throw std::domain_error("trying to convert negative value (" + std::to_string(v) + ")");
+              }
+            }
             exec_policy.currentContext()[m_argument_id] = std::move(TupleType{static_cast<ContentType>(v)});
           } else {
             throw UnexpectedError(std::string{"cannot convert '"} + demangle<ValueT>() + "' to '" +
diff --git a/tests/test_BuiltinFunctionProcessor.cpp b/tests/test_BuiltinFunctionProcessor.cpp
index bbc5ac52e..1cdfec95e 100644
--- a/tests/test_BuiltinFunctionProcessor.cpp
+++ b/tests/test_BuiltinFunctionProcessor.cpp
@@ -368,5 +368,34 @@ runtimeError();
 
       CHECK_AST_THROWS_WITH(data, error);
     }
+
+    SECTION("negative Z to N conversion")
+    {
+      std::string_view data = R"(
+NtoR(3);
+NtoR(-4);
+)";
+
+      CHECK_AST_THROWS_WITH(data, std::string{"trying to convert negative value (-4)"});
+    }
+
+    SECTION("negative Z in list  to (N) conversion")
+    {
+      std::string_view data = R"(
+tuple_NtoR(2);
+tuple_NtoR(-1);
+)";
+
+      CHECK_AST_THROWS_WITH(data, std::string{"trying to convert negative value (-1)"});
+    }
+
+    SECTION("negative Z in list  to (N) conversion")
+    {
+      std::string_view data = R"(
+tuple_NtoR((3, 2, -3, 2));
+)";
+
+      CHECK_AST_THROWS_WITH(data, std::string{"trying to convert negative value (-3)"});
+    }
   }
 }
-- 
GitLab