Skip to content

Commit dabf0dc

Browse files
authored
Merge pull request #111 from TheBlueMatt/2023-07-0.0.115-aliasing-fix
[0.0.115] Fix strict-aliasing violation on traits holding inner fields
2 parents 316ba2b + f337fb2 commit dabf0dc

File tree

5 files changed

+32
-21
lines changed

5 files changed

+32
-21
lines changed

.github/workflows/build.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ jobs:
4040
git checkout 0.0.115-bindings
4141
- name: Fix Github Actions to not be broken
4242
run: git config --global --add safe.directory /__w/ldk-c-bindings/ldk-c-bindings
43+
- name: Pin proc-macro and quote to meet MSRV
44+
run: |
45+
cd c-bindings-gen
46+
cargo update -p quote --precise "1.0.30" --verbose
47+
cargo update -p proc-macro2 --precise "1.0.65" --verbose
4348
- name: Rebuild bindings without std, and check the sample app builds + links
4449
run: ./genbindings.sh ./rust-lightning false
4550
- name: Rebuild bindings, and check the sample app builds + links

c-bindings-gen/src/main.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -351,10 +351,10 @@ fn writeln_trait<'a, 'b, W: std::io::Write>(w: &mut W, t: &'a syn::ItemTrait, ty
351351
// the Rust type and a flag to indicate whether deallocation needs to
352352
// happen) as well as provide an Option<>al function pointer which is
353353
// called when the trait method is called which allows updating on the fly.
354-
write!(w, "\tpub {}: ", m.sig.ident).unwrap();
355-
generated_fields.push((format!("{}", m.sig.ident), None, None));
354+
write!(w, "\tpub {}: core::cell::UnsafeCell<", m.sig.ident).unwrap();
355+
generated_fields.push((format!("{}", m.sig.ident), Some(("Clone::clone(unsafe { &*core::cell::UnsafeCell::get(".to_owned(), ")}).into()")), None));
356356
types.write_c_type(w, &*r.elem, Some(&meth_gen_types), false);
357-
writeln!(w, ",").unwrap();
357+
writeln!(w, ">,").unwrap();
358358
writeln!(w, "\t/// Fill in the {} field as a reference to it will be given to Rust after this returns", m.sig.ident).unwrap();
359359
writeln!(w, "\t/// Note that this takes a pointer to this object, not the this_ptr like other methods do").unwrap();
360360
writeln!(w, "\t/// This function pointer may be NULL if {} is filled in when this object is created and never needs updating.", m.sig.ident).unwrap();
@@ -430,7 +430,7 @@ fn writeln_trait<'a, 'b, W: std::io::Write>(w: &mut W, t: &'a syn::ItemTrait, ty
430430
let is_clonable = types.is_clonable(s);
431431
writeln!(w, "\tpub {}: crate::{},", i, s).unwrap();
432432
(format!("{}", i), if !is_clonable {
433-
Some(format!("crate::{}_clone_fields", s))
433+
Some((format!("crate::{}_clone_fields(", s), ")"))
434434
} else { None }, None)
435435
});
436436
}
@@ -513,7 +513,7 @@ fn writeln_trait<'a, 'b, W: std::io::Write>(w: &mut W, t: &'a syn::ItemTrait, ty
513513
writeln!(w, "\t\t\t(f)(&self{});", $impl_accessor).unwrap();
514514
write!(w, "\t\t}}\n\t\t").unwrap();
515515
$type_resolver.write_from_c_conversion_to_ref_prefix(w, &*r.elem, Some(&meth_gen_types));
516-
write!(w, "self{}.{}", $impl_accessor, m.sig.ident).unwrap();
516+
write!(w, "unsafe {{ &*self{}.{}.get() }}", $impl_accessor, m.sig.ident).unwrap();
517517
$type_resolver.write_from_c_conversion_to_ref_suffix(w, &*r.elem, Some(&meth_gen_types));
518518
writeln!(w, "\n\t}}").unwrap();
519519
continue;
@@ -557,9 +557,9 @@ fn writeln_trait<'a, 'b, W: std::io::Write>(w: &mut W, t: &'a syn::ItemTrait, ty
557557
writeln!(w, "\t{} {{", trait_name).unwrap();
558558
writeln!(w, "\t\tthis_arg: orig.this_arg,").unwrap();
559559
for (field, clone_fn, _) in generated_fields.iter() {
560-
if let Some(f) = clone_fn {
560+
if let Some((pfx, sfx)) = clone_fn {
561561
// If the field isn't clonable, blindly assume its a trait and hope for the best.
562-
writeln!(w, "\t\t{}: {}(&orig.{}),", field, f, field).unwrap();
562+
writeln!(w, "\t\t{}: {}&orig.{}{},", field, pfx, field, sfx).unwrap();
563563
} else {
564564
writeln!(w, "\t\t{}: Clone::clone(&orig.{}),", field, field).unwrap();
565565
}
@@ -1046,7 +1046,7 @@ fn writeln_impl<W: std::io::Write>(w: &mut W, w_uses: &mut HashSet<String, NonRa
10461046
if let syn::Type::Reference(r) = &**rtype {
10471047
write!(w, "\n\t\t{}{}: ", $indent, $m.sig.ident).unwrap();
10481048
types.write_empty_rust_val(Some(&gen_types), w, &*r.elem);
1049-
writeln!(w, ",\n{}\t\tset_{}: Some({}_{}_set_{}),", $indent, $m.sig.ident, ident, $trait.ident, $m.sig.ident).unwrap();
1049+
writeln!(w, ".into(),\n{}\t\tset_{}: Some({}_{}_set_{}),", $indent, $m.sig.ident, ident, $trait.ident, $m.sig.ident).unwrap();
10501050
printed = true;
10511051
}
10521052
}
@@ -1198,9 +1198,9 @@ fn writeln_impl<W: std::io::Write>(w: &mut W, w_uses: &mut HashSet<String, NonRa
11981198
writeln!(w, "\t// This is a bit race-y in the general case, but for our specific use-cases today, we're safe").unwrap();
11991199
writeln!(w, "\t// Specifically, we must ensure that the first time we're called it can never be in parallel").unwrap();
12001200
write!(w, "\tif ").unwrap();
1201-
$types.write_empty_rust_val_check(Some(&meth_gen_types), w, &*r.elem, &format!("trait_self_arg.{}", $m.sig.ident));
1201+
$types.write_empty_rust_val_check(Some(&meth_gen_types), w, &*r.elem, &format!("unsafe {{ &*trait_self_arg.{}.get() }}", $m.sig.ident));
12021202
writeln!(w, " {{").unwrap();
1203-
writeln!(w, "\t\tunsafe {{ &mut *(trait_self_arg as *const {} as *mut {}) }}.{} = {}_{}_{}(trait_self_arg.this_arg);", $trait.ident, $trait.ident, $m.sig.ident, ident, $trait.ident, $m.sig.ident).unwrap();
1203+
writeln!(w, "\t\t*unsafe {{ &mut *(&*(trait_self_arg as *const {})).{}.get() }} = {}_{}_{}(trait_self_arg.this_arg).into();", $trait.ident, $m.sig.ident, ident, $trait.ident, $m.sig.ident).unwrap();
12041204
writeln!(w, "\t}}").unwrap();
12051205
writeln!(w, "}}").unwrap();
12061206
}

genbindings.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,13 +231,19 @@ cbindgen -v --config cbindgen.toml -o include/lightning.h >/dev/null 2>&1
231231
if is_gnu_sed; then
232232
sed -i 's/typedef LDKnative.*Import.*LDKnative.*;//g' include/lightning.h
233233

234+
# UnsafeCell is `repr(transparent)` so should be ignored here
235+
sed -i 's/LDKUnsafeCell<\(.*\)> /\1 /g' include/lightning.h
236+
234237
# stdlib.h doesn't exist in clang's wasm sysroot, and cbindgen
235238
# doesn't actually use it anyway, so drop the import.
236239
sed -i 's/#include <stdlib.h>/#include "ldk_rust_types.h"/g' include/lightning.h
237240
else
238241
# OSX sed is for some reason not compatible with GNU sed
239242
sed -i '' 's/typedef LDKnative.*Import.*LDKnative.*;//g' include/lightning.h
240243

244+
# UnsafeCell is `repr(transparent)` so should be ignored by cbindgen
245+
sed -i '' 's/LDKUnsafeCell<\(.*\)> /\1 /g' include/lightning.h
246+
241247
# stdlib.h doesn't exist in clang's wasm sysroot, and cbindgen
242248
# doesn't actually use it anyway, so drop the import.
243249
sed -i '' 's/#include <stdlib.h>/#include "ldk_rust_types.h"/g' include/lightning.h

lightning-c-bindings/include/lightning.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7884,7 +7884,7 @@ typedef struct LDKChannelSigner {
78847884
/**
78857885
* Returns the holder's channel public keys and basepoints.
78867886
*/
7887-
struct LDKChannelPublicKeys pubkeys;
7887+
LDKChannelPublicKeys pubkeys;
78887888
/**
78897889
* Fill in the pubkeys field as a reference to it will be given to Rust after this returns
78907890
* Note that this takes a pointer to this object, not the this_ptr like other methods do

lightning-c-bindings/src/lightning/chain/keysinterface.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -629,7 +629,7 @@ pub struct ChannelSigner {
629629
#[must_use]
630630
pub validate_holder_commitment: extern "C" fn (this_arg: *const c_void, holder_tx: &crate::lightning::ln::chan_utils::HolderCommitmentTransaction, preimages: crate::c_types::derived::CVec_PaymentPreimageZ) -> crate::c_types::derived::CResult_NoneNoneZ,
631631
/// Returns the holder's channel public keys and basepoints.
632-
pub pubkeys: crate::lightning::ln::chan_utils::ChannelPublicKeys,
632+
pub pubkeys: core::cell::UnsafeCell<crate::lightning::ln::chan_utils::ChannelPublicKeys>,
633633
/// Fill in the pubkeys field as a reference to it will be given to Rust after this returns
634634
/// Note that this takes a pointer to this object, not the this_ptr like other methods do
635635
/// This function pointer may be NULL if pubkeys is filled in when this object is created and never needs updating.
@@ -662,7 +662,7 @@ pub(crate) extern "C" fn ChannelSigner_clone_fields(orig: &ChannelSigner) -> Cha
662662
get_per_commitment_point: Clone::clone(&orig.get_per_commitment_point),
663663
release_commitment_secret: Clone::clone(&orig.release_commitment_secret),
664664
validate_holder_commitment: Clone::clone(&orig.validate_holder_commitment),
665-
pubkeys: Clone::clone(&orig.pubkeys),
665+
pubkeys: Clone::clone(unsafe { &*core::cell::UnsafeCell::get(&orig.pubkeys)}).into(),
666666
set_pubkeys: Clone::clone(&orig.set_pubkeys),
667667
channel_keys_id: Clone::clone(&orig.channel_keys_id),
668668
provide_channel_parameters: Clone::clone(&orig.provide_channel_parameters),
@@ -690,7 +690,7 @@ impl rustChannelSigner for ChannelSigner {
690690
if let Some(f) = self.set_pubkeys {
691691
(f)(&self);
692692
}
693-
self.pubkeys.get_native_ref()
693+
unsafe { &*self.pubkeys.get() }.get_native_ref()
694694
}
695695
fn channel_keys_id(&self) -> [u8; 32] {
696696
let mut ret = (self.channel_keys_id)(self.this_arg);
@@ -889,7 +889,7 @@ impl lightning::chain::keysinterface::ChannelSigner for EcdsaChannelSigner {
889889
if let Some(f) = self.ChannelSigner.set_pubkeys {
890890
(f)(&self.ChannelSigner);
891891
}
892-
self.ChannelSigner.pubkeys.get_native_ref()
892+
unsafe { &*self.ChannelSigner.pubkeys.get() }.get_native_ref()
893893
}
894894
fn channel_keys_id(&self) -> [u8; 32] {
895895
let mut ret = (self.ChannelSigner.channel_keys_id)(self.ChannelSigner.this_arg);
@@ -1066,7 +1066,7 @@ impl lightning::chain::keysinterface::ChannelSigner for WriteableEcdsaChannelSig
10661066
if let Some(f) = self.EcdsaChannelSigner.ChannelSigner.set_pubkeys {
10671067
(f)(&self.EcdsaChannelSigner.ChannelSigner);
10681068
}
1069-
self.EcdsaChannelSigner.ChannelSigner.pubkeys.get_native_ref()
1069+
unsafe { &*self.EcdsaChannelSigner.ChannelSigner.pubkeys.get() }.get_native_ref()
10701070
}
10711071
fn channel_keys_id(&self) -> [u8; 32] {
10721072
let mut ret = (self.EcdsaChannelSigner.ChannelSigner.channel_keys_id)(self.EcdsaChannelSigner.ChannelSigner.this_arg);
@@ -1761,7 +1761,7 @@ pub extern "C" fn InMemorySigner_as_ChannelSigner(this_arg: &InMemorySigner) ->
17611761
release_commitment_secret: InMemorySigner_ChannelSigner_release_commitment_secret,
17621762
validate_holder_commitment: InMemorySigner_ChannelSigner_validate_holder_commitment,
17631763

1764-
pubkeys: crate::lightning::ln::chan_utils::ChannelPublicKeys { inner: core::ptr::null_mut(), is_owned: true },
1764+
pubkeys: crate::lightning::ln::chan_utils::ChannelPublicKeys { inner: core::ptr::null_mut(), is_owned: true }.into(),
17651765
set_pubkeys: Some(InMemorySigner_ChannelSigner_set_pubkeys),
17661766
channel_keys_id: InMemorySigner_ChannelSigner_channel_keys_id,
17671767
provide_channel_parameters: InMemorySigner_ChannelSigner_provide_channel_parameters,
@@ -1793,8 +1793,8 @@ extern "C" fn InMemorySigner_ChannelSigner_pubkeys(this_arg: *const c_void) -> c
17931793
extern "C" fn InMemorySigner_ChannelSigner_set_pubkeys(trait_self_arg: &ChannelSigner) {
17941794
// This is a bit race-y in the general case, but for our specific use-cases today, we're safe
17951795
// Specifically, we must ensure that the first time we're called it can never be in parallel
1796-
if trait_self_arg.pubkeys.inner.is_null() {
1797-
unsafe { &mut *(trait_self_arg as *const ChannelSigner as *mut ChannelSigner) }.pubkeys = InMemorySigner_ChannelSigner_pubkeys(trait_self_arg.this_arg);
1796+
if unsafe { &*trait_self_arg.pubkeys.get() }.inner.is_null() {
1797+
*unsafe { &mut *(&*(trait_self_arg as *const ChannelSigner)).pubkeys.get() } = InMemorySigner_ChannelSigner_pubkeys(trait_self_arg.this_arg).into();
17981798
}
17991799
}
18001800
#[must_use]
@@ -1839,7 +1839,7 @@ pub extern "C" fn InMemorySigner_as_EcdsaChannelSigner(this_arg: &InMemorySigner
18391839
release_commitment_secret: InMemorySigner_ChannelSigner_release_commitment_secret,
18401840
validate_holder_commitment: InMemorySigner_ChannelSigner_validate_holder_commitment,
18411841

1842-
pubkeys: crate::lightning::ln::chan_utils::ChannelPublicKeys { inner: core::ptr::null_mut(), is_owned: true },
1842+
pubkeys: crate::lightning::ln::chan_utils::ChannelPublicKeys { inner: core::ptr::null_mut(), is_owned: true }.into(),
18431843
set_pubkeys: Some(InMemorySigner_ChannelSigner_set_pubkeys),
18441844
channel_keys_id: InMemorySigner_ChannelSigner_channel_keys_id,
18451845
provide_channel_parameters: InMemorySigner_ChannelSigner_provide_channel_parameters,
@@ -1939,7 +1939,7 @@ pub extern "C" fn InMemorySigner_as_WriteableEcdsaChannelSigner(this_arg: &InMem
19391939
release_commitment_secret: InMemorySigner_ChannelSigner_release_commitment_secret,
19401940
validate_holder_commitment: InMemorySigner_ChannelSigner_validate_holder_commitment,
19411941

1942-
pubkeys: crate::lightning::ln::chan_utils::ChannelPublicKeys { inner: core::ptr::null_mut(), is_owned: true },
1942+
pubkeys: crate::lightning::ln::chan_utils::ChannelPublicKeys { inner: core::ptr::null_mut(), is_owned: true }.into(),
19431943
set_pubkeys: Some(InMemorySigner_ChannelSigner_set_pubkeys),
19441944
channel_keys_id: InMemorySigner_ChannelSigner_channel_keys_id,
19451945
provide_channel_parameters: InMemorySigner_ChannelSigner_provide_channel_parameters,

0 commit comments

Comments
 (0)