diff --git a/src/lib.rs b/src/lib.rs index 944e4d7ec..fceda8044 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -331,7 +331,10 @@ pub enum Level { /// The "error" level. /// /// Designates very serious errors. - Error = 1, // This way these line up with the discriminants for LevelFilter below + // This way these line up with the discriminants for LevelFilter below + // This works because Rust treats field-less enums the same way as C does: + // https://doc.rust-lang.org/reference/items/enumerations.html#custom-discriminant-values-for-field-less-enumerations + Error = 1, /// The "warn" level. /// /// Designates hazardous situations. @@ -1173,6 +1176,12 @@ pub fn set_max_level(level: LevelFilter) { /// [`set_max_level`]: fn.set_max_level.html #[inline(always)] pub fn max_level() -> LevelFilter { + // Since `LevelFilter` is `repr(usize)`, + // this transmute is sound if and only if `MAX_LOG_LEVEL_FILTER` + // is set to a usize that is a valid discriminant for `LevelFilter`. + // Since `MAX_LOG_LEVEL_FILTER` is private, the only time it's set + // is by `set_max_level` above, i.e. by casting a `LevelFilter` to `usize`. + // So any usize stored in `MAX_LOG_LEVEL_FILTER` is a valid discriminant. unsafe { mem::transmute(MAX_LOG_LEVEL_FILTER.load(Ordering::Relaxed)) } } @@ -1257,19 +1266,21 @@ fn set_logger_inner(make_logger: F) -> Result<(), SetLoggerError> where F: FnOnce() -> &'static dyn Log, { - unsafe { - match STATE.compare_and_swap(UNINITIALIZED, INITIALIZING, Ordering::SeqCst) { - UNINITIALIZED => { + match STATE.compare_and_swap(UNINITIALIZED, INITIALIZING, Ordering::SeqCst) { + UNINITIALIZED => { + unsafe { LOGGER = make_logger(); - STATE.store(INITIALIZED, Ordering::SeqCst); - Ok(()) } - INITIALIZING => { - while STATE.load(Ordering::SeqCst) == INITIALIZING {} - Err(SetLoggerError(())) + STATE.store(INITIALIZED, Ordering::SeqCst); + Ok(()) + } + INITIALIZING => { + while STATE.load(Ordering::SeqCst) == INITIALIZING { + std::sync::atomic::spin_loop_hint(); } - _ => Err(SetLoggerError(())), + Err(SetLoggerError(())) } + _ => Err(SetLoggerError(())), } } @@ -1345,13 +1356,11 @@ impl error::Error for ParseLevelError {} /// /// If a logger has not been set, a no-op implementation is returned. pub fn logger() -> &'static dyn Log { - unsafe { - if STATE.load(Ordering::SeqCst) != INITIALIZED { - static NOP: NopLogger = NopLogger; - &NOP - } else { - LOGGER - } + if STATE.load(Ordering::SeqCst) != INITIALIZED { + static NOP: NopLogger = NopLogger; + &NOP + } else { + unsafe { LOGGER } } }