Skip to content

Commit cac272d

Browse files
authored
Merge pull request #6346 from cloudflare/yagiz/enable-unsafe-safety-comments
enable undocumented_unsafe_blocks clippy rule
2 parents 99c199d + 6ca9873 commit cac272d

File tree

17 files changed

+190
-20
lines changed

17 files changed

+190
-20
lines changed

build/rust_lint.bazelrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ build:rust-enable-clippy-checks --output_groups=+clippy_checks
2323
# - clippy::non_std_lazy_statics – triggers on lazy_static, non-trivial to replace
2424
# - clippy::format_push_string – avoids single memory allocation, but makes code less readable
2525
# - clippy::cast_possible_truncation - usize/u64 conversion warning is unbelievably noisy
26-
build:rust-enable-clippy-checks --@rules_rust//:clippy_flags=-Wclippy::pedantic,-Wclippy::redundant_clone,-Wclippy::str_to_string,-Wclippy::to_string_in_format_args,-Wclippy::unnecessary_to_owned,-Wclippy::implicit_clone,-Wclippy::suspicious_to_owned,-Wclippy::unnecessary_to_owned,-Wclippy::nursery,-Wclippy::dbg_macro,-Wclippy::unwrap_used,-Wclippy::allow_attributes,-Aclippy::missing_const_for_fn,-Aclippy::cognitive_complexity,-Aclippy::trait_duplication_in_bounds,-Aclippy::non_send_fields_in_send_ty,-Aclippy::option_if_let_else,-Aclippy::missing_errors_doc,-Aclippy::must_use_candidate,-Aclippy::future_not_send,-Aclippy::trivial_regex,-Aclippy::literal_string_with_formatting_args,-Aclippy::non_std_lazy_statics,-Aclippy::format_push_string,-Aclippy::cast_possible_truncation,-Dwarnings
26+
build:rust-enable-clippy-checks --@rules_rust//:clippy_flags=-Wclippy::pedantic,-Wclippy::redundant_clone,-Wclippy::str_to_string,-Wclippy::to_string_in_format_args,-Wclippy::unnecessary_to_owned,-Wclippy::implicit_clone,-Wclippy::suspicious_to_owned,-Wclippy::unnecessary_to_owned,-Wclippy::nursery,-Wclippy::dbg_macro,-Wclippy::unwrap_used,-Wclippy::allow_attributes,-Wclippy::undocumented_unsafe_blocks,-Aclippy::missing_const_for_fn,-Aclippy::cognitive_complexity,-Aclippy::trait_duplication_in_bounds,-Aclippy::non_send_fields_in_send_ty,-Aclippy::option_if_let_else,-Aclippy::missing_errors_doc,-Aclippy::must_use_candidate,-Aclippy::future_not_send,-Aclippy::trivial_regex,-Aclippy::literal_string_with_formatting_args,-Aclippy::non_std_lazy_statics,-Aclippy::format_push_string,-Aclippy::cast_possible_truncation,-Dwarnings
2727
build --@rules_rust//rust/settings:clippy.toml=//src/rust:clippy.toml
2828

2929
# enable rustfmt checks

