1 #![no_main] 2 #![allow(missing_docs)] 3 4 use android_logger::{AndroidLogger, Config, Filter, FilterBuilder, LogId}; 5 use libfuzzer_sys::arbitrary::Arbitrary; 6 use libfuzzer_sys::fuzz_target; 7 use log::{Level, LevelFilter, Log, Record}; 8 use std::ffi::CString; 9 10 // TODO: Remove once Level and LevelInput Arbitrary derivations are upstreamed. 11 // https://github.com/rust-lang/log/issues/530 12 #[derive(Arbitrary, Copy, Clone, Debug)] 13 pub enum LevelInput { 14 Error, 15 Warn, 16 Info, 17 Debug, 18 Trace, 19 } 20 21 impl From<LevelInput> for Level { from(l: LevelInput) -> Level22 fn from(l: LevelInput) -> Level { 23 match l { 24 LevelInput::Error => Level::Error, 25 LevelInput::Warn => Level::Warn, 26 LevelInput::Info => Level::Info, 27 LevelInput::Debug => Level::Debug, 28 LevelInput::Trace => Level::Trace, 29 } 30 } 31 } 32 33 #[derive(Arbitrary, Debug)] 34 pub enum LevelFilterInput { 35 Off, 36 Error, 37 Warn, 38 Info, 39 Debug, 40 Trace, 41 } 42 43 impl From<&LevelFilterInput> for LevelFilter { from(l: &LevelFilterInput) -> LevelFilter44 fn from(l: &LevelFilterInput) -> LevelFilter { 45 match l { 46 LevelFilterInput::Off => LevelFilter::Off, 47 LevelFilterInput::Error => LevelFilter::Error, 48 LevelFilterInput::Warn => LevelFilter::Warn, 49 LevelFilterInput::Info => LevelFilter::Info, 50 LevelFilterInput::Debug => LevelFilter::Debug, 51 LevelFilterInput::Trace => LevelFilter::Trace, 52 } 53 } 54 } 55 56 #[derive(Arbitrary, Copy, Clone, Debug)] 57 pub enum LogIdInput { 58 Main, 59 Radio, 60 Events, 61 System, 62 Crash, 63 } 64 65 impl From<LogIdInput> for LogId { from(l: LogIdInput) -> LogId66 fn from(l: LogIdInput) -> LogId { 67 match l { 68 LogIdInput::Main => LogId::Main, 69 LogIdInput::Radio => LogId::Radio, 70 LogIdInput::Events => LogId::Events, 71 LogIdInput::System => LogId::System, 72 LogIdInput::Crash => LogId::Crash, 73 } 74 } 75 } 76 77 #[derive(Arbitrary, Debug)] 78 struct ConfigInput { 79 log_level: LevelInput, 80 log_id: LogIdInput, 81 filters: Vec<(Option<String>, LevelFilterInput)>, 82 tag: CString, 83 } 84 85 impl ConfigInput { get_filter(&self) -> Filter86 fn get_filter(&self) -> Filter { 87 let mut builder = FilterBuilder::new(); 88 for (name, level) in &self.filters { 89 builder.filter(name.as_deref(), level.into()); 90 } 91 builder.build() 92 } 93 } 94 95 impl From<ConfigInput> for Config { from(config_input: ConfigInput) -> Config96 fn from(config_input: ConfigInput) -> Config { 97 Config::default() 98 .with_filter(config_input.get_filter()) 99 .with_min_level(config_input.log_level.into()) 100 .with_tag(config_input.tag) 101 .with_log_id(config_input.log_id.into()) 102 } 103 } 104 105 #[derive(Arbitrary, Debug)] 106 struct RecordInput { 107 log_level: LevelInput, 108 target: String, 109 module_path: Option<String>, 110 file: Option<String>, 111 line: Option<u32>, 112 message: String, 113 } 114 115 #[derive(Arbitrary, Debug)] 116 struct LoggerInput { 117 config_input: ConfigInput, 118 record_input: RecordInput, 119 } 120 121 fuzz_target!(|logger_input: LoggerInput| { 122 let config: Config = logger_input.config_input.into(); 123 let logger = AndroidLogger::new(config); 124 let record_input = &logger_input.record_input; 125 logger.log( 126 &Record::builder() 127 .args(format_args!("{}", record_input.message)) 128 .level(record_input.log_level.into()) 129 .target(&record_input.target) 130 .file(record_input.file.as_deref()) 131 .line(record_input.line) 132 .module_path(record_input.module_path.as_deref()) 133 .build(), 134 ); 135 }); 136