Rust fix compilation for no_std targets #2 (#7553)

* Fix nightly no_std

* Fix nightly no_std
This commit is contained in:
Dan Lapid
2022-10-19 16:14:41 +03:00
committed by GitHub
parent 0edb275285
commit 5792623df4
11 changed files with 187 additions and 35 deletions

View File

@@ -12,14 +12,13 @@ categories = ["encoding", "data-structures", "memory-management"]
rust = "1.51"
[features]
default = ["thiserror"]
no_std = ["core2", "thiserror_core2"]
default = ["std"]
std = []
serialize = ["serde"]
[dependencies]
bitflags = "1.2.1"
serde = { version = "1.0", optional = true }
thiserror = { version = "1.0.30", optional = true }
core2 = { version = "0.4.0", optional = true }
# This version is compliant with mainline 1.0.30
thiserror_core2 = { version = "2.0.0", default-features = false, optional = true }
[build-dependencies]
rustc_version = "0.4.0"

12
rust/flatbuffers/build.rs Normal file
View File

@@ -0,0 +1,12 @@
use rustc_version::{version_meta, Channel};
fn main() {
let version_meta = version_meta().unwrap();
// To use nightly features we declare this and then we can use
// #[cfg(nightly)]
// for nightly only features
if version_meta.channel == Channel::Nightly {
println!("cargo:rustc-cfg=nightly")
}
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
#[cfg(feature = "no_std")]
#[cfg(not(feature = "std"))]
use alloc::{vec, vec::Vec};
use core::cmp::max;
use core::iter::{DoubleEndedIterator, ExactSizeIterator};

View File

@@ -28,9 +28,10 @@
//! At this time, to generate Rust code, you will need the latest `master` version of `flatc`, available from here: <https://github.com/google/flatbuffers>
//! (On OSX, you can install FlatBuffers from `HEAD` with the Homebrew package manager.)
#![cfg_attr(feature = "no_std", no_std)]
#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(all(nightly, not(feature = "std")), feature(error_in_core))]
#[cfg(feature = "no_std")]
#[cfg(not(feature = "std"))]
extern crate alloc;
mod array;

View File

@@ -1,14 +1,14 @@
use crate::follow::Follow;
use crate::{ForwardsUOffset, SOffsetT, SkipSizePrefix, UOffsetT, VOffsetT, Vector, SIZE_UOFFSET};
#[cfg(feature = "no_std")]
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
use core::ops::Range;
use core::option::Option;
#[cfg(not(feature = "no_std"))]
use thiserror::Error;
#[cfg(feature = "no_std")]
use thiserror_core2::Error;
#[cfg(all(nightly, not(feature = "std")))]
use core::error::Error;
#[cfg(feature = "std")]
use std::error::Error;
/// Traces the location of data errors. Not populated for Dos detecting errors.
/// Useful for MissingRequiredField and Utf8Error in particular, though
@@ -41,64 +41,138 @@ impl core::convert::AsRef<[ErrorTraceDetail]> for ErrorTrace {
/// Describes how a flatuffer is invalid and, for data errors, roughly where. No extra tracing
/// information is given for DoS detecting errors since it will probably be a lot.
#[derive(Clone, Error, Debug, PartialEq, Eq)]
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum InvalidFlatbuffer {
#[error("Missing required field `{required}`.\n{error_trace}")]
MissingRequiredField {
required: &'static str,
error_trace: ErrorTrace,
},
#[error(
"Union exactly one of union discriminant (`{field_type}`) and value \
(`{field}`) are present.\n{error_trace}"
)]
InconsistentUnion {
field: &'static str,
field_type: &'static str,
error_trace: ErrorTrace,
},
#[error("Utf8 error for string in {range:?}: {error}\n{error_trace}")]
Utf8Error {
#[source]
error: core::str::Utf8Error,
range: Range<usize>,
error_trace: ErrorTrace,
},
#[error("String in range [{}, {}) is missing its null terminator.\n{error_trace}",
range.start, range.end)]
MissingNullTerminator {
range: Range<usize>,
error_trace: ErrorTrace,
},
#[error("Type `{unaligned_type}` at position {position} is unaligned.\n{error_trace}")]
Unaligned {
position: usize,
unaligned_type: &'static str,
error_trace: ErrorTrace,
},
#[error("Range [{}, {}) is out of bounds.\n{error_trace}", range.start, range.end)]
RangeOutOfBounds {
range: Range<usize>,
error_trace: ErrorTrace,
},
#[error(
"Signed offset at position {position} has value {soffset} which points out of bounds.\
\n{error_trace}"
)]
SignedOffsetOutOfBounds {
soffset: SOffsetT,
position: usize,
error_trace: ErrorTrace,
},
// Dos detecting errors. These do not get error traces since it will probably be very large.
#[error("Too many tables.")]
TooManyTables,
#[error("Apparent size too large.")]
ApparentSizeTooLarge,
#[error("Nested table depth limit reached.")]
DepthLimitReached,
}
#[cfg(any(nightly, feature = "std"))]
impl Error for InvalidFlatbuffer {
fn source(&self) -> Option<&(dyn Error + 'static)> {
if let InvalidFlatbuffer::Utf8Error { error: source, .. } = self {
Some(source)
} else {
None
}
}
}
impl core::fmt::Display for InvalidFlatbuffer {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
match self {
InvalidFlatbuffer::MissingRequiredField {
required,
error_trace,
} => {
writeln!(f, "Missing required field `{}`.\n{}", required, error_trace)?;
}
InvalidFlatbuffer::InconsistentUnion {
field,
field_type,
error_trace,
} => {
writeln!(
f,
"Exactly one of union discriminant (`{}`) and value (`{}`) are present.\n{}",
field_type, field, error_trace
)?;
}
InvalidFlatbuffer::Utf8Error {
error,
range,
error_trace,
} => {
writeln!(
f,
"Utf8 error for string in {:?}: {}\n{}",
range, error, error_trace
)?;
}
InvalidFlatbuffer::MissingNullTerminator { range, error_trace } => {
writeln!(
f,
"String in range [{}, {}) is missing its null terminator.\n{}",
range.start, range.end, error_trace
)?;
}
InvalidFlatbuffer::Unaligned {
position,
unaligned_type,
error_trace,
} => {
writeln!(
f,
"Type `{}` at position {} is unaligned.\n{}",
unaligned_type, position, error_trace
)?;
}
InvalidFlatbuffer::RangeOutOfBounds { range, error_trace } => {
writeln!(
f,
"Range [{}, {}) is out of bounds.\n{}",
range.start, range.end, error_trace
)?;
}
InvalidFlatbuffer::SignedOffsetOutOfBounds {
soffset,
position,
error_trace,
} => {
writeln!(
f,
"Signed offset at position {} has value {} which points out of bounds.\n{}",
position, soffset, error_trace
)?;
}
InvalidFlatbuffer::TooManyTables {} => {
writeln!(f, "Too many tables.")?;
}
InvalidFlatbuffer::ApparentSizeTooLarge {} => {
writeln!(f, "Apparent size too large.")?;
}
InvalidFlatbuffer::DepthLimitReached {} => {
writeln!(f, "Nested table depth limit reached.")?;
}
}
Ok(())
}
}
impl core::fmt::Display for ErrorTrace {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
use ErrorTraceDetail::*;

View File

@@ -21,3 +21,10 @@ cargo run --bin=flatbuffers_alloc_check || exit /b 1
cargo run --bin=flexbuffers_alloc_check || exit /b 1
cargo run --bin=monster_example || exit /b 1
cd ..
cd rust_no_std_compilation_test
rustup install nightly
rustup component add rust-src --toolchain nightly
rustup target add thumbv7m-none-eabi
cargo build || exit /b 1
cd ..

View File

@@ -35,11 +35,18 @@ cd ./rust_serialize_test
cargo run $TARGET_FLAG -- --quiet
check_test_result "Rust serde tests"
cd ../rust_no_std_compilation_test
rustup install nightly
rustup component add rust-src --toolchain nightly
rustup target add thumbv7m-none-eabi
cargo +nightly build
check_test_result "Rust flatbuffers test no_std compilation"
cd ../rust_usage_test
cargo test $TARGET_FLAG -- --quiet
check_test_result "Rust tests"
cargo test $TARGET_FLAG --no-default-features --features no_std -- --quiet
cargo test $TARGET_FLAG --no-default-features -- --quiet
check_test_result "Rust tests (no_std)"
cargo run $TARGET_FLAG --bin=flatbuffers_alloc_check

View File

@@ -0,0 +1,5 @@
[build]
target = "thumbv7m-none-eabi"
[unstable]
build-std = ["core", "alloc"]

View File

@@ -0,0 +1,13 @@
[package]
name = "rust_test_no_std_compilation"
version = "0.1.0"
edition = "2021"
[dependencies]
flatbuffers = { path = "../../rust/flatbuffers", default-features = false }
[profile.dev]
panic = "abort"
[profile.release]
panic = "abort"

View File

@@ -0,0 +1,34 @@
#![no_std]
#![no_main]
#![feature(default_alloc_error_handler)]
// Include flatbuffers purely to check that it compiles in a no_std binary
#[allow(unused_imports)]
use flatbuffers;
// The rest is just no_std boilerplate
use core::alloc::{GlobalAlloc, Layout};
struct NullAllocator;
unsafe impl GlobalAlloc for NullAllocator {
unsafe fn alloc(&self, _lt: Layout) -> *mut u8 {
core::ptr::null_mut()
}
unsafe fn dealloc(&self, _ptr: *mut u8, _lt: Layout) {
panic!("won't deallocate: we never allocated!");
}
}
#[global_allocator]
static A: NullAllocator = NullAllocator;
#[panic_handler]
fn panic(_info: &core::panic::PanicInfo) -> ! {
loop {}
}
#[no_mangle]
pub extern "C" fn main(_argc: i32, _argv: *const *const u8) -> i32 {
0
}

View File

@@ -16,7 +16,7 @@ libc_alloc = { version = "1.0.3", optional = true }
[features]
default = ["flatbuffers/default"]
no_std = ["flatbuffers/no_std", "libc_alloc"]
no_std = ["libc_alloc"]
[[bin]]
name = "monster_example"