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 impl From<LevelInput> for LevelFilter { from(l: LevelInput) -> LevelFilter34 fn from(l: LevelInput) -> LevelFilter { 35 match l { 36 LevelInput::Error => LevelFilter::Error, 37 LevelInput::Warn => LevelFilter::Warn, 38 LevelInput::Info => LevelFilter::Info, 39 LevelInput::Debug => LevelFilter::Debug, 40 LevelInput::Trace => LevelFilter::Trace, 41 } 42 } 43 } 44 45 #[derive(Arbitrary, Debug)] 46 pub enum LevelFilterInput { 47 Off, 48 Error, 49 Warn, 50 Info, 51 Debug, 52 Trace, 53 } 54 55 impl From<&LevelFilterInput> for LevelFilter { from(l: &LevelFilterInput) -> LevelFilter56 fn from(l: &LevelFilterInput) -> LevelFilter { 57 match l { 58 LevelFilterInput::Off => LevelFilter::Off, 59 LevelFilterInput::Error => LevelFilter::Error, 60 LevelFilterInput::Warn => LevelFilter::Warn, 61 LevelFilterInput::Info => LevelFilter::Info, 62 LevelFilterInput::Debug => LevelFilter::Debug, 63 LevelFilterInput::Trace => LevelFilter::Trace, 64 } 65 } 66 } 67 68 #[derive(Arbitrary, Copy, Clone, Debug)] 69 pub enum LogIdInput { 70 Main, 71 Radio, 72 Events, 73 System, 74 Crash, 75 } 76 77 impl From<LogIdInput> for LogId { from(l: LogIdInput) -> LogId78 fn from(l: LogIdInput) -> LogId { 79 match l { 80 LogIdInput::Main => LogId::Main, 81 LogIdInput::Radio => LogId::Radio, 82 LogIdInput::Events => LogId::Events, 83 LogIdInput::System => LogId::System, 84 LogIdInput::Crash => LogId::Crash, 85 } 86 } 87 } 88 89 #[derive(Arbitrary, Debug)] 90 struct ConfigInput { 91 log_level: LevelInput, 92 log_id: LogIdInput, 93 filters: Vec<(Option<String>, LevelFilterInput)>, 94 tag: CString, 95 } 96 97 impl ConfigInput { get_filter(&self) -> Filter98 fn get_filter(&self) -> Filter { 99 let mut builder = FilterBuilder::new(); 100 for (name, level) in &self.filters { 101 builder.filter(name.as_deref(), level.into()); 102 } 103 builder.build() 104 } 105 } 106 107 impl From<ConfigInput> for Config { from(config_input: ConfigInput) -> Config108 fn from(config_input: ConfigInput) -> Config { 109 Config::default() 110 .with_filter(config_input.get_filter()) 111 .with_max_level(config_input.log_level.into()) 112 .with_tag(config_input.tag) 113 .with_log_buffer(config_input.log_id.into()) 114 } 115 } 116 117 #[derive(Arbitrary, Debug)] 118 struct RecordInput { 119 log_level: LevelInput, 120 target: String, 121 module_path: Option<String>, 122 file: Option<String>, 123 line: Option<u32>, 124 message: String, 125 } 126 127 #[derive(Arbitrary, Debug)] 128 struct LoggerInput { 129 config_input: ConfigInput, 130 record_input: RecordInput, 131 } 132 133 fuzz_target!(|logger_input: LoggerInput| { 134 let config: Config = logger_input.config_input.into(); 135 let logger = AndroidLogger::new(config); 136 let record_input = &logger_input.record_input; 137 logger.log( 138 &Record::builder() 139 .args(format_args!("{}", record_input.message)) 140 .level(record_input.log_level.into()) 141 .target(&record_input.target) 142 .file(record_input.file.as_deref()) 143 .line(record_input.line) 144 .module_path(record_input.module_path.as_deref()) 145 .build(), 146 ); 147 }); 148