61 lines
2.4 KiB
C++
61 lines
2.4 KiB
C++
// Phase 3 (int-truncation recall): explicit narrowing casts ((char)x,
|
|
// static_cast<char>(x)) carry the truncation in an inner ImplicitCast flagged
|
|
// part_of_explicit_cast that no use site observes. The encoder now fires the
|
|
// truncation hook for exactly those nodes — without double-counting ordinary
|
|
// implicit narrowings, which are still observed at their use sites.
|
|
#include <clang/Frontend/ASTUnit.h>
|
|
#include <clang/Tooling/Tooling.h>
|
|
|
|
#include <catch2/catch_test_macros.hpp>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "fold/detect/int_truncation.hpp"
|
|
#include "fold/report/finding.hpp"
|
|
#include "fold/symbolic/budget.hpp"
|
|
|
|
namespace {
|
|
|
|
std::size_t runTrunc(const std::string& body) {
|
|
const std::string code = "extern int RAND32();\nvoid sink(char);\n" + body;
|
|
auto unit = clang::tooling::buildASTFromCodeWithArgs(code, {"-std=c++17"}, "input.cpp");
|
|
REQUIRE(unit);
|
|
fold::SolverBudget b;
|
|
fold::SolverStats s;
|
|
auto fs = fold::detectIntTruncationInContext(unit->getASTContext(), b, s);
|
|
std::size_t n = 0;
|
|
for (const auto& f : fs)
|
|
if (f.kind == fold::FindingKind::IntTruncation)
|
|
++n;
|
|
return n;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
TEST_CASE("explicit C-style narrowing cast is flagged", "[int-truncation][cast]") {
|
|
REQUIRE(runTrunc("void f(short data){ char c = (char)data; sink(c); }") >= 1);
|
|
}
|
|
|
|
TEST_CASE("explicit static_cast narrowing is flagged", "[int-truncation][cast]") {
|
|
REQUIRE(runTrunc("void f(short data){ char c = static_cast<char>(data); sink(c); }") >= 1);
|
|
}
|
|
|
|
TEST_CASE("explicit narrowing cast in a call argument is flagged", "[int-truncation][cast]") {
|
|
REQUIRE(runTrunc("void f(short data){ sink((char)data); }") >= 1);
|
|
}
|
|
|
|
TEST_CASE("implicit narrowing is still flagged exactly once", "[int-truncation][cast]") {
|
|
// Must NOT double-count: the implicit cast is observed at the init use site,
|
|
// not at the cast node.
|
|
REQUIRE(runTrunc("void f(short data){ char c = data; sink(c); }") == 1);
|
|
}
|
|
|
|
TEST_CASE("explicit widening cast is not flagged", "[int-truncation][cast]") {
|
|
REQUIRE(runTrunc("void f(char data){ int w = (int)data; sink((char)w); (void)w; }") == 1);
|
|
// ^ exactly one: the (char)w narrowing fires; the (int)data widening does not.
|
|
}
|
|
|
|
TEST_CASE("same-width explicit cast is not flagged", "[int-truncation][cast]") {
|
|
REQUIRE(runTrunc("void f(char data){ char c = (char)data; sink(c); }") == 0);
|
|
}
|