src/rust/api/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ pub fn register_nodejs_modules(registry: Pin<&mut ffi::ModuleRegistry>) {
2525
jsg::modules::add_builtin(
2626
registry,
2727
"node-internal:dns",
28+
// SAFETY: isolate is a valid pointer provided by V8 during module resolution.
2829
|isolate| unsafe {
2930
let mut lock = jsg::Lock::from_isolate_ptr(isolate);
3031
let dns_util = jsg::Ref::new(DnsUtil {
@@ -48,6 +49,7 @@ mod tests {
4849
#[test]
4950
fn test_wrap_resource_equality() {
5051
let harness = Harness::new();
52+
// SAFETY: Harness guarantees lock and context are valid within run_in_context.
5153
harness.run_in_context(|lock, _ctx| unsafe {
5254
let dns_util = jsg::Ref::new(DnsUtil {
5355
_state: ResourceState::default(),

src/rust/cxx-integration-test/lib.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,11 +134,14 @@ fn pass_shared_struct_as_mut_ref(s: &mut ffi::SharedStruct) {
134134

135135
unsafe fn pass_shared_struct_as_const_ptr(s: *const ffi::SharedStruct) -> i32 {
136136
assert!(!s.is_null());
137+
// SAFETY: Null check above ensures s is valid; the SharedStruct is valid for reads.
137138
unsafe { (*s).a + (*s).b }
138139
}
139140

140141
unsafe fn pass_shared_struct_as_mut_ptr(s: *mut ffi::SharedStruct) {
142+
// SAFETY: Caller guarantees s is a valid, non-null mutable pointer.
141143
unsafe { (*s).a = 0 };
144+
// SAFETY: Caller guarantees s is a valid, non-null mutable pointer.
142145
unsafe { (*s).b = 0 };
143146
}
144147

@@ -180,7 +183,9 @@ fn get_str() -> &'static str {
180183
"rust_str"
181184
}
182185

186+
// SAFETY: UsizeCallback is only accessed from the Tokio runtime thread after being moved there.
183187
unsafe impl Send for ffi::UsizeCallback {}
188+
// SAFETY: UsizeCallback is only accessed from one thread at a time via Pin<&mut>.
184189
unsafe impl Sync for ffi::UsizeCallback {}
185190

186191
fn async_immediate(callback: Pin<&'static mut ffi::UsizeCallback>) {
@@ -205,6 +210,7 @@ mod tests {
205210
fn asan_stack_buffer_overflow() {
206211
expect_signal!(Signal::SIGABRT, {
207212
let xs = [0, 1, 2, 3];
213+
// SAFETY: Intentional out-of-bounds access to trigger ASAN detection.
208214
let _y = unsafe { *xs.as_ptr().offset(4) };
209215
});
210216
}

src/rust/jsg-macros/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ pub fn jsg_struct(attr: TokenStream, item: TokenStream) -> TokenStream {
8686
// TODO(soon): Use a precached ObjectTemplate instance to create the object,
8787
// similar to how C++ JSG optimizes object creation. This would avoid recreating
8888
// the object shape on every wrap() call and improve performance.
89-
unsafe {
89+
{
9090
let this = self;
9191
let mut obj = lock.new_object();
9292
#(#field_assignments)*
@@ -215,6 +215,7 @@ pub fn jsg_method(_attr: TokenStream, item: TokenStream) -> TokenStream {
215215
#fn_vis #fn_sig { #fn_block }
216216

217217
#[automatically_derived]
218+
#[expect(clippy::undocumented_unsafe_blocks)]
218219
extern "C" fn #callback_name(args: *mut jsg::v8::ffi::FunctionCallbackInfo) {
219220
let mut lock = unsafe { jsg::Lock::from_args(args) };
220221
let mut args = unsafe { jsg::v8::FunctionCallbackInfo::from_ffi(args) };

src/rust/jsg-test/lib.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,12 +78,14 @@ impl EvalContext<'_> {
7878
where
7979
T: jsg::FromJS<ResultType = T>,
8080
{
81+
// SAFETY: self.inner is a valid EvalContext from C++; code is a valid str.
8182
let result = unsafe { self.inner.eval(code) };
8283
let opt_local: Option<v8::ffi::Local> = result.value.into();
8384

8485
if result.success {
8586
match opt_local {
8687
Some(local) => {
88+
// SAFETY: self.isolate is valid and local is from a successful eval result.
8789
let local = unsafe { v8::Local::from_ffi(self.isolate, local) };
8890
match T::from_js(lock, local.clone()) {
8991
Err(e) => Err(EvalError::UncoercibleResult {
@@ -98,6 +100,7 @@ impl EvalContext<'_> {
98100
} else {
99101
match opt_local {
100102
Some(local) => {
103+
// SAFETY: self.isolate is valid and local is from an eval exception.
101104
let value = unsafe { v8::Local::from_ffi(self.isolate, local) };
102105
Err(EvalError::Exception(value))
103106
}
@@ -110,17 +113,20 @@ impl EvalContext<'_> {
110113
///
111114
/// Useful for obtaining handles (e.g. functions) that aren't `FromJS` types.
112115
pub fn eval_raw(&self, code: &str) -> Result<v8::Local<'_, v8::Value>, EvalError<'_>> {
116+
// SAFETY: self.inner is a valid EvalContext from C++; code is a valid str.
113117
let result = unsafe { self.inner.eval(code) };
114118
let opt_local: Option<v8::ffi::Local> = result.value.into();
115119

116120
if result.success {
117121
match opt_local {
122+
// SAFETY: self.isolate is valid and local is from a successful eval result.
118123
Some(local) => Ok(unsafe { v8::Local::from_ffi(self.isolate, local) }),
119124
None => unreachable!(),
120125
}
121126
} else {
122127
match opt_local {
123128
Some(local) => {
129+
// SAFETY: self.isolate is valid and local is from an eval exception.
124130
let value = unsafe { v8::Local::from_ffi(self.isolate, local) };
125131
Err(EvalError::Exception(value))
126132
}
@@ -130,12 +136,14 @@ impl EvalContext<'_> {
130136
}
131137

132138
pub fn set_global(&self, name: &str, value: v8::Local<v8::Value>) {
139+
// SAFETY: self.inner is a valid EvalContext and value is a valid Local handle.
133140
unsafe { self.inner.set_global(name, value.into_ffi()) }
134141
}
135142
}
136143

137144
impl Harness {
138145
pub fn new() -> Self {
146+
// SAFETY: create_test_harness initializes the V8 platform and returns a valid harness.
139147
Self(unsafe { ffi::create_test_harness() })
140148
}
141149

@@ -159,13 +167,16 @@ impl Harness {
159167
) where
160168
F: FnOnce(&mut jsg::Lock, &mut EvalContext) -> Result<(), jsg::Error>,
161169
{
170+
// SAFETY: data was cast from &raw mut Option<F> in run_in_context below.
162171
let cb = unsafe { &mut *(data as *mut Option<F>) };
163172
if let Some(callback) = cb.take() {
173+
// SAFETY: isolate is a valid pointer provided by the C++ test harness.
164174
let isolate_ptr = unsafe { v8::IsolatePtr::from_ffi(isolate) };
165175
let mut eval_context = EvalContext {
166176
inner: &context,
167177
isolate: isolate_ptr,
168178
};
179+
// SAFETY: isolate is a valid pointer provided by the C++ test harness.
169180
let mut lock = unsafe { jsg::Lock::from_isolate_ptr(isolate) };
170181
if let Err(e) = callback(&mut lock, &mut eval_context) {
171182
panic!("Test failed: {}: {}", e.name, e.message);
@@ -174,6 +185,7 @@ impl Harness {
174185
}
175186

176187
let mut callback = Some(callback);
188+
// SAFETY: callback pointer is valid for the duration of run_in_context.
177189
unsafe {
178190
self.0
179191
.run_in_context(&raw mut callback as usize, trampoline::<F>);

src/rust/jsg-test/tests/arrays.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ fn resource_accepts_array_parameter() {
162162
_state: ResourceState::default(),
163163
});
164164
let mut template = ArrayResourceTemplate::new(lock);
165+
// SAFETY: Lock is valid, resource is a valid Ref, and template holds a valid FunctionTemplate.
165166
let wrapped = unsafe { jsg::wrap_resource(lock, resource, &mut template) };
166167
ctx.set_global("arr", wrapped);
167168

@@ -184,6 +185,7 @@ fn resource_accepts_slice_parameter() {
184185
_state: ResourceState::default(),
185186
});
186187
let mut template = ArrayResourceTemplate::new(lock);
188+
// SAFETY: Lock is valid, resource is a valid Ref, and template holds a valid FunctionTemplate.
187189
let wrapped = unsafe { jsg::wrap_resource(lock, resource, &mut template) };
188190
ctx.set_global("arr", wrapped);
189191

@@ -207,6 +209,7 @@ fn resource_returns_array() {
207209
_state: ResourceState::default(),
208210
});
209211
let mut template = ArrayResourceTemplate::new(lock);
212+
// SAFETY: Lock is valid, resource is a valid Ref, and template holds a valid FunctionTemplate.
210213
let wrapped = unsafe { jsg::wrap_resource(lock, resource, &mut template) };
211214
ctx.set_global("arr", wrapped);
212215

@@ -234,6 +237,7 @@ fn resource_accepts_typed_array_parameter() {
234237
_state: ResourceState::default(),
235238
});
236239
let mut template = ArrayResourceTemplate::new(lock);
240+
// SAFETY: Lock is valid, resource is a valid Ref, and template holds a valid FunctionTemplate.
237241
let wrapped = unsafe { jsg::wrap_resource(lock, resource, &mut template) };
238242
ctx.set_global("arr", wrapped);
239243

@@ -258,6 +262,7 @@ fn resource_returns_typed_array() {
258262
_state: ResourceState::default(),
259263
});
260264
let mut template = ArrayResourceTemplate::new(lock);
265+
// SAFETY: Lock is valid, resource is a valid Ref, and template holds a valid FunctionTemplate.
261266
let wrapped = unsafe { jsg::wrap_resource(lock, resource, &mut template) };
262267
ctx.set_global("arr", wrapped);
263268

@@ -280,6 +285,7 @@ fn resource_accepts_typed_array_slice_parameter() {
280285
_state: ResourceState::default(),
281286
});
282287
let mut template = ArrayResourceTemplate::new(lock);
288+
// SAFETY: Lock is valid, resource is a valid Ref, and template holds a valid FunctionTemplate.
283289
let wrapped = unsafe { jsg::wrap_resource(lock, resource, &mut template) };
284290
ctx.set_global("arr", wrapped);
285291

@@ -313,6 +319,7 @@ fn typed_array_slice_rejects_wrong_type() {
313319
_state: ResourceState::default(),
314320
});
315321
let mut template = ArrayResourceTemplate::new(lock);
322+
// SAFETY: Lock is valid, resource is a valid Ref, and template holds a valid FunctionTemplate.
316323
let wrapped = unsafe { jsg::wrap_resource(lock, resource, &mut template) };
317324
ctx.set_global("arr", wrapped);
318325

@@ -346,6 +353,7 @@ fn resource_accepts_and_returns_struct_array() {
346353
_state: ResourceState::default(),
347354
});
348355
let mut template = ArrayResourceTemplate::new(lock);
356+
// SAFETY: Lock is valid, resource is a valid Ref, and template holds a valid FunctionTemplate.
349357
let wrapped = unsafe { jsg::wrap_resource(lock, resource, &mut template) };
350358
ctx.set_global("arr", wrapped);
351359

@@ -597,6 +605,7 @@ fn typed_array_iter_uint8() {
597605
harness.run_in_context(|lock, _ctx| {
598606
let data: Vec<u8> = vec![10, 20, 30];
599607
let js_val = data.to_js(lock);
608+
// SAFETY: The isolate is locked and the FFI handle is from a valid eval result.
600609
let typed: jsg::v8::Local<'_, jsg::v8::Uint8Array> =
601610
unsafe { jsg::v8::Local::from_ffi(lock.isolate(), js_val.into_ffi()) };
602611

@@ -623,6 +632,7 @@ fn typed_array_into_iter_uint8() {
623632
harness.run_in_context(|lock, _ctx| {
624633
let data: Vec<u8> = vec![1, 2, 3, 4, 5];
625634
let js_val = data.to_js(lock);
635+
// SAFETY: The isolate is locked and the FFI handle is from a valid eval result.
626636
let typed: jsg::v8::Local<'_, jsg::v8::Uint8Array> =
627637
unsafe { jsg::v8::Local::from_ffi(lock.isolate(), js_val.into_ffi()) };
628638

@@ -639,6 +649,7 @@ fn typed_array_iter_int32() {
639649
harness.run_in_context(|lock, _ctx| {
640650
let data: Vec<i32> = vec![-100, 0, 100];
641651
let js_val = data.to_js(lock);
652+
// SAFETY: The isolate is locked and the FFI handle is from a valid eval result.
642653
let typed: jsg::v8::Local<'_, jsg::v8::Int32Array> =
643654
unsafe { jsg::v8::Local::from_ffi(lock.isolate(), js_val.into_ffi()) };
644655

@@ -660,6 +671,7 @@ fn typed_array_iter_reverse() {
660671
harness.run_in_context(|lock, _ctx| {
661672
let data: Vec<u8> = vec![1, 2, 3, 4];
662673
let js_val = data.to_js(lock);
674+
// SAFETY: The isolate is locked and the FFI handle is from a valid eval result.
663675
let typed: jsg::v8::Local<'_, jsg::v8::Uint8Array> =
664676
unsafe { jsg::v8::Local::from_ffi(lock.isolate(), js_val.into_ffi()) };
665677

@@ -676,6 +688,7 @@ fn typed_array_empty() {
676688
harness.run_in_context(|lock, _ctx| {
677689
let data: Vec<u8> = vec![];
678690
let js_val = data.to_js(lock);
691+
// SAFETY: The isolate is locked and the FFI handle is from a valid eval result.
679692
let typed: jsg::v8::Local<'_, jsg::v8::Uint8Array> =
680693
unsafe { jsg::v8::Local::from_ffi(lock.isolate(), js_val.into_ffi()) };
681694

@@ -699,6 +712,7 @@ fn float32_array_parameter_and_return() {
699712
_state: ResourceState::default(),
700713
});
701714
let mut template = ArrayResourceTemplate::new(lock);
715+
// SAFETY: Lock is valid, resource is a valid Ref, and template holds a valid FunctionTemplate.
702716
let wrapped = unsafe { jsg::wrap_resource(lock, resource, &mut template) };
703717
ctx.set_global("arr", wrapped);
704718

@@ -734,6 +748,7 @@ fn float32_array_slice_parameter() {
734748
_state: ResourceState::default(),
735749
});
736750
let mut template = ArrayResourceTemplate::new(lock);
751+
// SAFETY: Lock is valid, resource is a valid Ref, and template holds a valid FunctionTemplate.
737752
let wrapped = unsafe { jsg::wrap_resource(lock, resource, &mut template) };
738753
ctx.set_global("arr", wrapped);
739754

@@ -761,6 +776,7 @@ fn float32_array_rejects_wrong_type() {
761776
_state: ResourceState::default(),
762777
});
763778
let mut template = ArrayResourceTemplate::new(lock);
779+
// SAFETY: Lock is valid, resource is a valid Ref, and template holds a valid FunctionTemplate.
764780
let wrapped = unsafe { jsg::wrap_resource(lock, resource, &mut template) };
765781
ctx.set_global("arr", wrapped);
766782

@@ -829,6 +845,7 @@ fn float64_array_parameter_and_return() {
829845
_state: ResourceState::default(),
830846
});
831847
let mut template = ArrayResourceTemplate::new(lock);
848+
// SAFETY: Lock is valid, resource is a valid Ref, and template holds a valid FunctionTemplate.
832849
let wrapped = unsafe { jsg::wrap_resource(lock, resource, &mut template) };
833850
ctx.set_global("arr", wrapped);
834851

@@ -864,6 +881,7 @@ fn float64_array_slice_parameter() {
864881
_state: ResourceState::default(),
865882
});
866883
let mut template = ArrayResourceTemplate::new(lock);
884+
// SAFETY: Lock is valid, resource is a valid Ref, and template holds a valid FunctionTemplate.
867885
let wrapped = unsafe { jsg::wrap_resource(lock, resource, &mut template) };
868886
ctx.set_global("arr", wrapped);
869887

@@ -891,6 +909,7 @@ fn float64_array_rejects_wrong_type() {
891909
_state: ResourceState::default(),
892910
});
893911
let mut template = ArrayResourceTemplate::new(lock);
912+
// SAFETY: Lock is valid, resource is a valid Ref, and template holds a valid FunctionTemplate.
894913
let wrapped = unsafe { jsg::wrap_resource(lock, resource, &mut template) };
895914
ctx.set_global("arr", wrapped);
896915

@@ -946,6 +965,7 @@ fn bigint64_array_parameter_and_return() {
946965
_state: ResourceState::default(),
947966
});
948967
let mut template = ArrayResourceTemplate::new(lock);
968+
// SAFETY: Lock is valid, resource is a valid Ref, and template holds a valid FunctionTemplate.
949969
let wrapped = unsafe { jsg::wrap_resource(lock, resource, &mut template) };
950970
ctx.set_global("arr", wrapped);
951971

@@ -987,6 +1007,7 @@ fn bigint64_array_slice_parameter() {
9871007
_state: ResourceState::default(),
9881008
});
9891009
let mut template = ArrayResourceTemplate::new(lock);
1010+
// SAFETY: Lock is valid, resource is a valid Ref, and template holds a valid FunctionTemplate.
9901011
let wrapped = unsafe { jsg::wrap_resource(lock, resource, &mut template) };
9911012
ctx.set_global("arr", wrapped);
9921013

@@ -1014,6 +1035,7 @@ fn bigint64_array_rejects_wrong_type() {
10141035
_state: ResourceState::default(),
10151036
});
10161037
let mut template = ArrayResourceTemplate::new(lock);
1038+
// SAFETY: Lock is valid, resource is a valid Ref, and template holds a valid FunctionTemplate.
10171039
let wrapped = unsafe { jsg::wrap_resource(lock, resource, &mut template) };
10181040
ctx.set_global("arr", wrapped);
10191041

@@ -1068,6 +1090,7 @@ fn biguint64_array_parameter_and_return() {
10681090
_state: ResourceState::default(),
10691091
});
10701092
let mut template = ArrayResourceTemplate::new(lock);
1093+
// SAFETY: Lock is valid, resource is a valid Ref, and template holds a valid FunctionTemplate.
10711094
let wrapped = unsafe { jsg::wrap_resource(lock, resource, &mut template) };
10721095
ctx.set_global("arr", wrapped);
10731096

@@ -1103,6 +1126,7 @@ fn biguint64_array_slice_parameter() {
11031126
_state: ResourceState::default(),
11041127
});
11051128
let mut template = ArrayResourceTemplate::new(lock);
1129+
// SAFETY: Lock is valid, resource is a valid Ref, and template holds a valid FunctionTemplate.
11061130
let wrapped = unsafe { jsg::wrap_resource(lock, resource, &mut template) };
11071131
ctx.set_global("arr", wrapped);
11081132

@@ -1130,6 +1154,7 @@ fn biguint64_array_rejects_wrong_type() {
11301154
_state: ResourceState::default(),
11311155
});
11321156
let mut template = ArrayResourceTemplate::new(lock);
1157+
// SAFETY: Lock is valid, resource is a valid Ref, and template holds a valid FunctionTemplate.
11331158
let wrapped = unsafe { jsg::wrap_resource(lock, resource, &mut template) };
11341159
ctx.set_global("arr", wrapped);
11351160

0 commit comments

Comments
 (0)