diff --git a/CMakeLists.txt b/CMakeLists.txt index a609182..cdef3fc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,7 +49,7 @@ if (${ENABLE_SANITIZER_UNDEFINED_BEHAVIOR}) endif() project_options( - # WARNINGS_AS_ERRORS + WARNINGS_AS_ERRORS # ENABLE_COVERAGE # ENABLE_CPPCHECK # ENABLE_CLANG_TIDY @@ -74,7 +74,7 @@ project_options( # TODO: Address all the warning below. This should be only temporary... target_compile_options(project_warnings - INTERFACE $<$:-Wno-sign-conversion;-Wno-shorten-64-to-32;-Wno-shadow;-Wno-implicit-fallthrough;-Wno-implicit-int-conversion;-Wno-old-style-cast;-Wno-gnu-zero-variadic-macro-arguments;-Wno-implicit-int-float-conversion;-Wno-deprecated-copy;-Wno-missing-field-initializers> + INTERFACE $<$:-Wno-sign-conversion;-Wno-shadow;-Wno-implicit-fallthrough;-Wno-old-style-cast;-Wno-deprecated-copy;-Wno-missing-field-initializers;-Wno-null-dereference;-Wno-maybe-uninitialized> ) check_cxx_source_compiles( diff --git a/src/executable/mlir/Target/PythonBytecode/LinearScanRegisterAllocation.hpp b/src/executable/mlir/Target/PythonBytecode/LinearScanRegisterAllocation.hpp index c044a0b..348ae5d 100644 --- a/src/executable/mlir/Target/PythonBytecode/LinearScanRegisterAllocation.hpp +++ b/src/executable/mlir/Target/PythonBytecode/LinearScanRegisterAllocation.hpp @@ -466,13 +466,13 @@ class LinearScanRegisterAllocation auto current_value = std::get(cur.value); // Resolve block arguments to their defining operations - if (current_value.isa()) { + if (mlir::isa(current_value)) { if (auto it = live_interval_analysis.block_input_mappings.find(cur.value); it != live_interval_analysis.block_input_mappings.end()) { for (auto mapped_value : it->second) { ASSERT(!std::holds_alternative(mapped_value)); if (clobbers_r0(std::get(mapped_value))) { - ASSERT(current_value.isa()); + ASSERT(mlir::isa(current_value)); current_value = std::get(mapped_value); break; } @@ -480,7 +480,7 @@ class LinearScanRegisterAllocation } } - ASSERT(!current_value.isa()); + ASSERT(!mlir::isa(current_value)); auto loc = current_value.getLoc(); // Insert: push r{cur_reg}, move r{scratch}, r{cur_reg}, pop r{cur_reg} diff --git a/src/runtime/PyArgParser.hpp b/src/runtime/PyArgParser.hpp index d799073..4079aef 100644 --- a/src/runtime/PyArgParser.hpp +++ b/src/runtime/PyArgParser.hpp @@ -8,6 +8,8 @@ #include "TypeError.hpp" #include "vm/VM.hpp" +#include + namespace py { template struct PyArgsParser @@ -56,7 +58,15 @@ template struct PyArgsParser return Err(type_error("'{}' object cannot be interpreted as an integer", int_obj.unwrap()->type()->name())); } else { - std::get(result) = as(int_obj.unwrap())->as_i64(); + auto value = as(int_obj.unwrap())->as_i64(); + static_assert(sizeof(ExpectedType) <= 8); + if (!fits_in(value)) { + return Err(type_error("{} not within range ({}, {})", + value, + std::numeric_limits::min(), + std::numeric_limits::max())); + } + std::get(result) = static_cast(value); } } else { []() { diff --git a/src/runtime/PyList.cpp b/src/runtime/PyList.cpp index 7cb52b3..399da8a 100644 --- a/src/runtime/PyList.cpp +++ b/src/runtime/PyList.cpp @@ -505,7 +505,7 @@ PyResult PyList::__mul__(size_t count) const if (count <= 0) { return PyList::create(); } std::vector values; values.reserve(count * m_elements.size()); - for (auto _ : std::views::iota(size_t{ 0 }, count)) { + for ([[maybe_unused]] auto _ : std::views::iota(size_t{ 0 }, count)) { values.insert(values.end(), m_elements.begin(), m_elements.end()); } diff --git a/src/runtime/PyString.cpp b/src/runtime/PyString.cpp index d44de79..348e72d 100644 --- a/src/runtime/PyString.cpp +++ b/src/runtime/PyString.cpp @@ -150,8 +150,11 @@ PyResult PyString::create(const Bytes &bytes, const std::string &enc if (byte < std::byte{ 128 }) { result.push_back(static_cast(byte)); } else { - result.push_back(0xc2 + (static_cast(byte) > 0xbf)); - result.push_back((static_cast(byte) & 0x3f) + 0x80); + result.push_back( + static_cast(0xc2) + static_cast(byte) > 0xbf); + result.push_back(static_cast( + (static_cast(byte) & static_cast(0x3f)) + + static_cast(0x80))); } } return PyString::create(result); @@ -1864,9 +1867,14 @@ PyResult PyString::translate(PyObject *table) const if (mapped_cp > 0x110000 || mapped_cp < 0) { return Err(value_error("character mapping must be in range(0x110000)")); } - auto el = utf8::utf8chr(mapped_cp.get_ui()); + auto mapped_cp_ui = mapped_cp.get_ui(); + if (!fits_in(mapped_cp_ui)) { + return Err(value_error( + "character mapping value {} does not fit in uint32_t", mapped_cp_ui)); + } + auto el = utf8::utf8chr(static_cast(mapped_cp_ui)); if (!el.has_value()) {} - cache[mapped_cp.get_ui()] = *el; + cache[static_cast(mapped_cp_ui)] = *el; result.append(*el); } else if (mapped_value.unwrap()->type()->issubclass(types::str())) { auto mapped_str = static_cast(*mapped_value.unwrap()).value(); diff --git a/src/runtime/Value.cpp b/src/runtime/Value.cpp index 58787d4..d0b09b2 100644 --- a/src/runtime/Value.cpp +++ b/src/runtime/Value.cpp @@ -455,8 +455,8 @@ bool Bytes::operator==(const PyObject *other) const constexpr unsigned char to_digit_value(char value) { if (value >= 0 && value <= 9) { return value; } - if (value >= 'a' && value <= 'z') { return (value - 'a') + 10; } - if (value >= 'A' && value <= 'Z') { return (value - 'A') + 10; } + if (value >= 'a' && value <= 'z') { return static_cast((value - 'a') + 10); } + if (value >= 'A' && value <= 'Z') { return static_cast((value - 'A') + 10); } return 37; } @@ -611,12 +611,6 @@ bool NameConstant::operator==(const NameConstant &other) const [](const auto &rhs, const auto &lhs) { return rhs == lhs; }, value, other.value); } -std::ostream &py::operator<<(std::ostream &os, const Tuple &tuple) -{ - os << tuple.to_string(); - return os; -} - std::string Tuple::to_string() const { std::ostringstream os; @@ -642,6 +636,12 @@ std::string Tuple::to_string() const namespace py { +std::ostream &operator<<(std::ostream &os, const Tuple &tuple) +{ + os << tuple.to_string(); + return os; +} + PyResult add(const Value &lhs, const Value &rhs, Interpreter &) { return std::visit( diff --git a/src/runtime/modules/signal/module.cpp b/src/runtime/modules/signal/module.cpp index 1d5ceed..9800deb 100644 --- a/src/runtime/modules/signal/module.cpp +++ b/src/runtime/modules/signal/module.cpp @@ -11,6 +11,7 @@ #include #include +#include #include namespace py { @@ -83,7 +84,10 @@ PyResult signal(PyTuple *args, PyDict *kwargs) previous_handler = std::get(it->second); } - if (std::signal(signalnum, sighandler) == SIG_ERR) { + if (signalnum >= NSIG) { return Err(value_error("signal number out of range")); } + + static_assert(NSIG < std::numeric_limits::max()); + if (std::signal(static_cast(signalnum), sighandler) == SIG_ERR) { return Err(value_error("error setting signal handler")); } diff --git a/src/runtime/modules/sre/Pattern.cpp b/src/runtime/modules/sre/Pattern.cpp index 4d40887..3a23d9e 100644 --- a/src/runtime/modules/sre/Pattern.cpp +++ b/src/runtime/modules/sre/Pattern.cpp @@ -8,11 +8,13 @@ #include "runtime/PyObject.hpp" #include "runtime/PyTuple.hpp" #include "runtime/TypeError.hpp" +#include "runtime/ValueError.hpp" #include "runtime/types/api.hpp" #include "runtime/types/builtin.hpp" #include "utilities.hpp" #include "vm/VM.hpp" #include +#include using namespace py; using namespace py::sre; @@ -49,7 +51,14 @@ PyResult Pattern::create(PyObject *pattern, auto el_ = PyObject::from(el); if (el_.is_err()) { return Err(el_.unwrap_err()); } if (!el_.unwrap()->type()->issubclass(types::integer())) { TODO(); } - code_vec.push_back(static_cast(*el_.unwrap()).as_size_t()); + auto value = static_cast(*el_.unwrap()).as_size_t(); + if (!fits_in(value)) { + return Err(value_error("code value {} does not fit in [{}, {}]", + value, + std::numeric_limits::min(), + std::numeric_limits::max())); + } + code_vec.push_back(static_cast(value)); } std::optional isbytes; diff --git a/src/runtime/modules/sre/module.cpp b/src/runtime/modules/sre/module.cpp index e9c96a6..2939554 100644 --- a/src/runtime/modules/sre/module.cpp +++ b/src/runtime/modules/sre/module.cpp @@ -95,7 +95,7 @@ PyResult ascii_iscased(PyTuple *args, PyDict *kwargs) auto ch = character->as_big_int().get_si(); if (ch >= 128) { return Ok(py_false()); } - return Ok(std::isalpha(ch) ? py_true() : py_false()); + return Ok(std::isalpha(static_cast(ch)) ? py_true() : py_false()); } PyResult ascii_tolower(PyTuple *args, PyDict *kwargs) @@ -111,7 +111,7 @@ PyResult ascii_tolower(PyTuple *args, PyDict *kwargs) auto ch = character->as_big_int().get_si(); if (ch >= 128) { return Ok(character); } - return PyInteger::create(std::tolower(ch)); + return PyInteger::create(std::tolower(static_cast(ch))); } diff --git a/src/runtime/modules/time/module.cpp b/src/runtime/modules/time/module.cpp index 96514f8..386a142 100644 --- a/src/runtime/modules/time/module.cpp +++ b/src/runtime/modules/time/module.cpp @@ -56,10 +56,10 @@ PyModule *time_module() module->add_symbol(PyString::create("monotonic").unwrap(), PyNativeFunction::create("monotonic", [](PyTuple *, PyDict *) { - const double ns = std::chrono::duration_cast( + auto ns = std::chrono::duration_cast( std::chrono::steady_clock::now().time_since_epoch()) - .count(); - return PyFloat::create(ns / std::nano::den); + .count(); + return PyFloat::create(static_cast(ns) / std::nano::den); }).unwrap()); return module; diff --git a/src/utilities.hpp b/src/utilities.hpp index 70c1b39..060f14c 100644 --- a/src/utilities.hpp +++ b/src/utilities.hpp @@ -83,3 +83,30 @@ template constexpr To bit_cast(const From &from) noexcept return std::bit_cast(from); } #endif + + +template +concept Integral = std::is_integral_v; + +template bool fits_in(Source value) +{ + constexpr bool source_is_signed = std::is_signed::value; + constexpr bool target_is_signed = std::is_signed::value; + + // Case 1: Source is signed, Target is unsigned + if constexpr (source_is_signed && !target_is_signed) { + if (value < 0) { return false; } + // Now we know value is non-negative, safe to cast and compare + return static_cast>(value) + <= std::numeric_limits::max(); + } + // Case 2: Source is unsigned, Target is signed + else if constexpr (!source_is_signed && target_is_signed) { + return value + <= static_cast>(std::numeric_limits::max()); + } else { + // Case 3: Both signed or both unsigned + return value >= std::numeric_limits::min() + && value <= std::numeric_limits::max(); + } +} \ No newline at end of file