Skip to content
Snippets Groups Projects
Commit fcbca642 authored by Stéphane Del Pino's avatar Stéphane Del Pino
Browse files

Check that natural integers are not initialized to negative value

parent 6882fae1
No related branches found
No related tags found
1 merge request!145git subrepo clone git@gitlab.com:OlMon/org-themes.git packages/org-themes
......@@ -8,6 +8,8 @@
#include <utils/Exceptions.hpp>
#include <utils/PugsTraits.hpp>
#include <exception>
template <typename Op>
struct AffOp;
......@@ -18,6 +20,11 @@ struct AffOp<language::multiplyeq_op>
PUGS_INLINE void
eval(A& a, const B& b)
{
if constexpr (std::is_same_v<uint64_t, A> and std::is_same_v<int64_t, B>) {
if (b < 0) {
throw std::domain_error("trying to affect negative value (" + std::to_string(b) + ")");
}
}
a *= b;
}
};
......@@ -29,6 +36,11 @@ struct AffOp<language::divideeq_op>
PUGS_INLINE void
eval(A& a, const B& b)
{
if constexpr (std::is_same_v<uint64_t, A> and std::is_same_v<int64_t, B>) {
if (b < 0) {
throw std::domain_error("trying to affect negative value (" + std::to_string(b) + ")");
}
}
a /= b;
}
};
......@@ -40,6 +52,12 @@ struct AffOp<language::pluseq_op>
PUGS_INLINE void
eval(A& a, const B& b)
{
if constexpr (std::is_same_v<uint64_t, A> and std::is_same_v<int64_t, B>) {
if (static_cast<int64_t>(a + b) < 0) {
throw std::domain_error("trying to affect negative value (lhs: " + std::to_string(a) +
" rhs: " + std::to_string(b) + ")");
}
}
a += b;
}
};
......@@ -51,6 +69,12 @@ struct AffOp<language::minuseq_op>
PUGS_INLINE void
eval(A& a, const B& b)
{
if constexpr (std::is_same_v<uint64_t, A> and std::is_same_v<int64_t, B>) {
if (static_cast<int64_t>(a - b) < 0) {
throw std::domain_error("trying to affect negative value (lhs: " + std::to_string(a) +
" rhs: " + std::to_string(b) + ")");
}
}
a -= b;
}
};
......@@ -72,6 +96,7 @@ class AffectationExecutor final : public IAffectationExecutor
{
private:
DataVariant& m_lhs;
ASTNode& m_node;
static inline const bool m_is_defined{[] {
if constexpr (std::is_same_v<std::decay_t<ValueT>, bool>) {
......@@ -83,7 +108,7 @@ class AffectationExecutor final : public IAffectationExecutor
}()};
public:
AffectationExecutor(ASTNode& node, DataVariant& lhs) : m_lhs(lhs)
AffectationExecutor(ASTNode& node, DataVariant& lhs) : m_lhs(lhs), m_node{node}
{
// LCOV_EXCL_START
if constexpr (not m_is_defined) {
......@@ -122,7 +147,13 @@ class AffectationExecutor final : public IAffectationExecutor
} else {
if constexpr (std::is_same_v<OperatorT, language::eq_op>) {
if constexpr (std::is_convertible_v<DataT, ValueT>) {
m_lhs = static_cast<ValueT>(std::get<DataT>(rhs));
const DataT& value = std::get<DataT>(rhs);
if constexpr (std::is_same_v<uint64_t, ValueT> and std::is_same_v<int64_t, DataT>) {
if (value < 0) {
throw std::domain_error("trying to affect negative value (" + std::to_string(value) + ")");
}
}
m_lhs = static_cast<ValueT>(value);
} else if constexpr (std::is_same_v<DataT, AggregateDataVariant>) {
const AggregateDataVariant& v = std::get<AggregateDataVariant>(rhs);
if constexpr (is_tiny_vector_v<ValueT>) {
......@@ -236,7 +267,12 @@ class AffectationProcessor final : public INodeProcessor
DataVariant
execute(ExecutionPolicy& exec_policy)
{
try {
m_affectation_executor->affect(exec_policy, m_rhs_node.execute(exec_policy));
}
catch (std::domain_error& e) {
throw ParseError(e.what(), m_rhs_node.begin());
}
return {};
}
......@@ -357,12 +393,18 @@ class AffectationToTupleProcessor final : public AffectationToDataVariantProcess
{
DataVariant value = m_rhs_node.execute(exec_policy);
try {
std::visit(
[&](auto&& v) {
using T = std::decay_t<decltype(v)>;
if constexpr (std::is_same_v<T, ValueT>) {
*m_lhs = std::vector{std::move(v)};
} else if constexpr (std::is_arithmetic_v<ValueT> and std::is_convertible_v<T, ValueT>) {
if constexpr (std::is_same_v<uint64_t, ValueT> and std::is_same_v<int64_t, T>) {
if (v < 0) {
throw std::domain_error("trying to affect negative value (" + std::to_string(v) + ")");
}
}
*m_lhs = std::vector{std::move(static_cast<ValueT>(v))};
} else if constexpr (std::is_same_v<std::string, ValueT>) {
if constexpr (std::is_arithmetic_v<T>) {
......@@ -392,7 +434,10 @@ class AffectationToTupleProcessor final : public AffectationToDataVariantProcess
}
},
value);
}
catch (std::domain_error& e) {
throw ParseError(e.what(), m_rhs_node.begin());
}
return {};
}
......@@ -412,12 +457,18 @@ class AffectationToTupleFromListProcessor final : public AffectationToDataVarian
{
std::vector<ValueT> tuple_value(children_values.size());
for (size_t i = 0; i < children_values.size(); ++i) {
try {
std::visit(
[&](auto&& child_value) {
using T = std::decay_t<decltype(child_value)>;
if constexpr (std::is_same_v<T, ValueT>) {
tuple_value[i] = child_value;
} else if constexpr (std::is_arithmetic_v<ValueT> and std::is_convertible_v<T, ValueT>) {
if constexpr (std::is_same_v<uint64_t, ValueT> and std::is_same_v<int64_t, T>) {
if (child_value < 0) {
throw std::domain_error("trying to affect negative value (" + std::to_string(child_value) + ")");
}
}
tuple_value[i] = static_cast<ValueT>(child_value);
} else if constexpr (std::is_same_v<std::string, ValueT>) {
if constexpr (std::is_arithmetic_v<T>) {
......@@ -504,6 +555,10 @@ class AffectationToTupleFromListProcessor final : public AffectationToDataVarian
},
children_values[i]);
}
catch (std::domain_error& e) {
throw ParseError(e.what(), m_rhs_node.children[i]->begin());
}
}
*m_lhs = std::move(tuple_value);
}
......@@ -620,11 +675,14 @@ class ListAffectationProcessor final : public INodeProcessor
{
AggregateDataVariant children_values = std::get<AggregateDataVariant>(m_node.children[1]->execute(exec_policy));
Assert(m_affectation_executor_list.size() == children_values.size());
for (size_t i = 0; i < m_affectation_executor_list.size(); ++i) {
try {
m_affectation_executor_list[i]->affect(exec_policy, std::move(children_values[i]));
}
catch (std::domain_error& e) {
throw ParseError(e.what(), m_node.children[1]->children[i]->begin());
}
}
return {};
}
......
......@@ -68,6 +68,25 @@
REQUIRE_THROWS_WITH(ASTBuilder::build(input), error_message); \
}
#define CHECK_AFFECTATION_EXEC_THROWS_WITH(data, error_message) \
{ \
TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"}; \
auto ast = ASTBuilder::build(input); \
\
ASTModulesImporter{*ast}; \
\
ASTSymbolTableBuilder{*ast}; \
ASTNodeDataTypeBuilder{*ast}; \
\
ASTNodeDeclarationToAffectationConverter{*ast}; \
ASTNodeTypeCleaner<language::var_declaration>{*ast}; \
\
ASTNodeExpressionBuilder{*ast}; \
ExecutionPolicy exec_policy; \
\
REQUIRE_THROWS_WITH(ast->execute(exec_policy), error_message); \
}
// clazy:excludeall=non-pod-global-static
TEST_CASE("AffectationProcessor", "[language]")
......@@ -370,19 +389,26 @@ TEST_CASE("AffectationProcessor", "[language]")
{
CHECK_AFFECTATION_THROWS_WITH("let n : N, n = 2.3;", "undefined affectation type: N = R");
CHECK_AFFECTATION_THROWS_WITH("let n : N, n = \"bar\";", "undefined affectation type: N = string");
CHECK_AFFECTATION_EXEC_THROWS_WITH("let n : N, n = -2;", "trying to affect negative value (-2)");
CHECK_AFFECTATION_THROWS_WITH("let n : N, n = 2; n += 1.1;", "undefined affectation type: N += R");
CHECK_AFFECTATION_THROWS_WITH("let n : N, n = 2; n += \"foo\";", "undefined affectation type: N += string");
CHECK_AFFECTATION_EXEC_THROWS_WITH("let n : N, n = 2; n+=-3;",
"trying to affect negative value (lhs: 2 rhs: -3)");
CHECK_AFFECTATION_THROWS_WITH("let n : N, n = 2; n -= 1.1;", "undefined affectation type: N -= R");
CHECK_AFFECTATION_THROWS_WITH("let n : N, n = 2; n -= \"bar\";", "undefined affectation type: N -= string");
CHECK_AFFECTATION_EXEC_THROWS_WITH("let n : N, n = 2; n-=3;",
"trying to affect negative value (lhs: 2 rhs: 3)");
CHECK_AFFECTATION_THROWS_WITH("let n : N, n = 2; n *= 2.51;", "undefined affectation type: N *= R");
CHECK_AFFECTATION_THROWS_WITH("let n : N, n = 2; n *= \"foobar\";", "undefined affectation type: N *= string");
CHECK_AFFECTATION_EXEC_THROWS_WITH("let n : N, n = 2; n*= -2;", "trying to affect negative value (-2)");
CHECK_AFFECTATION_THROWS_WITH("let n : N, n = 2; n /= true;", "undefined affectation type: N /= B");
CHECK_AFFECTATION_THROWS_WITH("let n : N, n = 2; n /= 2.51;", "undefined affectation type: N /= R");
CHECK_AFFECTATION_THROWS_WITH("let n : N, n = 2; n /= \"foo\";", "undefined affectation type: N /= string");
CHECK_AFFECTATION_EXEC_THROWS_WITH("let n : N, n = 2; n/= -2;", "trying to affect negative value (-2)");
}
SECTION("-> Z")
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment