Skip to content

Commit 88f8b34

Browse files
maurerByron
authored andcommitted
fix!: Remove unsafe transmute of should_interrupt
Adds a lifetime to the ExtendedBufRead trait to specify how long the callback provided must live.
1 parent abcfb65 commit 88f8b34

File tree

13 files changed

+52
-55
lines changed

13 files changed

+52
-55
lines changed

gix-protocol/src/fetch/arguments/async_io.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ impl Arguments {
99
&mut self,
1010
transport: &'a mut T,
1111
add_done_argument: bool,
12-
) -> Result<Box<dyn client::ExtendedBufRead + Unpin + 'a>, client::Error> {
12+
) -> Result<Box<dyn client::ExtendedBufRead<'a> + Unpin + 'a>, client::Error> {
1313
if self.haves.is_empty() {
1414
assert!(add_done_argument, "If there are no haves, is_done must be true.");
1515
}

gix-protocol/src/fetch/arguments/blocking_io.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ impl Arguments {
1010
&mut self,
1111
transport: &'a mut T,
1212
add_done_argument: bool,
13-
) -> Result<Box<dyn client::ExtendedBufRead + Unpin + 'a>, client::Error> {
13+
) -> Result<Box<dyn client::ExtendedBufRead<'a> + Unpin + 'a>, client::Error> {
1414
if self.haves.is_empty() {
1515
assert!(add_done_argument, "If there are no haves, is_done must be true.");
1616
}

gix-protocol/src/fetch/response/async_io.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use crate::fetch::{
1010

1111
async fn parse_v2_section<T>(
1212
line: &mut String,
13-
reader: &mut (impl client::ExtendedBufRead + Unpin),
13+
reader: &mut (impl client::ExtendedBufRead<'_> + Unpin),
1414
res: &mut Vec<T>,
1515
parse: impl Fn(&str) -> Result<T, response::Error>,
1616
) -> Result<bool, response::Error> {
@@ -44,7 +44,7 @@ impl Response {
4444
/// that `git` has to use to predict how many acks are supposed to be read. We also genuinely hope that this covers it all….
4545
pub async fn from_line_reader(
4646
version: Protocol,
47-
reader: &mut (impl client::ExtendedBufRead + Unpin),
47+
reader: &mut (impl client::ExtendedBufRead<'_> + Unpin),
4848
client_expects_pack: bool,
4949
wants_to_negotiate: bool,
5050
) -> Result<Response, response::Error> {

gix-protocol/src/fetch/response/blocking_io.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ use crate::fetch::{
88
Response,
99
};
1010

11-
fn parse_v2_section<T>(
11+
fn parse_v2_section<'a, T>(
1212
line: &mut String,
13-
reader: &mut impl client::ExtendedBufRead,
13+
reader: &mut impl client::ExtendedBufRead<'a>,
1414
res: &mut Vec<T>,
1515
parse: impl Fn(&str) -> Result<T, response::Error>,
1616
) -> Result<bool, response::Error> {
@@ -42,9 +42,9 @@ impl Response {
4242
/// is to predict how to parse V1 output only, and neither `client_expects_pack` nor `wants_to_negotiate` are relevant for V2.
4343
/// This ugliness is in place to avoid having to resort to an [an even more complex ugliness](https://github.com/git/git/blob/9e49351c3060e1fa6e0d2de64505b7becf157f28/fetch-pack.c#L583-L594)
4444
/// that `git` has to use to predict how many acks are supposed to be read. We also genuinely hope that this covers it all….
45-
pub fn from_line_reader(
45+
pub fn from_line_reader<'a>(
4646
version: Protocol,
47-
reader: &mut impl client::ExtendedBufRead,
47+
reader: &mut impl client::ExtendedBufRead<'a>,
4848
client_expects_pack: bool,
4949
wants_to_negotiate: bool,
5050
) -> Result<Response, response::Error> {

gix-protocol/src/fetch_fn.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -165,8 +165,10 @@ where
165165
Ok(())
166166
}
167167

168-
fn setup_remote_progress<P>(progress: &mut P, reader: &mut Box<dyn gix_transport::client::ExtendedBufRead + Unpin + '_>)
169-
where
168+
fn setup_remote_progress<P>(
169+
progress: &mut P,
170+
reader: &mut Box<dyn gix_transport::client::ExtendedBufRead<'_> + Unpin + '_>,
171+
) where
170172
P: NestedProgress,
171173
P::SubProgress: 'static,
172174
{
@@ -176,5 +178,5 @@ where
176178
crate::RemoteProgress::translate_to_progress(is_err, data, &mut remote_progress);
177179
gix_transport::packetline::read::ProgressAction::Continue
178180
}
179-
}) as gix_transport::client::HandleProgress));
181+
}) as gix_transport::client::HandleProgress<'_>));
180182
}

gix-transport/src/client/async_io/bufread_ext.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use crate::{
1515
/// A function `f(is_error, text)` receiving progress or error information.
1616
/// As it is not a future itself, it must not block. If IO is performed within the function, be sure to spawn
1717
/// it onto an executor.
18-
pub type HandleProgress = Box<dyn FnMut(bool, &[u8]) -> ProgressAction>;
18+
pub type HandleProgress<'a> = Box<dyn FnMut(bool, &[u8]) -> ProgressAction + 'a>;
1919

2020
/// This trait exists to get a version of a `gix_packetline::Provider` without type parameters,
2121
/// but leave support for reading lines directly without forcing them through `String`.
@@ -44,11 +44,11 @@ pub trait ReadlineBufRead: AsyncBufRead {
4444

4545
/// Provide even more access to the underlying packet reader.
4646
#[async_trait(?Send)]
47-
pub trait ExtendedBufRead: ReadlineBufRead {
47+
pub trait ExtendedBufRead<'a>: ReadlineBufRead {
4848
/// Set the handler to which progress will be delivered.
4949
///
5050
/// Note that this is only possible if packet lines are sent in side band mode.
51-
fn set_progress_handler(&mut self, handle_progress: Option<HandleProgress>);
51+
fn set_progress_handler(&mut self, handle_progress: Option<HandleProgress<'a>>);
5252
/// Peek the next data packet line. Maybe None if the next line is a packet we stop at, queryable using
5353
/// [`stopped_at()`][ExtendedBufRead::stopped_at()].
5454
async fn peek_data_line(&mut self) -> Option<io::Result<Result<&[u8], Error>>>;
@@ -70,8 +70,8 @@ impl<'a, T: ReadlineBufRead + ?Sized + 'a + Unpin> ReadlineBufRead for Box<T> {
7070
}
7171

7272
#[async_trait(?Send)]
73-
impl<'a, T: ExtendedBufRead + ?Sized + 'a + Unpin> ExtendedBufRead for Box<T> {
74-
fn set_progress_handler(&mut self, handle_progress: Option<HandleProgress>) {
73+
impl<'a, T: ExtendedBufRead<'a> + ?Sized + 'a + Unpin> ExtendedBufRead<'a> for Box<T> {
74+
fn set_progress_handler(&mut self, handle_progress: Option<HandleProgress<'a>>) {
7575
self.deref_mut().set_progress_handler(handle_progress)
7676
}
7777

@@ -101,7 +101,7 @@ impl<T: AsyncRead + Unpin> ReadlineBufRead
101101
}
102102

103103
#[async_trait(?Send)]
104-
impl<'a, T: AsyncRead + Unpin> ReadlineBufRead for gix_packetline::read::WithSidebands<'a, T, HandleProgress> {
104+
impl<'a, T: AsyncRead + Unpin> ReadlineBufRead for gix_packetline::read::WithSidebands<'a, T, HandleProgress<'a>> {
105105
async fn readline(&mut self) -> Option<io::Result<Result<PacketLineRef<'_>, gix_packetline::decode::Error>>> {
106106
self.read_data_line().await
107107
}
@@ -111,8 +111,8 @@ impl<'a, T: AsyncRead + Unpin> ReadlineBufRead for gix_packetline::read::WithSid
111111
}
112112

113113
#[async_trait(?Send)]
114-
impl<'a, T: AsyncRead + Unpin> ExtendedBufRead for gix_packetline::read::WithSidebands<'a, T, HandleProgress> {
115-
fn set_progress_handler(&mut self, handle_progress: Option<HandleProgress>) {
114+
impl<'a, T: AsyncRead + Unpin> ExtendedBufRead<'a> for gix_packetline::read::WithSidebands<'a, T, HandleProgress<'a>> {
115+
fn set_progress_handler(&mut self, handle_progress: Option<HandleProgress<'a>>) {
116116
self.set_progress_handler(handle_progress)
117117
}
118118
async fn peek_data_line(&mut self) -> Option<io::Result<Result<&[u8], Error>>> {

gix-transport/src/client/async_io/request.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ pin_project! {
1717
on_into_read: MessageKind,
1818
#[pin]
1919
writer: gix_packetline::Writer<Box<dyn AsyncWrite + Unpin + 'a>>,
20-
reader: Box<dyn ExtendedBufRead + Unpin + 'a>,
20+
reader: Box<dyn ExtendedBufRead<'a> + Unpin + 'a>,
2121
trace: bool,
2222
}
2323
}
@@ -43,7 +43,7 @@ impl<'a> RequestWriter<'a> {
4343
/// If `trace` is true, `gix_trace` will be used on every written message or data.
4444
pub fn new_from_bufread<W: AsyncWrite + Unpin + 'a>(
4545
writer: W,
46-
reader: Box<dyn ExtendedBufRead + Unpin + 'a>,
46+
reader: Box<dyn ExtendedBufRead<'a> + Unpin + 'a>,
4747
write_mode: WriteMode,
4848
on_into_read: MessageKind,
4949
trace: bool,
@@ -102,7 +102,7 @@ impl<'a> RequestWriter<'a> {
102102
/// Discard the ability to write and turn this instance into the reader for obtaining the other side's response.
103103
///
104104
/// Doing so will also write the message type this instance was initialized with.
105-
pub async fn into_read(mut self) -> std::io::Result<Box<dyn ExtendedBufRead + Unpin + 'a>> {
105+
pub async fn into_read(mut self) -> std::io::Result<Box<dyn ExtendedBufRead<'a> + Unpin + 'a>> {
106106
use futures_lite::AsyncWriteExt;
107107
self.write_message(self.on_into_read).await?;
108108
self.writer.inner_mut().flush().await?;
@@ -119,7 +119,12 @@ impl<'a> RequestWriter<'a> {
119119
/// It's of utmost importance to drop the request writer before reading the response as these might be inter-dependent, depending on
120120
/// the underlying transport mechanism. Failure to do so may result in a deadlock depending on how the write and read mechanism
121121
/// is implemented.
122-
pub fn into_parts(self) -> (Box<dyn AsyncWrite + Unpin + 'a>, Box<dyn ExtendedBufRead + Unpin + 'a>) {
122+
pub fn into_parts(
123+
self,
124+
) -> (
125+
Box<dyn AsyncWrite + Unpin + 'a>,
126+
Box<dyn ExtendedBufRead<'a> + Unpin + 'a>,
127+
) {
123128
(self.writer.into_inner(), self.reader)
124129
}
125130
}

gix-transport/src/client/async_io/traits.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ pub trait TransportV2Ext {
8282
capabilities: impl Iterator<Item = (&'a str, Option<impl AsRef<str>>)> + 'a,
8383
arguments: Option<impl Iterator<Item = bstr::BString> + 'a>,
8484
trace: bool,
85-
) -> Result<Box<dyn ExtendedBufRead + Unpin + '_>, Error>;
85+
) -> Result<Box<dyn ExtendedBufRead<'_> + Unpin + '_>, Error>;
8686
}
8787

8888
#[async_trait(?Send)]
@@ -93,7 +93,7 @@ impl<T: Transport> TransportV2Ext for T {
9393
capabilities: impl Iterator<Item = (&'a str, Option<impl AsRef<str>>)> + 'a,
9494
arguments: Option<impl Iterator<Item = BString> + 'a>,
9595
trace: bool,
96-
) -> Result<Box<dyn ExtendedBufRead + Unpin + '_>, Error> {
96+
) -> Result<Box<dyn ExtendedBufRead<'_> + Unpin + '_>, Error> {
9797
let mut writer = self.request(WriteMode::OneLfTerminatedLinePerWriteCall, MessageKind::Flush, trace)?;
9898
writer.write_all(format!("command={command}").as_bytes()).await?;
9999
for (name, value) in capabilities {

gix-transport/src/client/blocking_io/bufread_ext.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use crate::{
1010
Protocol,
1111
};
1212
/// A function `f(is_error, text)` receiving progress or error information.
13-
pub type HandleProgress = Box<dyn FnMut(bool, &[u8]) -> ProgressAction>;
13+
pub type HandleProgress<'a> = Box<dyn FnMut(bool, &[u8]) -> ProgressAction + 'a>;
1414

1515
/// This trait exists to get a version of a `gix_packetline::Provider` without type parameters,
1616
/// but leave support for reading lines directly without forcing them through `String`.
@@ -37,11 +37,11 @@ pub trait ReadlineBufRead: io::BufRead {
3737
}
3838

3939
/// Provide even more access to the underlying packet reader.
40-
pub trait ExtendedBufRead: ReadlineBufRead {
40+
pub trait ExtendedBufRead<'a>: ReadlineBufRead {
4141
/// Set the handler to which progress will be delivered.
4242
///
4343
/// Note that this is only possible if packet lines are sent in side band mode.
44-
fn set_progress_handler(&mut self, handle_progress: Option<HandleProgress>);
44+
fn set_progress_handler(&mut self, handle_progress: Option<HandleProgress<'a>>);
4545
/// Peek the next data packet line. Maybe None if the next line is a packet we stop at, queryable using
4646
/// [`stopped_at()`][ExtendedBufRead::stopped_at()].
4747
fn peek_data_line(&mut self) -> Option<io::Result<Result<&[u8], Error>>>;
@@ -61,8 +61,8 @@ impl<'a, T: ReadlineBufRead + ?Sized + 'a> ReadlineBufRead for Box<T> {
6161
}
6262
}
6363

64-
impl<'a, T: ExtendedBufRead + ?Sized + 'a> ExtendedBufRead for Box<T> {
65-
fn set_progress_handler(&mut self, handle_progress: Option<HandleProgress>) {
64+
impl<'a, T: ExtendedBufRead<'a> + ?Sized + 'a> ExtendedBufRead<'a> for Box<T> {
65+
fn set_progress_handler(&mut self, handle_progress: Option<HandleProgress<'a>>) {
6666
self.deref_mut().set_progress_handler(handle_progress)
6767
}
6868

@@ -89,7 +89,7 @@ impl<T: io::Read> ReadlineBufRead for gix_packetline::read::WithSidebands<'_, T,
8989
}
9090
}
9191

92-
impl<'a, T: io::Read> ReadlineBufRead for gix_packetline::read::WithSidebands<'a, T, HandleProgress> {
92+
impl<'a, T: io::Read> ReadlineBufRead for gix_packetline::read::WithSidebands<'a, T, HandleProgress<'a>> {
9393
fn readline(&mut self) -> Option<io::Result<Result<PacketLineRef<'_>, gix_packetline::decode::Error>>> {
9494
self.read_data_line()
9595
}
@@ -99,8 +99,8 @@ impl<'a, T: io::Read> ReadlineBufRead for gix_packetline::read::WithSidebands<'a
9999
}
100100
}
101101

102-
impl<'a, T: io::Read> ExtendedBufRead for gix_packetline::read::WithSidebands<'a, T, HandleProgress> {
103-
fn set_progress_handler(&mut self, handle_progress: Option<HandleProgress>) {
102+
impl<'a, T: io::Read> ExtendedBufRead<'a> for gix_packetline::read::WithSidebands<'a, T, HandleProgress<'a>> {
103+
fn set_progress_handler(&mut self, handle_progress: Option<HandleProgress<'a>>) {
104104
self.set_progress_handler(handle_progress)
105105
}
106106
fn peek_data_line(&mut self) -> Option<io::Result<Result<&[u8], Error>>> {

gix-transport/src/client/blocking_io/http/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -516,8 +516,8 @@ impl<H: Http, B: ReadlineBufRead + Unpin> ReadlineBufRead for HeadersThenBody<H,
516516
}
517517
}
518518

519-
impl<H: Http, B: ExtendedBufRead + Unpin> ExtendedBufRead for HeadersThenBody<H, B> {
520-
fn set_progress_handler(&mut self, handle_progress: Option<HandleProgress>) {
519+
impl<'a, H: Http, B: ExtendedBufRead<'a> + Unpin> ExtendedBufRead<'a> for HeadersThenBody<H, B> {
520+
fn set_progress_handler(&mut self, handle_progress: Option<HandleProgress<'a>>) {
521521
self.body.set_progress_handler(handle_progress)
522522
}
523523

gix-transport/src/client/blocking_io/request.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use crate::client::{ExtendedBufRead, MessageKind, WriteMode};
88
pub struct RequestWriter<'a> {
99
on_into_read: MessageKind,
1010
writer: gix_packetline::Writer<Box<dyn io::Write + 'a>>,
11-
reader: Box<dyn ExtendedBufRead + Unpin + 'a>,
11+
reader: Box<dyn ExtendedBufRead<'a> + Unpin + 'a>,
1212
trace: bool,
1313
}
1414

@@ -35,7 +35,7 @@ impl<'a> RequestWriter<'a> {
3535
/// If `trace` is true, `gix_trace` will be used on every written message or data.
3636
pub fn new_from_bufread<W: io::Write + 'a>(
3737
writer: W,
38-
reader: Box<dyn ExtendedBufRead + Unpin + 'a>,
38+
reader: Box<dyn ExtendedBufRead<'a> + Unpin + 'a>,
3939
write_mode: WriteMode,
4040
on_into_read: MessageKind,
4141
trace: bool,
@@ -89,7 +89,7 @@ impl<'a> RequestWriter<'a> {
8989
/// Discard the ability to write and turn this instance into the reader for obtaining the other side's response.
9090
///
9191
/// Doing so will also write the message type this instance was initialized with.
92-
pub fn into_read(mut self) -> std::io::Result<Box<dyn ExtendedBufRead + Unpin + 'a>> {
92+
pub fn into_read(mut self) -> std::io::Result<Box<dyn ExtendedBufRead<'a> + Unpin + 'a>> {
9393
self.write_message(self.on_into_read)?;
9494
self.writer.inner_mut().flush()?;
9595
Ok(self.reader)
@@ -105,7 +105,7 @@ impl<'a> RequestWriter<'a> {
105105
/// It's of utmost importance to drop the request writer before reading the response as these might be inter-dependent, depending on
106106
/// the underlying transport mechanism. Failure to do so may result in a deadlock depending on how the write and read mechanism
107107
/// is implemented.
108-
pub fn into_parts(self) -> (Box<dyn io::Write + 'a>, Box<dyn ExtendedBufRead + Unpin + 'a>) {
108+
pub fn into_parts(self) -> (Box<dyn io::Write + 'a>, Box<dyn ExtendedBufRead<'a> + Unpin + 'a>) {
109109
(self.writer.into_inner(), self.reader)
110110
}
111111
}

gix-transport/src/client/blocking_io/traits.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ pub trait TransportV2Ext {
7575
capabilities: impl Iterator<Item = (&'a str, Option<impl AsRef<str>>)> + 'a,
7676
arguments: Option<impl Iterator<Item = bstr::BString>>,
7777
trace: bool,
78-
) -> Result<Box<dyn ExtendedBufRead + Unpin + '_>, Error>;
78+
) -> Result<Box<dyn ExtendedBufRead<'_> + Unpin + '_>, Error>;
7979
}
8080

8181
impl<T: Transport> TransportV2Ext for T {
@@ -85,7 +85,7 @@ impl<T: Transport> TransportV2Ext for T {
8585
capabilities: impl Iterator<Item = (&'a str, Option<impl AsRef<str>>)> + 'a,
8686
arguments: Option<impl Iterator<Item = BString>>,
8787
trace: bool,
88-
) -> Result<Box<dyn ExtendedBufRead + Unpin + '_>, Error> {
88+
) -> Result<Box<dyn ExtendedBufRead<'_> + Unpin + '_>, Error> {
8989
let mut writer = self.request(WriteMode::OneLfTerminatedLinePerWriteCall, MessageKind::Flush, trace)?;
9090
writer.write_all(format!("command={command}").as_bytes())?;
9191
for (name, value) in capabilities {

gix/src/remote/connection/fetch/receive_pack.rs

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -410,24 +410,14 @@ fn add_shallow_args(
410410
Ok((shallow_commits, shallow_lock))
411411
}
412412

413-
fn setup_remote_progress(
413+
fn setup_remote_progress<'a>(
414414
progress: &mut dyn crate::DynNestedProgress,
415-
reader: &mut Box<dyn gix_protocol::transport::client::ExtendedBufRead + Unpin + '_>,
416-
should_interrupt: &AtomicBool,
415+
reader: &mut Box<dyn gix_protocol::transport::client::ExtendedBufRead<'a> + Unpin + 'a>,
416+
should_interrupt: &'a AtomicBool,
417417
) {
418418
use gix_protocol::transport::client::ExtendedBufRead;
419419
reader.set_progress_handler(Some(Box::new({
420420
let mut remote_progress = progress.add_child_with_id("remote".to_string(), ProgressId::RemoteProgress.into());
421-
// SAFETY: Ugh, so, with current Rust I can't declare lifetimes in the involved traits the way they need to
422-
// be and I also can't use scoped threads to pump from local scopes to an Arc version that could be
423-
// used here due to the this being called from sync AND async code (and the async version doesn't work
424-
// with a surrounding `std::thread::scope()`.
425-
// Thus there is only claiming this is 'static which we know works for *our* implementations of ExtendedBufRead
426-
// and typical implementations, but of course it's possible for user code to come along and actually move this
427-
// handler into a context where it can outlive the current function. Is this going to happen? Probably not unless
428-
// somebody really wants to break it. So, with standard usage this value is never used past its actual lifetime.
429-
#[allow(unsafe_code)]
430-
let should_interrupt: &'static AtomicBool = unsafe { std::mem::transmute(should_interrupt) };
431421
move |is_err: bool, data: &[u8]| {
432422
gix_protocol::RemoteProgress::translate_to_progress(is_err, data, &mut remote_progress);
433423
if should_interrupt.load(Ordering::Relaxed) {
@@ -436,5 +426,5 @@ fn setup_remote_progress(
436426
ProgressAction::Continue
437427
}
438428
}
439-
}) as gix_protocol::transport::client::HandleProgress));
429+
}) as gix_protocol::transport::client::HandleProgress<'a>));
440430
}

0 commit comments

Comments
 (0)