Run Miri on profiling crates and fix miri issues + Introduce ddog_prof_Profile struct#235
Conversation
c59432d to
d873337
Compare
d873337 to
c152e1e
Compare
9b0ac37 to
5149101
Compare
581fb13 to
9d396eb
Compare
9d396eb to
90170f4
Compare
| // Leaving a null will help with double-free issues that can | ||
| // arise in C. Of course, it's best to never get there in the | ||
| // first place! | ||
| let raw = std::mem::replace(&mut self.inner, std::ptr::null_mut()); |
There was a problem hiding this comment.
since null is default, I think you can just std::mem::take here
There was a problem hiding this comment.
I tried that first, but trait Default is apparently not implmented for *mut _!
| /// The `profile` can be null, but if non-null it must point to a valid object | ||
| /// created by the Rust Global allocator. | ||
| /// The `profile` can be null, but if non-null it must point to a Profile | ||
| /// made by this module, which has not previously been dropped. |
There was a problem hiding this comment.
I like this comment better :)
ivoanjo
left a comment
There was a problem hiding this comment.
👍 LGTM, thanks for making our ffi safer and more strictly checked :)
| # We need to disable isolation because | ||
| # "unsupported operation: `clock_gettime` with `REALTIME` clocks not available when isolation is enabled" |
There was a problem hiding this comment.
❤️ for documenting this here :)
| const ddog_prof_Period period = {wall_time, 60}; | ||
| std::unique_ptr<ddog_prof_Profile, Deleter> profile{ | ||
| ddog_prof_Profile profile_data{ | ||
| ddog_prof_Profile_new(sample_types, &period, nullptr)}; | ||
| std::unique_ptr<ddog_prof_Profile, Deleter> profile{&profile_data}; |
There was a problem hiding this comment.
Minor: I wonder if such a simple example needs this kind of sophistication, e.g. maybe we could simplify this a bit?
There was a problem hiding this comment.
I just fixed it up for the changes I made ^_^
I get that in C++, they want to have destructors run, rather than doing it manually. But obviously the C bindings don't have destructors.
I think we can maybe simplify this code, or acknowledge that we care more about C++ and try to also generate C++ headers and bindings, or something.
| /// Resets all data except the sample types and period. Returns the | ||
| /// previous Profile on success. | ||
| pub fn reset(&mut self, start_time: Option<SystemTime>) -> Option<Profile> { | ||
| pub fn reset(&mut self, start_time: Option<SystemTime>) -> anyhow::Result<Profile> { |
There was a problem hiding this comment.
Minor: Is it still worth returning the old profile in this situation? As an API think, it's kinda weird -- when would we want to keep around the old profile after a reset?
There was a problem hiding this comment.
I need to get this release moving so let's talk about that for v5.0. I think originally I was hoping to do something like:
let old = profile.reset();
// owned, not borrowed
let pprof_profile = pprof::Profile::from(old);But that didn't work for whatever reason and forgot to revisit. Or may it's that since the structures don't match anymore (did at one time), there's not really value to take ownership of the profile::Profile, since it has to copy things anyway.
What does this PR do?
This PR is a followup to #225.
profilingandprofiling-ffi.While changing this code, we (DSN and Levi) felt it was better to make a few changes to make this easier to reason about safety:
ddog_prof_Profilestruct that wraps a pointer to the Rustdatadog_profiling::profile::Profileobject, and return this fromddog_prof_Profile_newinstead ofddog_prof_Profile*. This means you need to take the address for further operations e.g:ddog_prof_Profile_Resultfor errors which don't return anything on success, but return addog_Errorwhen they fail. These functions have had their return type changed to use this result, andddog_prof_Profile_UpscalingRuleAddResultandddog_prof_Profile_AddResultwere removed:ddog_prof_Profile_add(previouslyddog_prof_Profile_AddResult)ddog_prof_Profile_set_endpoint(previouslyvoid)ddog_prof_Profile_add_endpoint_count(previouslyvoid)ddog_prof_Profile_add_upscaling_rule_poisson(previouslyddog_prof_Profile_UpscalingRuleAddResult)ddog_prof_Profile_add_upscaling_rule_proportional(previouslyddog_prof_Profile_UpscalingRuleAddResult)ddog_prof_Profile_reset(previouslybool)Motivation
Miri is a great way to find UB. We shouldn't have UB we can prevent.
Additional Notes
There was a subtle stacked-borrows violation cause by the ffi destructor taking an
Option<&mut>instead of a*mut.https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=b3fb4e106c1d19183c831f38389f2658
shows how this plays out on a small example in the playground (use the tools/miri option to compare
failsvsdoesnt_fail.How to test the change?
Update your code to account for the C API changes, but semantically nothing changed, so existing tests should work otherwise.
For Reviewers
@DataDog/security-design-and-guidance.