Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 4 additions & 6 deletions lang/rust/avro/src/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -653,6 +653,8 @@ mod tests {
use serde::Serialize;
use uuid::Uuid;

use crate::set_serde_human_readable;

use super::*;

#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)]
Expand Down Expand Up @@ -1230,9 +1232,7 @@ mod tests {
// AVRO-3747: set serde's is_human_readable to false
use serde::de::Deserializer as SerdeDeserializer;

unsafe {
crate::util::SERDE_HUMAN_READABLE = false;
}
set_serde_human_readable(false);

let deser = Deserializer::new(&Value::Null);

Expand All @@ -1246,9 +1246,7 @@ mod tests {
// AVRO-3747: set serde's is_human_readable to true
use serde::de::Deserializer as SerdeDeserializer;

unsafe {
crate::util::SERDE_HUMAN_READABLE = true;
}
set_serde_human_readable(true);

let deser = Deserializer::new(&Value::Null);

Expand Down
10 changes: 4 additions & 6 deletions lang/rust/avro/src/ser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,8 @@ pub fn to_value<S: Serialize>(value: S) -> Result<Value, Error> {

#[cfg(test)]
mod tests {
use crate::set_serde_human_readable;

use super::*;
use pretty_assertions::assert_eq;
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -1007,9 +1009,7 @@ mod tests {
fn avro_3747_human_readable_false() {
use serde::ser::Serializer as SerdeSerializer;

unsafe {
crate::util::SERDE_HUMAN_READABLE = false;
}
set_serde_human_readable(false);

let ser = &mut Serializer {};

Expand All @@ -1020,9 +1020,7 @@ mod tests {
fn avro_3747_human_readable_true() {
use serde::ser::Serializer as SerdeSerializer;

unsafe {
crate::util::SERDE_HUMAN_READABLE = true;
}
set_serde_human_readable(true);

let ser = &mut Serializer {};

Expand Down
47 changes: 14 additions & 33 deletions lang/rust/avro/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,24 @@

use crate::{schema::Documentation, AvroResult, Error};
use serde_json::{Map, Value};
use std::{convert::TryFrom, i64, io::Read, sync::Once};
use std::{
convert::TryFrom,
i64,
io::Read,
sync::atomic::{AtomicBool, AtomicUsize, Ordering},
};

/// Maximum number of bytes that can be allocated when decoding
/// Avro-encoded values. This is a protection against ill-formed
/// data, whose length field might be interpreted as enormous.
/// See max_allocation_bytes to change this limit.
pub const DEFAULT_MAX_ALLOCATION_BYTES: usize = 512 * 1024 * 1024;
static mut MAX_ALLOCATION_BYTES: usize = DEFAULT_MAX_ALLOCATION_BYTES;
static MAX_ALLOCATION_BYTES_ONCE: Once = Once::new();
static MAX_ALLOCATION_BYTES: AtomicUsize = AtomicUsize::new(512 * 1024 * 1024);

/// Whether to set serialization & deserialization traits
/// as `human_readable` or not.
/// See [set_serde_human_readable] to change this value.
pub const DEFAULT_SERDE_HUMAN_READABLE: bool = true;
// crate visible for testing
pub(crate) static mut SERDE_HUMAN_READABLE: bool = DEFAULT_SERDE_HUMAN_READABLE;
static SERDE_HUMAN_READABLE_ONCE: Once = Once::new();
pub(crate) static SERDE_HUMAN_READABLE: AtomicBool = AtomicBool::new(true);

pub trait MapHelper {
fn string(&self, key: &str) -> Option<String>;
Expand Down Expand Up @@ -133,23 +134,13 @@ fn decode_variable<R: Read>(reader: &mut R) -> AvroResult<u64> {
}

/// Set a new maximum number of bytes that can be allocated when decoding data.
/// Once called, the limit cannot be changed.
///
/// **NOTE** This function must be called before decoding **any** data. The
/// library leverages [`std::sync::Once`](https://doc.rust-lang.org/std/sync/struct.Once.html)
/// to set the limit either when calling this method, or when decoding for
/// the first time.
pub fn max_allocation_bytes(num_bytes: usize) -> usize {
unsafe {
MAX_ALLOCATION_BYTES_ONCE.call_once(|| {
MAX_ALLOCATION_BYTES = num_bytes;
});
MAX_ALLOCATION_BYTES
}
MAX_ALLOCATION_BYTES.store(num_bytes, Ordering::Relaxed);
num_bytes
}

pub fn safe_len(len: usize) -> AvroResult<usize> {
let max_bytes = max_allocation_bytes(DEFAULT_MAX_ALLOCATION_BYTES);
let max_bytes = MAX_ALLOCATION_BYTES.load(Ordering::Relaxed);

if len <= max_bytes {
Ok(len)
Expand All @@ -163,23 +154,13 @@ pub fn safe_len(len: usize) -> AvroResult<usize> {

/// Set whether serializing/deserializing is marked as human readable in serde traits.
/// This will adjust the return value of `is_human_readable()` for both.
/// Once called, the value cannot be changed.
///
/// **NOTE** This function must be called before serializing/deserializing **any** data. The
/// library leverages [`std::sync::Once`](https://doc.rust-lang.org/std/sync/struct.Once.html)
/// to set the limit either when calling this method, or when decoding for
/// the first time.
pub fn set_serde_human_readable(human_readable: bool) -> bool {
unsafe {
SERDE_HUMAN_READABLE_ONCE.call_once(|| {
SERDE_HUMAN_READABLE = human_readable;
});
SERDE_HUMAN_READABLE
}
SERDE_HUMAN_READABLE.store(human_readable, Ordering::Relaxed);
human_readable
}

pub(crate) fn is_human_readable() -> bool {
unsafe { SERDE_HUMAN_READABLE }
SERDE_HUMAN_READABLE.load(Ordering::Relaxed)
}

#[cfg(test)]
Expand Down