#![cfg_attr(any(), rustfmt::skip)]
#![allow(clippy::duplicated_attributes)]
use std::fmt::{Debug, Display, Formatter};
use std::io;
use serde::Serialize;
use thiserror::Error;
use yara_x_macros::ErrorEnum;
use yara_x_macros::ErrorStruct;
use yara_x_parser::ast;
use crate::compiler::report::{Level, Patch, Report, ReportBuilder, CodeLoc, Label, Footer};
#[derive(Error, Debug)]
#[error(transparent)]
#[doc(hidden)]
pub struct EmitWasmError(#[from] anyhow::Error);
#[derive(Error, Debug, Eq, PartialEq)]
#[error("`{0}` is not a valid warning code")]
pub struct InvalidWarningCode(String);
impl InvalidWarningCode {
pub(crate) fn new(code: String) -> Self {
Self(code)
}
}
#[derive(Error, Debug)]
pub enum SerializationError {
#[error("incompatible version, expected {expected} got {actual}")]
InvalidVersion {
expected: u32,
actual: u32,
},
#[error("not a YARA-X compiled rules file")]
InvalidFormat,
#[error("cannot encode YARA-X rules")]
EncodeError(#[from] bincode::error::EncodeError),
#[error("cannot decode YARA-X rules")]
DecodeError(#[from] bincode::error::DecodeError),
#[error(transparent)]
IoError(#[from] io::Error),
#[error("invalid YARA-X compiled rules file")]
InvalidWASM(#[from] anyhow::Error),
}
#[allow(missing_docs)]
#[non_exhaustive]
#[derive(ErrorEnum, Error, Clone, PartialEq, Eq)]
#[derive(Serialize)]
#[serde(tag = "type")]
pub enum CompileError {
ArbitraryRegexpPrefix(Box<ArbitraryRegexpPrefix>),
AssignmentMismatch(Box<AssignmentMismatch>),
CircularIncludes(Box<CircularIncludes>),
ConflictingRuleIdentifier(Box<ConflictingRuleIdentifier>),
CustomError(Box<CustomError>),
DuplicateModifier(Box<DuplicateModifier>),
DuplicatePattern(Box<DuplicatePattern>),
DuplicateRule(Box<DuplicateRule>),
DuplicateTag(Box<DuplicateTag>),
EmptyPatternSet(Box<EmptyPatternSet>),
EntrypointUnsupported(Box<EntrypointUnsupported>),
IncludeError(Box<IncludeError>),
IncludeNotAllowed(Box<IncludeNotAllowed>),
IncludeNotFound(Box<IncludeNotFound>),
InvalidBase64Alphabet(Box<InvalidBase64Alphabet>),
InvalidEscapeSequence(Box<InvalidEscapeSequence>),
InvalidFloat(Box<InvalidFloat>),
InvalidInteger(Box<InvalidInteger>),
InvalidMetadata(Box<InvalidMetadata>),
InvalidModifier(Box<InvalidModifier>),
InvalidModifierCombination(Box<InvalidModifierCombination>),
InvalidPattern(Box<InvalidPattern>),
InvalidRange(Box<InvalidRange>),
InvalidRegexp(Box<InvalidRegexp>),
InvalidRegexpModifier(Box<InvalidRegexpModifier>),
InvalidRuleName(Box<InvalidRuleName>),
InvalidTag(Box<InvalidTag>),
InvalidUTF8(Box<InvalidUTF8>),
MethodNotAllowedInWith(Box<MethodNotAllowedInWith>),
MismatchingTypes(Box<MismatchingTypes>),
MissingMetadata(Box<MissingMetadata>),
MixedGreediness(Box<MixedGreediness>),
NumberOutOfRange(Box<NumberOutOfRange>),
PotentiallySlowLoop(Box<PotentiallySlowLoop>),
SlowPattern(Box<SlowPattern>),
SyntaxError(Box<SyntaxError>),
TooManyPatterns(Box<TooManyPatterns>),
UnexpectedEscapeSequence(Box<UnexpectedEscapeSequence>),
UnexpectedNegativeNumber(Box<UnexpectedNegativeNumber>),
UnknownField(Box<UnknownField>),
UnknownIdentifier(Box<UnknownIdentifier>),
UnknownModule(Box<UnknownModule>),
UnknownPattern(Box<UnknownPattern>),
UnknownTag(Box<UnknownTag>),
UnusedPattern(Box<UnusedPattern>),
WrongArguments(Box<WrongArguments>),
WrongType(Box<WrongType>),
}
impl CompileError {
pub(crate) fn from(
report_builder: &ReportBuilder,
err: ast::Error,
) -> Self {
match err {
ast::Error::SyntaxError { message, span } => {
SyntaxError::build(report_builder, message, report_builder.span_to_code_loc(span))
}
ast::Error::InvalidInteger { message, span } => {
InvalidInteger::build(report_builder, message, report_builder.span_to_code_loc(span))
}
ast::Error::InvalidFloat { message, span } => {
InvalidFloat::build(report_builder, message, report_builder.span_to_code_loc(span))
}
ast::Error::InvalidRegexpModifier { message, span } => {
InvalidRegexpModifier::build(
report_builder,
message,
report_builder.span_to_code_loc(span),
)
}
ast::Error::InvalidEscapeSequence { message, span } => {
InvalidEscapeSequence::build(
report_builder,
message,
report_builder.span_to_code_loc(span),
)
}
ast::Error::UnexpectedEscapeSequence(span) => {
UnexpectedEscapeSequence::build(report_builder, report_builder.span_to_code_loc(span))
}
ast::Error::InvalidUTF8(span) => {
InvalidUTF8::build(report_builder, report_builder.span_to_code_loc(span))
}
}
}
pub(crate) fn join_with_or<S: ToString>(s: &[S], quotes: bool) -> String {
let mut strings = if quotes {
s.iter()
.map(|s| format!("`{}`", s.to_string()))
.collect::<Vec<String>>()
} else {
s.iter().map(|s| s.to_string()).collect::<Vec<String>>()
};
strings.sort();
strings.dedup();
match strings.len() {
1 => strings[0].to_owned(),
2 => format!("{} or {}", strings[0], strings[1]),
l => {
format!(
"{}, or {}",
strings[..l - 1].join(", "),
strings[l - 1]
)
}
}
}
}
#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
#[associated_enum(CompileError)]
#[error(code = "E001", title = "syntax error")]
#[label("{error}", error_loc)]
pub struct SyntaxError {
report: Report,
error: String,
error_loc: CodeLoc,
}
#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
#[associated_enum(CompileError)]
#[error(code = "E002", title = "wrong type")]
#[label(
"expression should be {expected_types}, but it is {actual_type}",
error_loc
)]
#[footer(help, Level::HELP)]
pub struct WrongType {
report: Report,
expected_types: String,
actual_type: String,
error_loc: CodeLoc,
help: Option<String>,
}
#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
#[associated_enum(CompileError)]
#[error(code = "E003", title = "mismatching types")]
#[label("this expression is `{type1}`", type1_loc)]
#[label("this expression is `{type2}`", type2_loc)]
pub struct MismatchingTypes {
report: Report,
type1: String,
type2: String,
type1_loc: CodeLoc,
type2_loc: CodeLoc,
}
#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
#[associated_enum(CompileError)]
#[error(code = "E004", title = "wrong arguments")]
#[label("wrong arguments in this call", error_loc)]
#[footer(note)]
pub struct WrongArguments {
report: Report,
error_loc: CodeLoc,
note: Option<String>,
}
#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
#[associated_enum(CompileError)]
#[error(code = "E005", title = "assignment mismatch")]
#[label("this expects {expected_values} value(s)", error_loc)]
#[label("this produces {actual_values} value(s)", iterable_loc)]
pub struct AssignmentMismatch {
report: Report,
expected_values: u8,
actual_values: u8,
iterable_loc: CodeLoc,
error_loc: CodeLoc,
}
#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
#[associated_enum(CompileError)]
#[error(code = "E006", title = "unexpected negative number")]
#[label("this number can not be negative", error_loc)]
pub struct UnexpectedNegativeNumber {
report: Report,
error_loc: CodeLoc,
}
#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
#[associated_enum(CompileError)]
#[error(code = "E007", title = "number out of range")]
#[label("this number is out of the allowed range [{min}-{max}]", error_loc)]
pub struct NumberOutOfRange {
report: Report,
min: i64,
max: i64,
error_loc: CodeLoc,
}
#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
#[associated_enum(CompileError)]
#[error(code = "E008", title = "unknown field or method `{identifier}`")]
#[label("this field or method doesn't exist", error_loc)]
pub struct UnknownField {
report: Report,
identifier: String,
error_loc: CodeLoc,
}
#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
#[associated_enum(CompileError)]
#[error(code = "E009", title = "unknown identifier `{identifier}`")]
#[label("this identifier has not been declared", identifier_loc)]
#[footer(note)]
pub struct UnknownIdentifier {
report: Report,
identifier: String,
identifier_loc: CodeLoc,
note: Option<String>,
}
impl UnknownIdentifier {
#[inline]
pub fn identifier(&self) -> &str {
self.identifier.as_str()
}
pub(crate) fn identifier_location(&self) -> &CodeLoc {
&self.identifier_loc
}
}
#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
#[associated_enum(CompileError)]
#[error(code = "E010", title = "unknown module `{identifier}`")]
#[label("module `{identifier}` not found", error_loc)]
pub struct UnknownModule {
report: Report,
identifier: String,
error_loc: CodeLoc,
}
#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
#[associated_enum(CompileError)]
#[error(code = "E011", title = "invalid range")]
#[label("{error}", error_loc)]
pub struct InvalidRange {
report: Report,
error: String,
error_loc: CodeLoc,
}
#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
#[associated_enum(CompileError)]
#[error(code = "E012", title = "duplicate rule `{new_rule}`")]
#[label(
"duplicate declaration of `{new_rule}`",
duplicate_rule_loc,
Level::ERROR
)]
#[label(
"`{new_rule}` declared here for the first time",
existing_rule_loc,
Level::NOTE
)]
pub struct DuplicateRule {
report: Report,
new_rule: String,
duplicate_rule_loc: CodeLoc,
existing_rule_loc: CodeLoc,
}
#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
#[associated_enum(CompileError)]
#[error(
code = "E013",
title = "rule `{identifier}` conflicts with an existing identifier"
)]
#[label("identifier already in use by a module or global variable", error_loc)]
pub struct ConflictingRuleIdentifier {
report: Report,
identifier: String,
error_loc: CodeLoc,
}
#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
#[associated_enum(CompileError)]
#[error(code = "E014", title = "invalid regular expression")]
#[label("{error}", error_loc)]
#[footer(note)]
pub struct InvalidRegexp {
report: Report,
error: String,
error_loc: CodeLoc,
note: Option<String>,
}
#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
#[associated_enum(CompileError)]
#[error(
code = "E015",
title = "mixing greedy and non-greedy quantifiers in regular expression"
)]
#[label("this is {quantifier1_greediness}", quantifier1_loc)]
#[label("this is {quantifier2_greediness}", quantifier2_loc)]
pub struct MixedGreediness {
report: Report,
quantifier1_greediness: String,
quantifier2_greediness: String,
quantifier1_loc: CodeLoc,
quantifier2_loc: CodeLoc,
}
#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
#[associated_enum(CompileError)]
#[error(code = "E016", title = "no matching patterns")]
#[label("there's no pattern in this set", error_loc)]
#[footer(note)]
pub struct EmptyPatternSet {
report: Report,
error_loc: CodeLoc,
note: Option<String>,
}
#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
#[associated_enum(CompileError)]
#[error(code = "E017", title = "`entrypoint` is unsupported")]
#[label("the `entrypoint` keyword is not supported anymore", error_loc)]
pub struct EntrypointUnsupported {
report: Report,
error_loc: CodeLoc,
}
#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
#[associated_enum(CompileError)]
#[error(code = "E018", title = "slow pattern")]
#[label("this pattern may slow down the scan", error_loc)]
#[footer(note)]
pub struct SlowPattern {
report: Report,
error_loc: CodeLoc,
note: Option<String>,
}
#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
#[associated_enum(CompileError)]
#[error(
code = "E019",
title = "invalid modifier combination: `{modifier1}` `{modifier2}`"
)]
#[label("`{modifier1}` modifier used here", modifier1_loc)]
#[label("`{modifier2}` modifier used here", modifier2_loc)]
#[footer(note)]
pub struct InvalidModifierCombination {
report: Report,
modifier1: String,
modifier2: String,
modifier1_loc: CodeLoc,
modifier2_loc: CodeLoc,
note: Option<String>,
}
#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
#[associated_enum(CompileError)]
#[error(code = "E020", title = "duplicate pattern modifier")]
#[label("duplicate modifier", error_loc)]
pub struct DuplicateModifier {
report: Report,
error_loc: CodeLoc,
}
#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
#[associated_enum(CompileError)]
#[error(code = "E021", title = "duplicate tag `{tag}`")]
#[label("duplicate tag", error_loc)]
pub struct DuplicateTag {
report: Report,
tag: String,
error_loc: CodeLoc,
}
#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
#[associated_enum(CompileError)]
#[error(code = "E022", title = "unused pattern `{pattern_ident}`")]
#[label("this pattern was not used in the condition", error_loc)]
pub struct UnusedPattern {
report: Report,
pattern_ident: String,
error_loc: CodeLoc,
}
#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
#[associated_enum(CompileError)]
#[error(code = "E023", title = "duplicate pattern `{pattern_ident}`")]
#[label("duplicate declaration of `{pattern_ident}`", error_loc)]
#[label(
"`{pattern_ident}` declared here for the first time",
note_loc,
Level::NOTE
)]
pub struct DuplicatePattern {
report: Report,
pattern_ident: String,
error_loc: CodeLoc,
note_loc: CodeLoc,
}
#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
#[associated_enum(CompileError)]
#[error(code = "E024", title = "invalid pattern `{pattern_ident}`")]
#[label("{error}", error_loc)]
#[footer(note)]
pub struct InvalidPattern {
report: Report,
pattern_ident: String,
error: String,
error_loc: CodeLoc,
note: Option<String>,
}
#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
#[associated_enum(CompileError)]
#[error(code = "E025", title = "unknown pattern `{pattern_ident}`")]
#[label("this pattern is not declared in the `strings` section", error_loc)]
pub struct UnknownPattern {
report: Report,
pattern_ident: String,
error_loc: CodeLoc,
}
#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
#[associated_enum(CompileError)]
#[error(code = "E026", title = "invalid base64 alphabet")]
#[label("{error}", error_loc)]
pub struct InvalidBase64Alphabet {
report: Report,
error: String,
error_loc: CodeLoc,
}
#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
#[associated_enum(CompileError)]
#[error(code = "E027", title = "invalid integer")]
#[label("{error}", error_loc)]
pub struct InvalidInteger {
report: Report,
error: String,
error_loc: CodeLoc,
}
#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
#[associated_enum(CompileError)]
#[error(code = "E028", title = "invalid float")]
#[label("{error}", error_loc)]
pub struct InvalidFloat {
report: Report,
error: String,
error_loc: CodeLoc,
}
#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
#[associated_enum(CompileError)]
#[error(code = "E029", title = "invalid escape sequence")]
#[label("{error}", error_loc)]
pub struct InvalidEscapeSequence {
report: Report,
error: String,
error_loc: CodeLoc,
}
#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
#[associated_enum(CompileError)]
#[error(code = "E030", title = "invalid regexp modifier `{modifier}`")]
#[label("invalid modifier", error_loc)]
pub struct InvalidRegexpModifier {
report: Report,
modifier: String,
error_loc: CodeLoc,
}
#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
#[associated_enum(CompileError)]
#[error(code = "E031", title = "unexpected escape sequence")]
#[label("escape sequences are not allowed in this string", error_loc)]
pub struct UnexpectedEscapeSequence {
report: Report,
error_loc: CodeLoc,
}
#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
#[associated_enum(CompileError)]
#[error(code = "E032", title = "invalid UTF-8")]
#[label("invalid UTF-8 character", error_loc)]
pub struct InvalidUTF8 {
report: Report,
error_loc: CodeLoc,
}
#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
#[associated_enum(CompileError)]
#[error(code = "E033", title = "invalid pattern modifier")]
#[label("{error}", error_loc)]
pub struct InvalidModifier {
report: Report,
error: String,
error_loc: CodeLoc,
}
#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
#[associated_enum(CompileError)]
#[error(code = "E034", title = "potentially slow loop")]
#[label(
"this range can be very large",
loc
)]
pub struct PotentiallySlowLoop {
report: Report,
loc: CodeLoc,
}
#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
#[associated_enum(CompileError)]
#[error(code = "E035", title = "too many patterns in a rule")]
#[label("this rule has more than {max_num_patterns} patterns", error_loc)]
pub struct TooManyPatterns {
report: Report,
max_num_patterns: usize,
error_loc: CodeLoc,
}
#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
#[associated_enum(CompileError)]
#[error(code = "E036", title = "method not allowed in `with` statement")]
#[label("this method is not allowed here", error_loc)]
pub struct MethodNotAllowedInWith {
report: Report,
error_loc: CodeLoc,
}
#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
#[associated_enum(CompileError)]
#[error(code = "E037", title = "metadata `{name}` is not valid")]
#[label(
"{label}",
label_loc
)]
pub struct InvalidMetadata {
report: Report,
name: String,
label_loc: CodeLoc,
label: String,
}
#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
#[associated_enum(CompileError)]
#[error(
code = "E038",
title = "required metadata is missing"
)]
#[label(
"required metadata `{name}` not found",
rule_loc
)]
#[footer(note)]
pub struct MissingMetadata {
report: Report,
rule_loc: CodeLoc,
name: String,
note: Option<String>,
}
#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
#[associated_enum(CompileError)]
#[error(
code = "E039",
title = "rule name does not match regex `{regex}`"
)]
#[label(
"this rule name does not match regex `{regex}`",
rule_loc
)]
pub struct InvalidRuleName {
report: Report,
rule_loc: CodeLoc,
regex: String,
}
#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
#[associated_enum(CompileError)]
#[error(
code = "E040",
title = "tag not in allowed list"
)]
#[label(
"tag `{name}` not in allowed list",
tag_loc
)]
#[footer(note)]
pub struct UnknownTag {
report: Report,
tag_loc: CodeLoc,
name: String,
note: Option<String>,
}
#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
#[associated_enum(CompileError)]
#[error(
code = "E041",
title = "tag does not match regex `{regex}`"
)]
#[label(
"tag `{name}` does not match regex `{regex}`",
tag_loc
)]
pub struct InvalidTag {
report: Report,
tag_loc: CodeLoc,
name: String,
regex: String,
}
#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
#[associated_enum(CompileError)]
#[error(
code = "E042",
title = "error including file"
)]
#[label(
"failed with error: {error}",
include_loc
)]
pub struct IncludeError {
report: Report,
include_loc: CodeLoc,
error: String,
}
#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
#[associated_enum(CompileError)]
#[error(
code = "E043",
title = "include file not found"
)]
#[label(
"`{file_path}` not found in any of the include directories",
include_loc
)]
pub struct IncludeNotFound {
report: Report,
file_path: String,
include_loc: CodeLoc,
}
#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
#[associated_enum(CompileError)]
#[error(
code = "E044",
title = "include statements not allowed"
)]
#[label(
"includes are disabled for this compilation",
include_loc
)]
pub struct IncludeNotAllowed {
report: Report,
include_loc: CodeLoc,
}
#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
#[associated_enum(CompileError)]
#[error(code = "E045", title = "arbitrary regular expression prefix")]
#[label("this prefix can be arbitrarily long and matches all bytes", error_loc)]
pub struct ArbitraryRegexpPrefix {
report: Report,
error_loc: CodeLoc,
}
#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
#[associated_enum(CompileError)]
#[error(code = "E046", title = "circular include dependencies")]
#[label("include statement has circular dependencies", error_loc)]
#[footer(note)]
pub struct CircularIncludes {
report: Report,
error_loc: CodeLoc,
note: Option<String>,
}
#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
#[associated_enum(CompileError)]
#[error(code = "E100", title = "{title}")]
#[label("{error}", error_loc)]
pub struct CustomError {
report: Report,
title: String,
error: String,
error_loc: CodeLoc,
}