yara_x/compiler/
errors.rs

1#![cfg_attr(any(), rustfmt::skip)]
2#![allow(clippy::duplicated_attributes)]
3
4use std::fmt::{Debug, Display, Formatter};
5use std::io;
6use serde::Serialize;
7
8use thiserror::Error;
9
10use yara_x_macros::ErrorEnum;
11use yara_x_macros::ErrorStruct;
12use yara_x_parser::ast;
13
14use crate::compiler::report::{Level, Report, ReportBuilder, CodeLoc, Label, Footer};
15
16/// Error returned while serializing/deserializing compiled rules.
17#[derive(Error, Debug)]
18pub enum SerializationError {
19    /// The data being deserialized doesn't contain YARA-X serialized rules.
20    #[error("not a YARA-X compiled rules file")]
21    InvalidFormat,
22
23    /// Error occurred while encoding YARA-X rules.
24    #[error("cannot encode YARA-X rules")]
25    EncodeError(#[from] bincode::error::EncodeError),
26
27    /// Error occurred while decoding YARA-X rules.
28    #[error("cannot decode YARA-X rules")]
29    DecodeError(#[from] bincode::error::DecodeError),
30
31    /// I/O error while trying to read or write serialized data.
32    #[error(transparent)]
33    IoError(#[from] io::Error),
34
35    /// Error occurred while deserializing WASM code.
36    #[error("invalid YARA-X compiled rules file")]
37    InvalidWASM(#[from] anyhow::Error),
38}
39
40/// Error returned by [`crate::Compiler::emit_wasm_file`].
41#[derive(Error, Debug)]
42#[error(transparent)]
43#[doc(hidden)]
44pub struct EmitWasmError(#[from] anyhow::Error);
45
46/// Error returned when rule compilation fails.
47#[allow(missing_docs)]
48#[non_exhaustive]
49#[derive(ErrorEnum, Error, Clone, PartialEq, Eq)]
50#[derive(Serialize)]
51#[serde(tag = "type")]
52pub enum CompileError {
53    ArbitraryRegexpPrefix(Box<ArbitraryRegexpPrefix>),
54    AssignmentMismatch(Box<AssignmentMismatch>),
55    CircularIncludes(Box<CircularIncludes>),
56    ConflictingRuleIdentifier(Box<ConflictingRuleIdentifier>),
57    CustomError(Box<CustomError>),
58    DuplicateModifier(Box<DuplicateModifier>),
59    DuplicatePattern(Box<DuplicatePattern>),
60    DuplicateRule(Box<DuplicateRule>),
61    DuplicateTag(Box<DuplicateTag>),
62    EmptyPatternSet(Box<EmptyPatternSet>),
63    EntrypointUnsupported(Box<EntrypointUnsupported>),
64    IncludeError(Box<IncludeError>),
65    IncludeNotAllowed(Box<IncludeNotAllowed>),
66    IncludeNotFound(Box<IncludeNotFound>),
67    InvalidBase64Alphabet(Box<InvalidBase64Alphabet>),
68    InvalidEscapeSequence(Box<InvalidEscapeSequence>),
69    InvalidFloat(Box<InvalidFloat>),
70    InvalidInteger(Box<InvalidInteger>),
71    InvalidMetadata(Box<InvalidMetadata>),
72    InvalidModifier(Box<InvalidModifier>),
73    InvalidModifierCombination(Box<InvalidModifierCombination>),
74    InvalidPattern(Box<InvalidPattern>),
75    InvalidRange(Box<InvalidRange>),
76    InvalidRegexp(Box<InvalidRegexp>),
77    InvalidRegexpModifier(Box<InvalidRegexpModifier>),
78    InvalidRuleName(Box<InvalidRuleName>),
79    InvalidTag(Box<InvalidTag>),
80    InvalidUTF8(Box<InvalidUTF8>),
81    MethodNotAllowedInWith(Box<MethodNotAllowedInWith>),
82    MismatchingTypes(Box<MismatchingTypes>),
83    MissingMetadata(Box<MissingMetadata>),
84    MixedGreediness(Box<MixedGreediness>),
85    NumberOutOfRange(Box<NumberOutOfRange>),
86    PotentiallySlowLoop(Box<PotentiallySlowLoop>),
87    SlowPattern(Box<SlowPattern>),
88    SyntaxError(Box<SyntaxError>),
89    TooManyPatterns(Box<TooManyPatterns>),
90    UnexpectedEscapeSequence(Box<UnexpectedEscapeSequence>),
91    UnexpectedNegativeNumber(Box<UnexpectedNegativeNumber>),
92    UnknownField(Box<UnknownField>),
93    UnknownIdentifier(Box<UnknownIdentifier>),
94    UnknownModule(Box<UnknownModule>),
95    UnknownPattern(Box<UnknownPattern>),
96    UnknownTag(Box<UnknownTag>),
97    UnusedPattern(Box<UnusedPattern>),
98    WrongArguments(Box<WrongArguments>),
99    WrongType(Box<WrongType>),
100}
101
102impl CompileError {
103    pub(crate) fn from(
104        report_builder: &ReportBuilder,
105        err: ast::Error,
106    ) -> Self {
107        match err {
108            ast::Error::SyntaxError { message, span } => {
109                SyntaxError::build(report_builder, message, report_builder.span_to_code_loc(span))
110            }
111            ast::Error::InvalidInteger { message, span } => {
112                InvalidInteger::build(report_builder, message, report_builder.span_to_code_loc(span))
113            }
114            ast::Error::InvalidFloat { message, span } => {
115                InvalidFloat::build(report_builder, message, report_builder.span_to_code_loc(span))
116            }
117            ast::Error::InvalidRegexpModifier { message, span } => {
118                InvalidRegexpModifier::build(
119                    report_builder,
120                    message,
121                    report_builder.span_to_code_loc(span),
122                )
123            }
124            ast::Error::InvalidEscapeSequence { message, span } => {
125                InvalidEscapeSequence::build(
126                    report_builder,
127                    message,
128                    report_builder.span_to_code_loc(span),
129                )
130            }
131            ast::Error::UnexpectedEscapeSequence(span) => {
132                UnexpectedEscapeSequence::build(report_builder, report_builder.span_to_code_loc(span))
133            }
134            ast::Error::InvalidUTF8(span) => {
135                InvalidUTF8::build(report_builder, report_builder.span_to_code_loc(span))
136            }
137        }
138    }
139
140    /// Utility function that receives an array of strings and joins them
141    /// together separated by commas and with "or" before the last one.
142    /// For example, if input is `["s1", "s2", "s3"]` the result is:
143    ///
144    /// ```text
145    /// str1, str2 or str3
146    /// ```
147    ///
148    /// If `quotes` is true, the strings are enclosed in back tilts, like this:
149    ///
150    /// ```text
151    /// `str1`, `str2` or `str3`
152    /// ```
153    ///
154    pub(crate) fn join_with_or<S: ToString>(s: &[S], quotes: bool) -> String {
155        let mut strings = if quotes {
156            s.iter()
157                .map(|s| format!("`{}`", s.to_string()))
158                .collect::<Vec<String>>()
159        } else {
160            s.iter().map(|s| s.to_string()).collect::<Vec<String>>()
161        };
162
163        // Sort alphabetically.
164        strings.sort();
165
166        // Deduplicate repeated items.
167        strings.dedup();
168
169        match strings.len() {
170            1 => strings[0].to_owned(),
171            2 => format!("{} or {}", strings[0], strings[1]),
172            l => {
173                format!(
174                    "{}, or {}",
175                    strings[..l - 1].join(", "),
176                    strings[l - 1]
177                )
178            }
179        }
180    }
181}
182
183/// A syntax error was found in the rule.
184#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
185#[associated_enum(CompileError)]
186#[error(code = "E001", title = "syntax error")]
187#[label("{error}", error_loc)]
188pub struct SyntaxError {
189    report: Report,
190    error: String,
191    error_loc: CodeLoc,
192}
193
194/// Some expression has an unexpected type.
195#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
196#[associated_enum(CompileError)]
197#[error(code = "E002", title = "wrong type")]
198#[label(
199    "expression should be {expected_types}, but it is {actual_type}",
200    error_loc
201)]
202#[footer(help, Level::HELP)]
203pub struct WrongType {
204    report: Report,
205    expected_types: String,
206    actual_type: String,
207    error_loc: CodeLoc,
208    help: Option<String>,
209}
210
211/// Operands have mismatching types.
212#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
213#[associated_enum(CompileError)]
214#[error(code = "E003", title = "mismatching types")]
215#[label("this expression is `{type1}`", type1_loc)]
216#[label("this expression is `{type2}`", type2_loc)]
217pub struct MismatchingTypes {
218    report: Report,
219    type1: String,
220    type2: String,
221    type1_loc: CodeLoc,
222    type2_loc: CodeLoc,
223}
224
225/// Wrong arguments when calling a function.
226#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
227#[associated_enum(CompileError)]
228#[error(code = "E004", title = "wrong arguments")]
229#[label("wrong arguments in this call", error_loc)]
230#[footer(note)]
231pub struct WrongArguments {
232    report: Report,
233    error_loc: CodeLoc,
234    note: Option<String>,
235}
236
237/// Mismatch between number of variables and number of values in a loop
238/// expression.
239#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
240#[associated_enum(CompileError)]
241#[error(code = "E005", title = "assignment mismatch")]
242#[label("this expects {expected_values} value(s)", error_loc)]
243#[label("this produces {actual_values} value(s)", iterable_loc)]
244pub struct AssignmentMismatch {
245    report: Report,
246    expected_values: u8,
247    actual_values: u8,
248    iterable_loc: CodeLoc,
249    error_loc: CodeLoc,
250}
251
252/// Negative number used where positive number was expected.
253#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
254#[associated_enum(CompileError)]
255#[error(code = "E006", title = "unexpected negative number")]
256#[label("this number can not be negative", error_loc)]
257pub struct UnexpectedNegativeNumber {
258    report: Report,
259    error_loc: CodeLoc,
260}
261
262/// A number is out of the allowed range.
263#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
264#[associated_enum(CompileError)]
265#[error(code = "E007", title = "number out of range")]
266#[label("this number is out of the allowed range [{min}-{max}]", error_loc)]
267pub struct NumberOutOfRange {
268    report: Report,
269    min: i64,
270    max: i64,
271    error_loc: CodeLoc,
272}
273
274/// Unknown field or method name.
275#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
276#[associated_enum(CompileError)]
277#[error(code = "E008", title = "unknown field or method `{identifier}`")]
278#[label("this field or method doesn't exist", error_loc)]
279pub struct UnknownField {
280    report: Report,
281    identifier: String,
282    error_loc: CodeLoc,
283}
284
285/// Unknown identifier.
286#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
287#[associated_enum(CompileError)]
288#[error(code = "E009", title = "unknown identifier `{identifier}`")]
289#[label("this identifier has not been declared", identifier_loc)]
290#[footer(note)]
291pub struct UnknownIdentifier {
292    report: Report,
293    identifier: String,
294    identifier_loc: CodeLoc,
295    note: Option<String>,
296}
297
298impl UnknownIdentifier {
299    /// Name of the unknown identifier.
300    #[inline]
301    pub fn identifier(&self) -> &str {
302        self.identifier.as_str()
303    }
304    /// Location of the unknown identifier.
305    pub(crate) fn identifier_location(&self) -> &CodeLoc {
306        &self.identifier_loc
307    }
308}
309
310/// Unknown module.
311#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
312#[associated_enum(CompileError)]
313#[error(code = "E010", title = "unknown module `{identifier}`")]
314#[label("module `{identifier}` not found", error_loc)]
315pub struct UnknownModule {
316    report: Report,
317    identifier: String,
318    error_loc: CodeLoc,
319}
320
321/// Invalid range.
322#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
323#[associated_enum(CompileError)]
324#[error(code = "E011", title = "invalid range")]
325#[label("{error}", error_loc)]
326pub struct InvalidRange {
327    report: Report,
328    error: String,
329    error_loc: CodeLoc,
330}
331
332/// Two rules have the same name.
333#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
334#[associated_enum(CompileError)]
335#[error(code = "E012", title = "duplicate rule `{new_rule}`")]
336#[label(
337    "duplicate declaration of `{new_rule}`",
338    duplicate_rule_loc,
339    Level::ERROR
340)]
341#[label(
342    "`{new_rule}` declared here for the first time",
343    existing_rule_loc,
344    Level::NOTE
345)]
346pub struct DuplicateRule {
347    report: Report,
348    new_rule: String,
349    duplicate_rule_loc: CodeLoc,
350    existing_rule_loc: CodeLoc,
351}
352
353
354/// A rule has the same name as a module or global variable.
355#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
356#[associated_enum(CompileError)]
357#[error(
358    code = "E013",
359    title = "rule `{identifier}` conflicts with an existing identifier"
360)]
361#[label("identifier already in use by a module or global variable", error_loc)]
362pub struct ConflictingRuleIdentifier {
363    report: Report,
364    identifier: String,
365    error_loc: CodeLoc,
366}
367
368/// A regular expression is invalid.
369#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
370#[associated_enum(CompileError)]
371#[error(code = "E014", title = "invalid regular expression")]
372#[label("{error}", error_loc)]
373#[footer(note)]
374pub struct InvalidRegexp {
375    report: Report,
376    error: String,
377    error_loc: CodeLoc,
378    note: Option<String>,
379}
380
381/// A regular expression contains a mixture of greedy and non-greedy quantifiers.
382#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
383#[associated_enum(CompileError)]
384#[error(
385    code = "E015",
386    title = "mixing greedy and non-greedy quantifiers in regular expression"
387)]
388#[label("this is {quantifier1_greediness}", quantifier1_loc)]
389#[label("this is {quantifier2_greediness}", quantifier2_loc)]
390pub struct MixedGreediness {
391    report: Report,
392    quantifier1_greediness: String,
393    quantifier2_greediness: String,
394    quantifier1_loc: CodeLoc,
395    quantifier2_loc: CodeLoc,
396}
397
398/// A set of patterns doesn't contain any patterns.
399#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
400#[associated_enum(CompileError)]
401#[error(code = "E016", title = "no matching patterns")]
402#[label("there's no pattern in this set", error_loc)]
403#[footer(note)]
404pub struct EmptyPatternSet {
405    report: Report,
406    error_loc: CodeLoc,
407    note: Option<String>,
408}
409
410/// The `entrypoint` keyword is not supported.
411#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
412#[associated_enum(CompileError)]
413#[error(code = "E017", title = "`entrypoint` is unsupported")]
414#[label("the `entrypoint` keyword is not supported anymore", error_loc)]
415pub struct EntrypointUnsupported {
416    report: Report,
417    error_loc: CodeLoc,
418}
419
420/// Some pattern may be potentially slow.
421#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
422#[associated_enum(CompileError)]
423#[error(code = "E018", title = "slow pattern")]
424#[label("this pattern may slow down the scan", error_loc)]
425#[footer(note)]
426pub struct SlowPattern {
427    report: Report,
428    error_loc: CodeLoc,
429    note: Option<String>,
430}
431
432/// A pattern has modifiers that can't be used together.
433#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
434#[associated_enum(CompileError)]
435#[error(
436    code = "E019",
437    title = "invalid modifier combination: `{modifier1}` `{modifier2}`"
438)]
439#[label("`{modifier1}` modifier used here", modifier1_loc)]
440#[label("`{modifier2}` modifier used here", modifier2_loc)]
441#[footer(note)]
442pub struct InvalidModifierCombination {
443    report: Report,
444    modifier1: String,
445    modifier2: String,
446    modifier1_loc: CodeLoc,
447    modifier2_loc: CodeLoc,
448    note: Option<String>,
449}
450
451/// A pattern has duplicate modifiers.
452#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
453#[associated_enum(CompileError)]
454#[error(code = "E020", title = "duplicate pattern modifier")]
455#[label("duplicate modifier", error_loc)]
456pub struct DuplicateModifier {
457    report: Report,
458    error_loc: CodeLoc,
459}
460
461/// A rule has duplicate tags.
462#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
463#[associated_enum(CompileError)]
464#[error(code = "E021", title = "duplicate tag `{tag}`")]
465#[label("duplicate tag", error_loc)]
466pub struct DuplicateTag {
467    report: Report,
468    tag: String,
469    error_loc: CodeLoc,
470}
471
472/// A rule defines a pattern that is not used in the condition.
473#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
474#[associated_enum(CompileError)]
475#[error(code = "E022", title = "unused pattern `{pattern_ident}`")]
476#[label("this pattern was not used in the condition", error_loc)]
477pub struct UnusedPattern {
478    report: Report,
479    pattern_ident: String,
480    error_loc: CodeLoc,
481}
482
483/// A rule has two patterns with the same identifier.
484#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
485#[associated_enum(CompileError)]
486#[error(code = "E023", title = "duplicate pattern `{pattern_ident}`")]
487#[label("duplicate declaration of `{pattern_ident}`", error_loc)]
488#[label(
489    "`{pattern_ident}` declared here for the first time",
490    note_loc,
491    Level::NOTE
492)]
493pub struct DuplicatePattern {
494    report: Report,
495    pattern_ident: String,
496    error_loc: CodeLoc,
497    note_loc: CodeLoc,
498}
499
500/// A rule has an invalid pattern.
501#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
502#[associated_enum(CompileError)]
503#[error(code = "E024", title = "invalid pattern `{pattern_ident}`")]
504#[label("{error}", error_loc)]
505#[footer(note)]
506pub struct InvalidPattern {
507    report: Report,
508    pattern_ident: String,
509    error: String,
510    error_loc: CodeLoc,
511    note: Option<String>,
512}
513
514/// Some rule condition uses a pattern that was not defined.
515#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
516#[associated_enum(CompileError)]
517#[error(code = "E025", title = "unknown pattern `{pattern_ident}`")]
518#[label("this pattern is not declared in the `strings` section", error_loc)]
519pub struct UnknownPattern {
520    report: Report,
521    pattern_ident: String,
522    error_loc: CodeLoc,
523}
524
525/// Wrong alphabet for the `base64` or `base64wide` modifiers.
526#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
527#[associated_enum(CompileError)]
528#[error(code = "E026", title = "invalid base64 alphabet")]
529#[label("{error}", error_loc)]
530pub struct InvalidBase64Alphabet {
531    report: Report,
532    error: String,
533    error_loc: CodeLoc,
534}
535
536/// Invalid integer.
537#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
538#[associated_enum(CompileError)]
539#[error(code = "E027", title = "invalid integer")]
540#[label("{error}", error_loc)]
541pub struct InvalidInteger {
542    report: Report,
543    error: String,
544    error_loc: CodeLoc,
545}
546
547/// Invalid float.
548#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
549#[associated_enum(CompileError)]
550#[error(code = "E028", title = "invalid float")]
551#[label("{error}", error_loc)]
552pub struct InvalidFloat {
553    report: Report,
554    error: String,
555    error_loc: CodeLoc,
556}
557
558/// A text pattern contains an invalid escape sequence.
559#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
560#[associated_enum(CompileError)]
561#[error(code = "E029", title = "invalid escape sequence")]
562#[label("{error}", error_loc)]
563pub struct InvalidEscapeSequence {
564    report: Report,
565    error: String,
566    error_loc: CodeLoc,
567}
568
569/// Invalid modifier for a regular expression.
570#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
571#[associated_enum(CompileError)]
572#[error(code = "E030", title = "invalid regexp modifier `{modifier}`")]
573#[label("invalid modifier", error_loc)]
574pub struct InvalidRegexpModifier {
575    report: Report,
576    modifier: String,
577    error_loc: CodeLoc,
578}
579
580/// A string literal contains escaped sequences and it shouldn't.
581#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
582#[associated_enum(CompileError)]
583#[error(code = "E031", title = "unexpected escape sequence")]
584#[label("escape sequences are not allowed in this string", error_loc)]
585pub struct UnexpectedEscapeSequence {
586    report: Report,
587    error_loc: CodeLoc,
588}
589
590
591/// Source code contains invalid UTF-8 characters.
592#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
593#[associated_enum(CompileError)]
594#[error(code = "E032", title = "invalid UTF-8")]
595#[label("invalid UTF-8 character", error_loc)]
596pub struct InvalidUTF8 {
597    report: Report,
598    error_loc: CodeLoc,
599}
600
601/// Some pattern has an invalid modifier.
602#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
603#[associated_enum(CompileError)]
604#[error(code = "E033", title = "invalid pattern modifier")]
605#[label("{error}", error_loc)]
606pub struct InvalidModifier {
607    report: Report,
608    error: String,
609    error_loc: CodeLoc,
610}
611
612/// A rule contains a loop that could be very slow.
613///
614/// This error indicates that a rule contains a `for` loop that may be very
615/// slow because it iterates over a range with an upper bound that depends on
616/// `filesize`. For very large files this may mean hundreds of millions of
617/// iterations.
618///
619/// # Example
620///
621/// ```text
622/// error[E034]: potentially slow loop
623///  --> test.yar:1:34
624///   |
625/// 1 | rule t { condition: for any i in (0..filesize-1) : ( int32(i) == 0xcafebabe ) }
626///   |                                  --------------- this range can be very large
627///   |
628/// ```
629#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
630#[associated_enum(CompileError)]
631#[error(code = "E034", title = "potentially slow loop")]
632#[label(
633"this range can be very large",
634    loc
635)]
636pub struct PotentiallySlowLoop {
637    report: Report,
638    loc: CodeLoc,
639}
640
641/// A rule has too many patterns.
642#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
643#[associated_enum(CompileError)]
644#[error(code = "E035", title = "too many patterns in a rule")]
645#[label("this rule has more than {max_num_patterns} patterns", error_loc)]
646pub struct TooManyPatterns {
647    report: Report,
648    max_num_patterns: usize,
649    error_loc: CodeLoc,
650}
651
652/// A rule has too many patterns.
653#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
654#[associated_enum(CompileError)]
655#[error(code = "E036", title = "method not allowed in `with` statement")]
656#[label("this method is not allowed here", error_loc)]
657pub struct MethodNotAllowedInWith {
658    report: Report,
659    error_loc: CodeLoc,
660}
661
662/// Some metadata entry is invalid. This is only used if the compiler is
663/// configured to check for valid metadata (see: [`crate::linters::Metadata`]).
664///
665/// ## Example
666///
667/// ```text
668/// error[E037]: metadata `author` is not valid
669/// --> test.yar:4:5
670///   |
671/// 4 |     author = 1234
672///   |              ---- `author` must be a string
673///   |
674/// ```
675#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
676#[associated_enum(CompileError)]
677#[error(code = "E037", title = "metadata `{name}` is not valid")]
678#[label(
679    "{label}",
680    label_loc
681)]
682pub struct InvalidMetadata {
683    report: Report,
684    name: String,
685    label_loc: CodeLoc,
686    label: String,
687}
688
689/// Missing metadata. This is only used if the compiler is configured to check
690/// for required metadata (see:  [`crate::linters::Metadata`]).
691///
692/// ## Example
693///
694/// ```text
695/// error[E038]: required metadata is missing
696///  --> test.yar:12:6
697///    |
698/// 12 | rule pants {
699///    |      ----- required metadata "date" not found
700///    |
701/// ```
702#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
703#[associated_enum(CompileError)]
704#[error(
705    code = "E038",
706    title = "required metadata is missing"
707)]
708#[label(
709    "required metadata `{name}` not found",
710    rule_loc
711)]
712#[footer(note)]
713pub struct MissingMetadata {
714    report: Report,
715    rule_loc: CodeLoc,
716    name: String,
717    note: Option<String>,
718}
719
720/// Rule name does not match regex. This is only used if the compiler is
721/// configured to check for it (see: [`crate::linters::RuleName`]).
722///
723/// ## Example
724///
725/// ```text
726/// error[E039]: rule name does not match regex `APT_.*`
727///  --> test.yar:13:6
728///    |
729/// 13 | rule pants {
730///    |      ----- this rule name does not match regex `APT_.*`
731///    |
732/// ```
733#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
734#[associated_enum(CompileError)]
735#[error(
736    code = "E039",
737    title = "rule name does not match regex `{regex}`"
738)]
739#[label(
740    "this rule name does not match regex `{regex}`",
741    rule_loc
742)]
743pub struct InvalidRuleName {
744    report: Report,
745    rule_loc: CodeLoc,
746    regex: String,
747}
748
749/// Unknown tag. This is only used if the compiler is configured to check
750/// for required tags (see:  [`crate::linters::Tags`]).
751///
752/// ## Example
753///
754/// ```text
755/// error[E040]: tag not in allowed list
756///  --> rules/test.yara:1:10
757///   |
758/// 1 | rule a : foo {
759///   |          ^^^ tag `foo` not in allowed list
760///   |
761///   = note: Allowed tags: test, bar
762/// ```
763#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
764#[associated_enum(CompileError)]
765#[error(
766    code = "E040",
767    title = "tag not in allowed list"
768)]
769#[label(
770    "tag `{name}` not in allowed list",
771    tag_loc
772)]
773#[footer(note)]
774pub struct UnknownTag {
775    report: Report,
776    tag_loc: CodeLoc,
777    name: String,
778    note: Option<String>,
779}
780
781/// Tag does not match regex. This is only used if the compiler is configured to
782/// check for it (see: [`crate::linters::Tags`]).
783///
784/// ## Example
785///
786/// ```text
787/// error[E041]: tag does not match regex `bar`
788///  --> rules/test.yara:1:10
789///   |
790/// 1 | rule a : foo {
791///   |          ^^^ tag `foo` does not match regex `bar`
792///   |
793/// ```
794#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
795#[associated_enum(CompileError)]
796#[error(
797    code = "E041",
798    title = "tag does not match regex `{regex}`"
799)]
800#[label(
801    "tag `{name}` does not match regex `{regex}`",
802    tag_loc
803)]
804pub struct InvalidTag {
805    report: Report,
806    tag_loc: CodeLoc,
807    name: String,
808    regex: String,
809}
810
811/// An error occurred while including a file.
812///
813/// ## Example
814///
815/// ```text
816/// error[E042]: error including file
817///  --> line:1:1
818///   |
819/// 1 | include "unknown"
820///   | ^^^^^^^^^^^^^^^^^ failed with error: Permission denied (os error 13)
821///   |
822/// ```
823#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
824#[associated_enum(CompileError)]
825#[error(
826    code = "E042",
827    title = "error including file"
828)]
829#[label(
830    "failed with error: {error}",
831    include_loc
832)]
833pub struct IncludeError {
834    report: Report,
835    include_loc: CodeLoc,
836    error: String,
837}
838
839/// An included file was not found.
840///
841/// ## Example
842///
843/// ```text
844/// error[E042]: include file not found
845///  --> line:1:1
846///   |
847/// 1 | include "unknown"
848///   | ^^^^^^^^^^^^^^^^^ `unknown` not found in any of the include directories
849///   |
850/// ```
851#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
852#[associated_enum(CompileError)]
853#[error(
854    code = "E043",
855    title = "include file not found"
856)]
857#[label(
858    "`{file_path}` not found in any of the include directories",
859    include_loc
860)]
861pub struct IncludeNotFound {
862    report: Report,
863    file_path: String,
864    include_loc: CodeLoc,
865}
866
867/// An include statement was used, but includes are disabled
868///
869/// # Example
870///
871/// ```text
872/// error[E044]: include statements not allowed
873///  --> line:1:1
874///
875/// 1 | include "some_file"
876///   | ^^^^^^^^^^^^^^^^^^^ includes are disabled for this compilation
877///   |
878/// ```
879#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
880#[associated_enum(CompileError)]
881#[error(
882    code = "E044",
883    title = "include statements not allowed"
884)]
885#[label(
886    "includes are disabled for this compilation",
887    include_loc
888)]
889pub struct IncludeNotAllowed {
890    report: Report,
891    include_loc: CodeLoc,
892}
893
894/// Indicates that a regular expression has a prefix that can be arbitrarily
895/// long and matches any sequence of bytes.
896///
897/// # Example
898///
899/// ```text
900/// error[E045]: arbitrary regular expression prefix  
901///  --> line:3:11  
902///   |  
903/// 3 |     $a = /.*foo/s  
904///   |           ^^ this prefix can be arbitrarily long and matches all bytes  
905///   |
906/// ```  
907///
908/// Regular expressions with such prefixes are problematic because YARA will
909/// report a match at every file offset from the start of the file up to where
910/// the rest of the pattern matches. In most cases, this prefix can be removed
911/// without affecting the rule's semantics.
912#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
913#[associated_enum(CompileError)]
914#[error(code = "E045", title = "arbitrary regular expression prefix")]
915#[label("this prefix can be arbitrarily long and matches all bytes", error_loc)]
916pub struct ArbitraryRegexpPrefix {
917    report: Report,
918    error_loc: CodeLoc,
919}
920
921/// Include statements have circular dependencies.
922#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
923#[associated_enum(CompileError)]
924#[error(code = "E046", title = "circular include dependencies")]
925#[label("include statement has circular dependencies", error_loc)]
926#[footer(note)]
927pub struct CircularIncludes {
928    report: Report,
929    error_loc: CodeLoc,
930    note: Option<String>,
931}
932
933/// A custom error has occurred.
934#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
935#[associated_enum(CompileError)]
936#[error(code = "E100", title = "{title}")]
937#[label("{error}", error_loc)]
938pub struct CustomError {
939    report: Report,
940    title: String,
941    error: String,
942    error_loc: CodeLoc,
943}