Skip to content

Commit 7a3aeef

Browse files
authored
Add read-core feature gate (#596)
1 parent 80010ee commit 7a3aeef

13 files changed

Lines changed: 110 additions & 34 deletions

File tree

.github/workflows/rust.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,8 @@ jobs:
103103
steps:
104104
- uses: actions/checkout@v2
105105
- run: cargo test --no-default-features
106+
# Ensure gimli can be built without alloc.
107+
- run: cargo check --no-default-features --features read-core
106108
- run: cargo test --no-default-features --features read
107109
- run: cargo test --no-default-features --features read,fallible-iterator
108110
- run: cargo test --no-default-features --features read,std

Cargo.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,9 @@ test-assembler = "0.1.3"
3838
typed-arena = "2"
3939

4040
[features]
41-
read = []
42-
endian-reader = ["stable_deref_trait"]
41+
read-core = []
42+
read = ["read-core"]
43+
endian-reader = ["read", "stable_deref_trait"]
4344
write = ["indexmap"]
4445
std = ["fallible-iterator/std", "stable_deref_trait/std"]
4546
default = ["read", "write", "std", "fallible-iterator", "endian-reader"]

src/constants.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,14 @@ macro_rules! dw {
8181
if let Some(s) = self.static_string() {
8282
f.pad(s)
8383
} else {
84-
f.pad(&format!("Unknown {}: {}",
85-
stringify!($struct_name),
86-
self.0))
84+
#[cfg(feature = "read")]
85+
{
86+
f.pad(&format!("Unknown {}: {}", stringify!($struct_name), self.0))
87+
}
88+
#[cfg(not(feature = "read"))]
89+
{
90+
write!(f, "Unknown {}: {}", stringify!($struct_name), self.0)
91+
}
8792
}
8893
}
8994
}

src/leb128.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
//! ```
4646
4747
const CONTINUATION_BIT: u8 = 1 << 7;
48-
#[cfg(feature = "read")]
48+
#[cfg(feature = "read-core")]
4949
const SIGN_BIT: u8 = 1 << 6;
5050

