diff --git a/frontends/rtlil/rtlil_frontend.cc b/frontends/rtlil/rtlil_frontend.cc index 4709c76ed..418837cf9 100644 --- a/frontends/rtlil/rtlil_frontend.cc +++ b/frontends/rtlil/rtlil_frontend.cc @@ -31,10 +31,6 @@ YOSYS_NAMESPACE_BEGIN struct RTLILFrontendWorker { - // Forbid constants of more than 1 Gb. - // This will help us not explode on malicious RTLIL. - static constexpr int MAX_CONST_WIDTH = 1024 * 1024 * 1024; - std::istream *f = nullptr; RTLIL::Design *design; bool flag_nooverwrite = false; @@ -283,7 +279,7 @@ struct RTLILFrontendWorker { ++idx; std::vector bits; - if (width > MAX_CONST_WIDTH) + if (width >= RTLIL::WIDTH_LIMIT) error("Constant width %lld out of range before `%s`.", width, error_token()); bits.reserve(width); int start_idx = idx; @@ -532,14 +528,22 @@ struct RTLILFrontendWorker { wire = current_module->addWire(std::move(*id)); break; } - if (try_parse_keyword("width")) - width = parse_integer(); + if (try_parse_keyword("width")){ + long long width_val = parse_integer(); + if (width_val < 0 || width_val >= RTLIL::WIDTH_LIMIT) + error("Wire width %lld out of range before `%s`.", width_val, error_token()); + width = width_val; + } else if (try_parse_keyword("upto")) upto = true; else if (try_parse_keyword("signed")) is_signed = true; - else if (try_parse_keyword("offset")) - start_offset = parse_integer(); + else if (try_parse_keyword("offset")) { + long long offset_val = parse_integer(); + if (offset_val < INT_MIN || offset_val > INT_MAX) + error("Wire offset %lld out of range before `%s`.", offset_val, error_token()); + start_offset = offset_val; + } else if (try_parse_keyword("input")) { port_id = parse_integer(); port_input = true; @@ -589,12 +593,24 @@ struct RTLILFrontendWorker { memory->name = std::move(*id); break; } - if (try_parse_keyword("width")) - width = parse_integer(); - else if (try_parse_keyword("size")) - size = parse_integer(); - else if (try_parse_keyword("offset")) - start_offset = parse_integer(); + if (try_parse_keyword("width")){ + long long width_val = parse_integer(); + if (width_val < 0 || width_val >= RTLIL::WIDTH_LIMIT) + error("Memory width %lld out of range before `%s`.", width_val, error_token()); + width = width_val; + } + else if (try_parse_keyword("size")) { + long long size_val = parse_integer(); + if (size_val < INT_MIN || size_val > INT_MAX) + error("Memory size %lld out of range before `%s`.", size_val, error_token()); + size = size_val; + } + else if (try_parse_keyword("offset")) { + long long offset_val = parse_integer(); + if (offset_val < INT_MIN || offset_val > INT_MAX) + error("Memory offset %lld out of range before `%s`.", offset_val, error_token()); + start_offset = offset_val; + } else if (try_parse_eol()) error("Missing memory ID"); else diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index d7503d5e2..89cd1b244 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -379,6 +379,7 @@ RTLIL::Const::Const(long long val) // default width 32 RTLIL::Const::Const(long long val, int width) { + log_assert(width >= 0 && width < RTLIL::WIDTH_LIMIT); flags = RTLIL::CONST_FLAG_NONE; if ((width & 7) == 0) { new ((void*)&str_) std::string(); @@ -407,6 +408,7 @@ RTLIL::Const::Const(long long val, int width) RTLIL::Const::Const(RTLIL::State bit, int width) { + log_assert(width >= 0 && width < RTLIL::WIDTH_LIMIT); flags = RTLIL::CONST_FLAG_NONE; new ((void*)&bits_) bitvectype(); tag = backing_tag::bits; @@ -3170,6 +3172,7 @@ void RTLIL::Module::fixup_ports() RTLIL::Wire *RTLIL::Module::addWire(RTLIL::IdString name, int width) { + log_assert(width >= 0 && width < RTLIL::WIDTH_LIMIT); RTLIL::Wire *wire = new RTLIL::Wire; wire->name = std::move(name); wire->width = width; diff --git a/kernel/rtlil.h b/kernel/rtlil.h index e55caf35a..79466ac3b 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -99,6 +99,9 @@ namespace RTLIL PD_INOUT = 3 }; + // Maximum width in bits of RTLIL::Wire or RTLIL::Const + constexpr int WIDTH_LIMIT = 1 << 30; + struct Const; struct AttrObject; struct NamedObject; @@ -1106,6 +1109,7 @@ public: bits_internal()[i] = state; } void resize(int size, RTLIL::State fill) { + log_assert(size >= 0 && size < RTLIL::WIDTH_LIMIT); bits_internal().resize(size, fill); } diff --git a/pyosys/generator.py b/pyosys/generator.py index 091099742..3ee19cff0 100644 --- a/pyosys/generator.py +++ b/pyosys/generator.py @@ -631,7 +631,7 @@ class PyosysWrapperGenerator(object): self.register_containers(variable) definition_fn = ( - f"def_{'readonly' if variable.type.const else 'readwrite'}_static" + f"def_{'readonly' if (variable.type.const or variable.constexpr) else 'readwrite'}_static" ) variable_python_basename = keyword_aliases.get( diff --git a/tests/rtlil/bug1206.ys b/tests/rtlil/bug1206.ys new file mode 100644 index 000000000..0084bb0f4 --- /dev/null +++ b/tests/rtlil/bug1206.ys @@ -0,0 +1,6 @@ +logger -expect error "Wire width .* out of range" 1 +read_rtlil < mod = std::make_unique(); + EXPECT_DEATH(mod->addWire(ID(test), RTLIL::WIDTH_LIMIT), ""); + EXPECT_NO_FATAL_FAILURE(mod->addWire(ID(test), RTLIL::WIDTH_LIMIT - 1)); + } + TEST_F(KernelRtlilTest, ConstEqualStr) { EXPECT_EQ(Const("abc"), Const("abc")); EXPECT_NE(Const("abc"), Const("def"));