source/Sanitizer.cpp (142 lines of code) (raw):
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <mariana-trench/Assert.h>
#include <mariana-trench/JsonValidation.h>
#include <mariana-trench/Log.h>
#include <mariana-trench/NamedKind.h>
#include <mariana-trench/PartialKind.h>
#include <mariana-trench/Sanitizer.h>
namespace marianatrench {
Sanitizer::Sanitizer(
const SanitizerKind& sanitizer_kind,
const KindSetAbstractDomain& kinds)
: sanitizer_kind_(sanitizer_kind), kinds_(kinds) {
mt_assert(
sanitizer_kind_ != SanitizerKind::Propagations || !kinds_.is_value());
}
bool Sanitizer::leq(const Sanitizer& other) const {
if (is_bottom()) {
return true;
} else if (other.is_bottom()) {
return false;
}
return sanitizer_kind_ == other.sanitizer_kind_ && kinds_.leq(other.kinds_);
}
bool Sanitizer::equals(const Sanitizer& other) const {
if (is_bottom()) {
return other.is_bottom();
} else if (other.is_bottom()) {
return false;
} else {
return sanitizer_kind_ == other.sanitizer_kind_ && kinds_ == other.kinds_;
}
}
void Sanitizer::join_with(const Sanitizer& other) {
mt_if_expensive_assert(auto previous = *this);
if (is_bottom()) {
*this = other;
} else if (other.is_bottom()) {
return;
} else {
mt_assert(sanitizer_kind_ == other.sanitizer_kind_);
kinds_.join_with(other.kinds_);
}
mt_expensive_assert(previous.leq(*this) && other.leq(*this));
}
void Sanitizer::widen_with(const Sanitizer& other) {
join_with(other);
}
void Sanitizer::meet_with(const Sanitizer& /* other */) {
mt_unreachable(); // Not implemented
}
void Sanitizer::narrow_with(const Sanitizer& other) {
meet_with(other);
}
std::ostream& operator<<(std::ostream& out, const Sanitizer& sanitizer) {
if (sanitizer.is_bottom()) {
return out << "Sanitizer()";
}
out << "Sanitizer(";
switch (sanitizer.sanitizer_kind_) {
case SanitizerKind::Sources:
out << "Sources";
break;
case SanitizerKind::Sinks:
out << "Sinks";
break;
case SanitizerKind::Propagations:
out << "Propagations";
break;
}
if (sanitizer.kinds_.is_value()) {
out << ", kinds = " << sanitizer.kinds_;
}
return out << ")";
}
const Sanitizer Sanitizer::from_json(
const Json::Value& value,
Context& context) {
JsonValidation::validate_object(value);
SanitizerKind sanitizer_kind;
auto sanitizer_kind_string =
JsonValidation::string(value, /* field */ "sanitize");
if (sanitizer_kind_string == "sources") {
sanitizer_kind = SanitizerKind::Sources;
} else if (sanitizer_kind_string == "sinks") {
sanitizer_kind = SanitizerKind::Sinks;
} else if (sanitizer_kind_string == "propagations") {
sanitizer_kind = SanitizerKind::Propagations;
} else {
throw JsonValidationError(
value,
/* field */ "sanitizer",
/* expected */ "`sources`, `sinks` or `propagations`");
}
KindSetAbstractDomain kinds;
if (value.isMember("kinds")) {
if (sanitizer_kind == SanitizerKind::Propagations) {
throw JsonValidationError(
value,
/* field */ "kinds",
/* expected */
"Unspecified kinds for propagation sanitizers");
}
kinds = KindSetAbstractDomain();
for (const auto& kind_json :
JsonValidation::nonempty_array(value, "kinds")) {
kinds.add(Kind::from_json(kind_json, context));
}
} else {
kinds = KindSetAbstractDomain::top();
}
return Sanitizer(sanitizer_kind, kinds);
}
Json::Value Sanitizer::to_json() const {
mt_assert(!is_bottom());
auto value = Json::Value(Json::objectValue);
switch (sanitizer_kind_) {
case SanitizerKind::Sources:
value["sanitize"] = "sources";
break;
case SanitizerKind::Sinks:
value["sanitize"] = "sinks";
break;
case SanitizerKind::Propagations:
value["sanitize"] = "propagations";
break;
}
if (kinds_.is_value()) {
auto kinds_json = Json::Value(Json::arrayValue);
for (const auto* kind : kinds_.elements()) {
kinds_json.append(kind->to_json());
}
value["kinds"] = kinds_json;
}
return value;
}
bool Sanitizer::GroupEqual::operator()(
const Sanitizer& left,
const Sanitizer& right) const {
return left.sanitizer_kind() == right.sanitizer_kind();
}
std::size_t Sanitizer::GroupHash::operator()(const Sanitizer& sanitizer) const {
return std::hash<SanitizerKind>()(sanitizer.sanitizer_kind());
}
} // namespace marianatrench