Skip to content

Commit 5255129

Browse files
appaquetdwrensha
authored andcommitted
Use AtomicUsize for read limiter + feature gate it
1 parent 22d3321 commit 5255129

File tree

4 files changed

+102
-29
lines changed

4 files changed

+102
-29
lines changed

capnp/Cargo.toml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ quickcheck = { version = "0.9", optional = true }
2525
quickcheck = "0.9"
2626

2727
[features]
28-
default = ["std"]
28+
default = ["std", "sync_reader"]
2929

3030
rpc_try = []
3131

@@ -37,3 +37,8 @@ unaligned = []
3737
# with the Rust standard library.
3838
std = []
3939

40+
# If disabled, message reader will not be `Sync`. This can be used
41+
# to support platforms where `AtomicUsize` is not available.
42+
# To be replaced by #[cfg(target_has_atomic = ...)] once it lands.
43+
# See: https://github.com/rust-lang/rust/issues/32976
44+
sync_reader = []

capnp/src/private/arena.rs

Lines changed: 3 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -20,42 +20,17 @@
2020

2121
use alloc::vec::Vec;
2222
use core::cell::RefCell;
23-
use core::sync::atomic::{AtomicU64, Ordering};
2423
use core::slice;
2524
use core::u64;
2625

2726
use crate::private::units::*;
27+
use crate::private::read_limiter::ReadLimiter;
2828
use crate::message;
2929
use crate::message::{Allocator, ReaderSegments};
3030
use crate::{Error, OutputSegments, Result};
3131

3232
pub type SegmentId = u32;
3333

34-
pub struct ReadLimiter {
35-
pub limit: u64,
36-
pub read: AtomicU64,
37-
}
38-
39-
impl ReadLimiter {
40-
pub fn new(limit: u64) -> ReadLimiter {
41-
ReadLimiter {
42-
limit,
43-
read: AtomicU64::new(0),
44-
}
45-
}
46-
47-
#[inline]
48-
pub fn can_read(&self, amount: u64) -> Result<()> {
49-
let read = self.read.fetch_add(amount, Ordering::Relaxed) + amount;
50-
51-
if read > self.limit {
52-
Err(Error::failed(format!("read limit exceeded")))
53-
} else {
54-
Ok(())
55-
}
56-
}
57-
}
58-
5934
pub trait ReaderArena {
6035
// return pointer to start of segment, and number of words in that segment
6136
fn get_segment(&self, id: u32) -> Result<(*const u8, u32)>;
@@ -134,12 +109,12 @@ impl <S> ReaderArena for ReaderArenaImpl<S> where S: ReaderSegments {
134109
if !(start >= this_start && start - this_start + size <= this_size) {
135110
Err(Error::failed(format!("message contained out-of-bounds pointer")))
136111
} else {
137-
self.read_limiter.can_read(size_in_words as u64)
112+
self.read_limiter.can_read(size_in_words)
138113
}
139114
}
140115

141116
fn amplified_read(&self, virtual_amount: u64) -> Result<()> {
142-
self.read_limiter.can_read(virtual_amount)
117+
self.read_limiter.can_read(virtual_amount as usize)
143118
}
144119
}
145120

capnp/src/private/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ mod primitive;
2929
pub mod layout;
3030
mod mask;
3131
pub mod units;
32+
mod read_limiter;
3233
mod zero;
3334

3435
#[cfg(test)]

capnp/src/private/read_limiter.rs

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
// Copyright (c) 2013-2015 Sandstorm Development Group, Inc. and contributors
2+
// Licensed under the MIT License:
3+
//
4+
// Permission is hereby granted, free of charge, to any person obtaining a copy
5+
// of this software and associated documentation files (the "Software"), to deal
6+
// in the Software without restriction, including without limitation the rights
7+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
// copies of the Software, and to permit persons to whom the Software is
9+
// furnished to do so, subject to the following conditions:
10+
//
11+
// The above copyright notice and this permission notice shall be included in
12+
// all copies or substantial portions of the Software.
13+
//
14+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20+
// THE SOFTWARE.
21+
22+
#[cfg(feature = "sync_reader")]
23+
pub use sync::ReadLimiter;
24+
25+
#[cfg(feature = "sync_reader")]
26+
mod sync {
27+
use crate::{Error, Result};
28+
use core::sync::atomic::{AtomicUsize, Ordering};
29+
30+
pub struct ReadLimiter {
31+
pub limit: usize,
32+
pub read: AtomicUsize,
33+
}
34+
35+
impl ReadLimiter {
36+
pub fn new(limit: u64) -> ReadLimiter {
37+
if limit > core::usize::MAX as u64 {
38+
panic!("traversal_limit_in_words cannot be bigger than core::usize::MAX")
39+
}
40+
41+
ReadLimiter {
42+
limit: limit as usize,
43+
read: AtomicUsize::new(0),
44+
}
45+
}
46+
47+
#[inline]
48+
pub fn can_read(&self, amount: usize) -> Result<()> {
49+
let read = self.read.load(Ordering::Relaxed) + amount;
50+
51+
if read > self.limit {
52+
Err(Error::failed(format!("read limit exceeded")))
53+
} else {
54+
self.read.fetch_add(amount, Ordering::Relaxed);
55+
Ok(())
56+
}
57+
}
58+
}
59+
}
60+
61+
#[cfg(not(feature = "sync_reader"))]
62+
pub use unsync::ReadLimiter;
63+
64+
#[cfg(not(feature = "sync_reader"))]
65+
mod unsync {
66+
use core::cell::Cell;
67+
use crate::{Error, Result};
68+
69+
pub struct ReadLimiter {
70+
pub limit: Cell<u64>,
71+
}
72+
73+
impl ReadLimiter {
74+
pub fn new(limit: u64) -> ReadLimiter {
75+
ReadLimiter {
76+
limit: Cell::new(limit),
77+
}
78+
}
79+
80+
#[inline]
81+
pub fn can_read(&self, amount: usize) -> Result<()> {
82+
let amount = amount as u64;
83+
let current = self.limit.get();
84+
if amount > current {
85+
Err(Error::failed(format!("read limit exceeded")))
86+
} else {
87+
self.limit.set(current - amount);
88+
Ok(())
89+
}
90+
}
91+
}
92+
}

0 commit comments

Comments
 (0)