5151
#[inline]
@@ -62,7 +62,7 @@ fn low_bits_of_u64(val: u64) -> u8 {
6262

6363
/// A module for reading signed and unsigned integers that have been LEB128
6464
/// encoded.
65-
#[cfg(feature = "read")]
65+
#[cfg(feature = "read-core")]
6666
pub mod read {
6767
use super::{low_bits_of_byte, CONTINUATION_BIT, SIGN_BIT};
6868
use crate::read::{Error, Reader, Result};

src/lib.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#![no_std]
3838

3939
#[allow(unused_imports)]
40+
#[cfg(any(feature = "read", feature = "write"))]
4041
#[macro_use]
4142
extern crate alloc;
4243

@@ -62,10 +63,10 @@ pub use crate::endianity::{BigEndian, Endianity, LittleEndian, NativeEndian, Run
6263

6364
pub mod leb128;
6465

65-
#[cfg(feature = "read")]
66+
#[cfg(feature = "read-core")]
6667
pub mod read;
6768
// For backwards compat.
68-
#[cfg(feature = "read")]
69+
#[cfg(feature = "read-core")]
6970
pub use crate::read::*;
7071

7172
#[cfg(feature = "write")]

src/read/cfi.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#[cfg(feature = "read")]
12
use alloc::vec::Vec;
23

34
use core::cmp::{Ord, Ordering};
@@ -1738,8 +1739,13 @@ impl<R: Reader> FrameDescriptionEntry<R> {
17381739

17391740
/// Specification of what storage should be used for [`UnwindContext`].
17401741
///
1741-
/// Normally you would only need to use [`StoreOnHeap`], which places the stack
1742-
/// on the heap using [`Vec`]. This is the default storage type parameter for [`UnwindContext`].
1742+
#[cfg_attr(
1743+
feature = "read",
1744+
doc = "
1745+
Normally you would only need to use [`StoreOnHeap`], which places the stack
1746+
on the heap using [`Vec`]. This is the default storage type parameter for [`UnwindContext`].
1747+
"
1748+
)]
17431749
///
17441750
/// If you need to avoid [`UnwindContext`] from allocating memory, e.g. for signal safety,
17451751
/// you can provide you own storage specification:
@@ -1780,8 +1786,10 @@ pub trait UnwindContextStorage<R: Reader>: Sized {
17801786
type Stack: ArrayLike<Item = UnwindTableRow<R, Self>>;
17811787
}
17821788

1789+
#[cfg(feature = "read")]
17831790
const MAX_RULES: usize = 192;
17841791

1792+
#[cfg(feature = "read")]
17851793
impl<R: Reader> UnwindContextStorage<R> for StoreOnHeap {
17861794
type Rules = [(Register, RegisterRule<R>); MAX_RULES];
17871795
type Stack = Vec<UnwindTableRow<R, Self>>;
@@ -1849,6 +1857,7 @@ impl<R: Reader, A: UnwindContextStorage<R>> Default for UnwindContext<R, A> {
18491857
}
18501858
}
18511859

1860+
#[cfg(feature = "read")]
18521861
impl<R: Reader> UnwindContext<R> {
18531862
/// Construct a new call frame unwinding context.
18541863
pub fn new() -> Self {

src/read/endian_slice.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
//! Working with byte slices that have an associated endianity.
22
3+
#[cfg(feature = "read")]
34
use alloc::borrow::Cow;
5+
#[cfg(feature = "read")]
46
use alloc::string::String;
57
use core::ops::{Deref, Index, Range, RangeFrom, RangeTo};
68
use core::str;
@@ -82,6 +84,7 @@ where
8284

8385
/// Converts the slice to a string, including invalid characters,
8486
/// using `String::from_utf8_lossy`.
87+
#[cfg(feature = "read")]
8588
#[inline]
8689
pub fn to_string_lossy(&self) -> Cow<'input, str> {
8790
String::from_utf8_lossy(self.slice)
@@ -284,11 +287,18 @@ where
284287
Ok(EndianSlice::new(slice, self.endian))
285288
}
286289

290+
#[cfg(not(feature = "read"))]
291+
fn cannot_implement() -> super::reader::seal_if_no_alloc::Sealed {
292+
super::reader::seal_if_no_alloc::Sealed
293+
}
294+
295+
#[cfg(feature = "read")]
287296
#[inline]
288297
fn to_slice(&self) -> Result<Cow<[u8]>> {
289298
Ok(self.slice.into())
290299
}
291300

301+
#[cfg(feature = "read")]
292302
#[inline]
293303
fn to_string(&self) -> Result<Cow<str>> {
294304
match str::from_utf8(self.slice) {
@@ -297,6 +307,7 @@ where
297307
}
298308
}
299309

310+
#[cfg(feature = "read")]
300311
#[inline]
301312
fn to_string_lossy(&self) -> Result<Cow<str>> {
302313
Ok(String::from_utf8_lossy(self.slice))

src/read/mod.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,9 @@ pub use self::addr::*;
186186
mod cfi;
187187
pub use self::cfi::*;
188188

189+
#[cfg(feature = "read")]
189190
mod dwarf;
191+
#[cfg(feature = "read")]
190192
pub use self::dwarf::*;
191193

192194
mod endian_slice;
@@ -200,7 +202,9 @@ pub use self::endian_reader::*;
200202
mod reader;
201203
pub use self::reader::*;
202204

205+
#[cfg(feature = "read")]
203206
mod abbrev;
207+
#[cfg(feature = "read")]
204208
pub use self::abbrev::*;
205209

206210
mod aranges;
@@ -209,23 +213,30 @@ pub use self::aranges::*;
209213
mod index;
210214
pub use self::index::*;
211215

216+
#[cfg(feature = "read")]
212217
mod line;
218+
#[cfg(feature = "read")]
213219
pub use self::line::*;
214220

215221
mod lists;
216222

217223
mod loclists;
218224
pub use self::loclists::*;
219225

226+
#[cfg(feature = "read")]
220227
mod lookup;
221228

222229
mod op;
223230
pub use self::op::*;
224231

232+
#[cfg(feature = "read")]
225233
mod pubnames;
234+
#[cfg(feature = "read")]
226235
pub use self::pubnames::*;
227236

237+
#[cfg(feature = "read")]
228238
mod pubtypes;
239+
#[cfg(feature = "read")]
229240
pub use self::pubtypes::*;
230241

231242
mod rnglists;
@@ -234,7 +245,13 @@ pub use self::rnglists::*;
234245
mod str;
235246
pub use self::str::*;
236247

248+
/// An offset into the current compilation or type unit.
249+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash)]
250+
pub struct UnitOffset<T = usize>(pub T);
251+
252+
#[cfg(feature = "read")]
237253
mod unit;
254+
#[cfg(feature = "read")]
238255
pub use self::unit::*;
239256

240257
mod value;

src/read/op.rs

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//! Functions for parsing and evaluating DWARF expressions.
22
3+
#[cfg(feature = "read")]
34
use alloc::vec::Vec;
45
use core::mem;
56

@@ -938,6 +939,7 @@ impl<R: Reader> Expression<R> {
938939
/// let mut eval = expression.evaluation(unit.encoding());
939940
/// let mut result = eval.evaluate().unwrap();
940941
/// ```
942+
#[cfg(feature = "read")]
941943
#[inline]
942944
pub fn evaluation(self, encoding: Encoding) -> Evaluation<R> {
943945
Evaluation::new(self.0, encoding)
@@ -982,8 +984,13 @@ impl<R: Reader> OperationIter<R> {
982984

983985
/// Specification of what storage should be used for [`Evaluation`].
984986
///
985-
/// Normally you would only need to use [`StoreOnHeap`], which places the stacks and the results
986-
/// on the heap using [`Vec`]. This is the default storage type parameter for [`Evaluation`].
987+
#[cfg_attr(
988+
feature = "read",
989+
doc = "
990+
Normally you would only need to use [`StoreOnHeap`], which places the stacks and the results
991+
on the heap using [`Vec`]. This is the default storage type parameter for [`Evaluation`].
992+
"
993+
)]
987994
///
988995
/// If you need to avoid [`Evaluation`] from allocating memory, e.g. for signal safety,
989996
/// you can provide you own storage specification:
@@ -1030,6 +1037,7 @@ pub trait EvaluationStorage<R: Reader> {
10301037
type Result: ArrayLike<Item = Piece<R>>;
10311038
}
10321039

1040+
#[cfg(feature = "read")]
10331041
impl<R: Reader> EvaluationStorage<R> for StoreOnHeap {
10341042
type Stack = Vec<Value>;
10351043
type ExpressionStack = Vec<(R, R)>;
@@ -1108,6 +1116,7 @@ pub struct Evaluation<R: Reader, S: EvaluationStorage<R> = StoreOnHeap> {
11081116
result: ArrayVec<S::Result>,
11091117
}
11101118

1119+
#[cfg(feature = "read")]
11111120
impl<R: Reader> Evaluation<R> {
11121121
/// Create a new DWARF expression evaluator.
11131122
///
@@ -1116,6 +1125,19 @@ impl<R: Reader> Evaluation<R> {
11161125
pub fn new(bytecode: R, encoding: Encoding) -> Self {
11171126
Self::new_in(bytecode, encoding)
11181127
}
1128+
1129+
/// Get the result of this `Evaluation`.
1130+
///
1131+
/// # Panics
1132+
/// Panics if this `Evaluation` has not been driven to completion.
1133+
pub fn result(self) -> Vec<Piece<R>> {
1134+
match self.state {
1135+
EvaluationState::Complete => self.result.into_vec(),
1136+
_ => {
1137+
panic!("Called `Evaluation::result` on an `Evaluation` that has not been completed")
1138+
}
1139+
}
1140+
}
11191141
}
11201142

11211143
impl<R: Reader, S: EvaluationStorage<R>> Evaluation<R, S> {
@@ -1956,21 +1978,6 @@ impl<R: Reader, S: EvaluationStorage<R>> Evaluation<R, S> {
19561978
}
19571979
}
19581980

1959-
impl<R: Reader> Evaluation<R, StoreOnHeap> {
1960-
/// Get the result of this `Evaluation`.
1961-
///
1962-
/// # Panics
1963-
/// Panics if this `Evaluation` has not been driven to completion.
1964-
pub fn result(self) -> Vec<Piece<R>> {
1965-
match self.state {
1966-
EvaluationState::Complete => self.result.into_vec(),
1967-
_ => {
1968-
panic!("Called `Evaluation::result` on an `Evaluation` that has not been completed")
1969-
}
1970-
}
1971-
}
1972-
}
1973-
19741981
#[cfg(test)]
19751982
// Tests require leb128::write.
19761983
#[cfg(feature = "write")]

src/read/reader.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#[cfg(feature = "read")]
12
use alloc::borrow::Cow;
23
use core::convert::TryInto;
34
use core::fmt::Debug;
@@ -186,6 +187,12 @@ impl ReaderOffset for usize {
186187
}
187188
}
188189

190+
#[cfg(not(feature = "read"))]
191+
pub(crate) mod seal_if_no_alloc {
192+
#[derive(Debug)]
193+
pub struct Sealed;
194+
}
195+
189196
/// A trait for reading the data from a DWARF section.
190197
///
191198
/// All read operations advance the section offset of the reader
@@ -251,12 +258,22 @@ pub trait Reader: Debug + Clone {
251258
/// `len` bytes, and `self` is advanced so that it reads the remainder.
252259
fn split(&mut self, len: Self::Offset) -> Result<Self>;
253260

261+
/// This trait cannot be implemented if "read" feature is not enabled.
262+
///
263+
/// `Reader` trait has a few methods that depend on `alloc` crate.
264+
/// Disallowing `Reader` trait implementation prevents a crate that only depends on
265+
/// "read-core" from being broken if another crate depending on `gimli` enables
266+
/// "read" feature.
267+
#[cfg(not(feature = "read"))]
268+
fn cannot_implement() -> seal_if_no_alloc::Sealed;
269+
254270
/// Return all remaining data as a clone-on-write slice.
255271
///
256272
/// The slice will be borrowed where possible, but some readers may
257273
/// always return an owned vector.
258274
///
259275
/// Does not advance the reader.
276+
#[cfg(feature = "read")]
260277
fn to_slice(&self) -> Result<Cow<[u8]>>;
261278

262279
/// Convert all remaining data to a clone-on-write string.
@@ -267,6 +284,7 @@ pub trait Reader: Debug + Clone {
267284
/// Does not advance the reader.
268285
///
269286
/// Returns an error if the data contains invalid characters.
287+
#[cfg(feature = "read")]
270288
fn to_string(&self) -> Result<Cow<str>>;
271289

272290
/// Convert all remaining data to a clone-on-write string, including invalid characters.
@@ -275,6 +293,7 @@ pub trait Reader: Debug + Clone {
275293
/// always return an owned string.
276294
///
277295
/// Does not advance the reader.
296+
#[cfg(feature = "read")]
278297
fn to_string_lossy(&self) -> Result<Cow<str>>;
279298

280299
/// Read exactly `buf.len()` bytes into `buf`.

0 commit comments

Comments
 (0)