Skip to content

Commit bf5f3db

Browse files
yannhampaullegranddc
authored andcommitted
doc: add safety comments and missing unsafe annotation
1 parent ffc9d77 commit bf5f3db

1 file changed

Lines changed: 40 additions & 46 deletions

File tree

  • libdd-trace-utils/src/change_buffer

libdd-trace-utils/src/change_buffer/mod.rs

Lines changed: 40 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -347,8 +347,14 @@ where
347347
let mut count = self.change_buffer.read::<u64>(&mut index)? as u32;
348348

349349
let mut cached_slot: u32 = u32::MAX;
350-
// We keep a bunch of cached internal pointers. They are safe to use as long as we don't
351-
// modify their parent vector and keep a unique borrow to `self` overall.
350+
// Cached elements for the current span.
351+
//
352+
// When applying span operations, we cache the last span index (cached_slot) and the
353+
// corresponding elements in `deffered_meta`, `deferred_metrics`, and `span`. We use direct
354+
// pointers to save intermediate dereferences.
355+
//
356+
// They are safe to use as long as we don't modify their parent vector and keep a unique
357+
// borrow to `self` overall.
352358
//
353359
// Using mutable references instead would be better, but is not possible (or very hard)
354360
// given we iterate and nest calls to different submethods taking a `&mut self`.
@@ -368,14 +374,19 @@ where
368374
self.interpret_operation(&mut index, &op)?;
369375
}
370376
_ => {
371-
self.interpret_operation_cached(
372-
&mut index,
373-
&op,
374-
&mut cached_slot,
375-
&mut cached_span_ptr,
376-
&mut cached_deferred_meta,
377-
&mut cached_deferred_metrics,
378-
)?;
377+
// SAFETY: at the first iteration of the loop, all pointers are null and
378+
// `*cached_slot` is `u32::MAX`. In subsequent iterations,
379+
// `interpret_operation_cached` maintains its own safety invariant.
380+
unsafe {
381+
self.interpret_operation_cached(
382+
&mut index,
383+
&op,
384+
&mut cached_slot,
385+
&mut cached_span_ptr,
386+
&mut cached_deferred_meta,
387+
&mut cached_deferred_metrics,
388+
)?;
389+
}
379390
}
380391
}
381392
count -= 1;
@@ -387,7 +398,15 @@ where
387398
Ok(())
388399
}
389400

390-
fn interpret_operation_cached(
401+
/// # Safety
402+
///
403+
/// The pointer arguments provided to this function: `*cached_slot`, `*cached_span_ptr`,
404+
/// `*cached_deferred_meta` and `*cached_deferred_metrics` must either:
405+
///
406+
/// - be all `null` if `*cached_slot` is `u32::MAX`
407+
/// - point to `self.spans[*cached_slot]`, `self.deferred_meta[*cached_slot]` and
408+
/// `self.deferred_metrics[*cached_slot]` respectively otherwise.
409+
unsafe fn interpret_operation_cached(
391410
&mut self,
392411
index: &mut usize,
393412
op: &BufferedOperation,
@@ -418,13 +437,9 @@ where
418437
// modified during this function (no inserts/removes).
419438
let span = unsafe { &mut *span_ptr };
420439

421-
// SAFETY:
422-
//
423-
// - `cached_deferred_xxx`: they point to writable memory (derived from self), and we don't
424-
// modify, move nor drop the parent `deferred_xxx` vec, so the pointer should remain
425-
// valid.
426-
// - `xxx_unchecked`: we rely on the encoder side to write the correct arguments to an
427-
// opcode.
440+
// SAFETY: `cached_deferred_xxx`: they point to writable memory, and we don't shrink, move
441+
// nor drop the parent `deferred_xxx` vec, so the pointers remain valid. We keep a mutable
442+
// borrow on `self`, which ensures ownership/uniqueness.
428443
match op.opcode {
429444
OpCode::SetMetaAttr => {
430445
let key_id: u32 = self.get_num_arg(index)?;
@@ -439,25 +454,25 @@ where
439454
dm.insert(key_id, val);
440455
}
441456
OpCode::SetServiceName => {
442-
span.service = unsafe { self.get_string_arg_unchecked(index) };
457+
span.service = self.get_string_arg(index)?;
443458
}
444459
OpCode::SetResourceName => {
445-
span.resource = unsafe { self.get_string_arg_unchecked(index) };
460+
span.resource = self.get_string_arg(index)?;
446461
}
447462
OpCode::SetError => {
448-
span.error = unsafe { self.get_num_arg_unchecked(index) };
463+
span.error = self.get_num_arg(index)?;
449464
}
450465
OpCode::SetStart => {
451-
span.start = unsafe { self.get_num_arg_unchecked(index) };
466+
span.start = self.get_num_arg(index)?;
452467
}
453468
OpCode::SetDuration => {
454-
span.duration = unsafe { self.get_num_arg_unchecked(index) };
469+
span.duration = self.get_num_arg(index)?;
455470
}
456471
OpCode::SetType => {
457-
span.r#type = unsafe { self.get_string_arg_unchecked(index) };
472+
span.r#type = self.get_string_arg(index)?;
458473
}
459474
OpCode::SetName => {
460-
span.name = unsafe { self.get_string_arg_unchecked(index) };
475+
span.name = self.get_string_arg(index)?;
461476
}
462477
OpCode::SetTraceMetaAttr => {
463478
let name = self.get_string_arg(index)?;
@@ -514,31 +529,10 @@ where
514529
.ok_or(ChangeBufferError::StringNotFound(num))
515530
}
516531

517-
/// # Safety
518-
///
519-
/// Caller must ensure `*index + size_of::<T::Tex>() <= self.change_buffer.len`.
520-
#[inline(always)]
521-
unsafe fn get_string_arg_unchecked(&self, index: &mut usize) -> T::Text {
522-
let num: u32 = self.change_buffer.read_unchecked(index);
523-
self.string_table
524-
.get_unchecked(num as usize)
525-
.clone()
526-
.unwrap_unchecked()
527-
}
528-
529532
fn get_num_arg<U: Copy + FromBytes>(&self, index: &mut usize) -> Result<U> {
530533
self.change_buffer.read(index)
531534
}
532535

533-
/// # Safety
534-
///
535-
/// Caller must ensure `*index + size_of::<U>() <= self.change_buffer.len`.
536-
#[inline(always)]
537-
unsafe fn get_num_arg_unchecked<U: Copy + FromBytes>(&self, index: &mut usize) -> U {
538-
// Safety: this function's pre-condition
539-
unsafe { self.change_buffer.read_unchecked(index) }
540-
}
541-
542536
fn get_span_mut(&mut self, slot: u32) -> Result<&mut Span<T>> {
543537
self.spans
544538
.get_mut(slot as usize)

0 commit comments

Comments
 (0)