Skip to main content

valgrind_requests/
drd.rs

1// Copyright (C) 2006-2020 Bart Van Assche <bvanassche@acm.org>.
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions
6// are met:
7//
8// 1. Redistributions of source code must retain the above copyright
9// notice, this list of conditions and the following disclaimer.
10//
11// 2. The origin of this software must not be misrepresented; you must
12// not claim that you wrote the original software.  If you use this
13// software in a product, an acknowledgment in the product
14// documentation would be appreciated but is not required.
15//
16// 3. Altered source versions must be plainly marked as such, and must
17// not be misrepresented as being the original software.
18//
19// 4. The name of the author may not be used to endorse or promote
20// products derived from this software without specific prior written
21// permission.
22//
23// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
24// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26// ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
27// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
29// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
31// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34//
35// ----------------------------------------------------------------
36//
37// We're using a lot of the original documentation from the `drd.h` header file with some
38// small adjustments, so above is the original license from `drd.h` file.
39//
40// This file is distributed under the same License as the rest of `valgrind-requests`.
41//
42// ----------------------------------------------------------------
43//
44//! All public client requests from the `drd.h` header file
45//!
46//! The client requests which do nothing or are not implemented (as of valgrind version 3.22) are
47//! not available.
48//!
49//! See also [DRD Client
50//! Requests](https://valgrind.org/docs/manual/drd-manual.html#drd-manual.clientreqs)
51use core::ffi::CStr;
52
53use super::{
54    bindings, fatal_error, helgrind, valgrind_do_client_request_expr,
55    valgrind_do_client_request_stmt,
56};
57
58/// Obtain the thread ID assigned by Valgrind's core
59///
60/// Valgrind's thread ID's start at one and are recycled in case a thread stops.
61#[inline(always)]
62pub fn get_valgrind_threadid() -> usize {
63    do_client_request!(
64        "drd::get_valgrind_threadid",
65        0,
66        bindings::VR_DRDClientRequest::VR_DRD_GET_VALGRIND_THREAD_ID,
67        0,
68        0,
69        0,
70        0,
71        0
72    )
73}
74
75/// Obtain the thread ID assigned by DRD
76///
77/// These are the thread ID's reported by DRD in data race reports and in trace messages. DRD's
78/// thread ID's start at one and are never recycled.
79#[inline(always)]
80pub fn get_drd_threadid() -> usize {
81    do_client_request!(
82        "drd::get_drd_threadid",
83        0,
84        bindings::VR_DRDClientRequest::VR_DRD_GET_DRD_THREAD_ID,
85        0,
86        0,
87        0,
88        0,
89        0
90    )
91}
92
93/// Tell DRD not to complain about data races for the specified variable
94///
95/// Some applications contain intentional races. There exist e.g. applications where the same value
96/// is assigned to a shared variable from two different threads. It may be more convenient to
97/// suppress such races than to solve these. This client request allows one to suppress such races.
98#[inline(always)]
99pub fn ignore_var<T>(var: &T) {
100    do_client_request!(
101        "drd::ignore_var",
102        bindings::VR_DRDClientRequest::VR_DRD_START_SUPPRESSION,
103        core::ptr::from_ref::<T>(var) as usize,
104        core::mem::size_of::<T>(),
105        0,
106        0,
107        0
108    );
109}
110
111/// Tell DRD to no longer ignore data races for the specified variable that was suppressed via
112/// [`ignore_var`]
113#[inline(always)]
114pub fn stop_ignoring_var<T>(var: &T) {
115    do_client_request!(
116        "drd::stop_ignoring_var",
117        bindings::VR_DRDClientRequest::VR_DRD_FINISH_SUPPRESSION,
118        core::ptr::from_ref::<T>(var) as usize,
119        core::mem::size_of::<T>(),
120        0,
121        0,
122        0
123    );
124}
125
126/// Tell DRD to trace all memory accesses for the specified variable until the memory that was
127/// allocated for the variable is freed.
128///
129/// When DRD reports a data race on a specified variable, and it's not immediately clear which
130/// source code statements triggered the conflicting accesses, it can be very helpful to trace all
131/// activity on the offending memory location.
132#[inline(always)]
133pub fn trace_var<T>(var: &T) {
134    do_client_request!(
135        "drd::trace_var",
136        bindings::VR_DRDClientRequest::VR_DRD_START_TRACE_ADDR,
137        core::ptr::from_ref::<T>(var) as usize,
138        core::mem::size_of::<T>(),
139        0,
140        0,
141        0
142    );
143}
144
145/// Tell DRD to stop tracing memory accesses for the specified variable
146#[inline(always)]
147pub fn stop_tracing_var<T>(var: &T) {
148    do_client_request!(
149        "drd::stop_tracing_var",
150        bindings::VR_DRDClientRequest::VR_DRD_STOP_TRACE_ADDR,
151        core::ptr::from_ref::<T>(var) as usize,
152        core::mem::size_of::<T>(),
153        0,
154        0,
155        0
156    );
157}
158
159/// Create completely arbitrary happens-before edges between threads
160///
161/// See [`super::helgrind::annotate_happens_before`]
162#[inline(always)]
163pub fn annotate_happens_before(obj: *const ()) {
164    helgrind::annotate_happens_before(obj);
165}
166
167/// See [`super::helgrind::annotate_happens_before`]
168#[inline(always)]
169pub fn annotate_happens_after(obj: *const ()) {
170    helgrind::annotate_happens_after(obj);
171}
172
173/// Report that a lock has just been created at address `lock`
174///
175/// See [`super::helgrind::annotate_rwlock_create`]
176#[inline(always)]
177pub fn annotate_rwlock_create(lock: *const ()) {
178    helgrind::annotate_rwlock_create(lock);
179}
180
181/// Report that the lock at address `lock` is about to be destroyed
182///
183/// See [`super::helgrind::annotate_rwlock_create`]
184#[inline(always)]
185pub fn annotate_rwlock_destroy(lock: *const ()) {
186    helgrind::annotate_rwlock_destroy(lock);
187}
188
189/// Report that the lock at address `lock` has just been acquired
190///
191/// See also [`super::helgrind::annotate_rwlock_create`]
192#[inline(always)]
193pub fn annotate_rwlock_acquired(lock: *const (), is_writer_lock: bool) {
194    helgrind::annotate_rwlock_acquired(lock, is_writer_lock);
195}
196
197/// Report that the lock at address `lock` is about to be released
198///
199/// See also [`super::helgrind::annotate_rwlock_create`]
200#[inline(always)]
201pub fn annotate_rwlock_released(lock: *const (), is_writer_lock: bool) {
202    helgrind::annotate_rwlock_released(lock, is_writer_lock);
203}
204
205/// Tell DRD that a semaphore object is going to be initialized.
206#[inline(always)]
207pub fn annotate_sem_init_pre(sem: *const (), value: usize) {
208    do_client_request!(
209        "drd::annotate_sem_init_pre",
210        bindings::VR_DRDClientRequest::VR_DRD_ANNOTATE_SEM_INIT_PRE,
211        sem as usize,
212        value,
213        0,
214        0,
215        0
216    );
217}
218
219/// Tell DRD that a semaphore object has been destroyed.
220#[inline(always)]
221pub fn annotate_sem_destroy_post(sem: *const ()) {
222    do_client_request!(
223        "drd::annotate_sem_destroy_post",
224        bindings::VR_DRDClientRequest::VR_DRD_ANNOTATE_SEM_DESTROY_POST,
225        sem as usize,
226        0,
227        0,
228        0,
229        0
230    );
231}
232
233/// Tell DRD that a semaphore is going to be acquired.
234#[inline(always)]
235pub fn annotate_sem_wait_pre(sem: *const ()) {
236    do_client_request!(
237        "drd::annotate_sem_wait_pre",
238        bindings::VR_DRDClientRequest::VR_DRD_ANNOTATE_SEM_WAIT_PRE,
239        sem as usize,
240        0,
241        0,
242        0,
243        0
244    );
245}
246
247/// Tell DRD that a semaphore has been acquired.
248#[inline(always)]
249pub fn annotate_sem_wait_post(sem: *const ()) {
250    do_client_request!(
251        "drd::annotate_sem_wait_post",
252        bindings::VR_DRDClientRequest::VR_DRD_ANNOTATE_SEM_WAIT_POST,
253        sem as usize,
254        0,
255        0,
256        0,
257        0
258    );
259}
260
261/// Tell DRD that a semaphore is going to be released.
262#[inline(always)]
263pub fn annotate_sem_post_pre(sem: *const ()) {
264    do_client_request!(
265        "drd::annotate_sem_post_pre",
266        bindings::VR_DRDClientRequest::VR_DRD_ANNOTATE_SEM_POST_PRE,
267        sem as usize,
268        0,
269        0,
270        0,
271        0
272    );
273}
274
275/// Tell DRD that data races at the specified address are expected and must not be reported
276///
277/// Any races detected on the specified variable are benign and hence should not be reported.
278#[inline(always)]
279pub fn annotate_benign_race<T>(addr: &T) {
280    do_client_request!(
281        "drd::annotate_benign_race",
282        bindings::VR_DRDClientRequest::VR_DRD_START_SUPPRESSION,
283        core::ptr::from_ref::<T>(addr) as usize,
284        core::mem::size_of::<T>(),
285        0,
286        0,
287        0
288    );
289}
290
291/// Same as [`annotate_benign_race`], but applies to the memory range [addr, addr + size).
292///
293/// Any races detected on the specified variable are benign and hence should not be reported.
294#[inline(always)]
295pub fn annotate_benign_race_sized<T>(addr: &T, size: usize) {
296    do_client_request!(
297        "drd::annotate_benign_race_sized",
298        bindings::VR_DRDClientRequest::VR_DRD_START_SUPPRESSION,
299        core::ptr::from_ref::<T>(addr) as usize,
300        size,
301        0,
302        0,
303        0
304    );
305}
306
307/// Tell DRD to ignore all reads performed by the current thread
308#[inline(always)]
309pub fn annotate_ignore_reads_begin() {
310    do_client_request!(
311        "drd::annotate_ignore_reads_begin",
312        bindings::VR_DRDClientRequest::VR_DRD_RECORD_LOADS,
313        0,
314        0,
315        0,
316        0,
317        0
318    );
319}
320
321/// Tell DRD to no longer ignore the reads performed by the current thread.
322#[inline(always)]
323pub fn annotate_ignore_reads_end() {
324    do_client_request!(
325        "drd::annotate_ignore_reads_end",
326        bindings::VR_DRDClientRequest::VR_DRD_RECORD_LOADS,
327        1,
328        0,
329        0,
330        0,
331        0
332    );
333}
334
335/// Tell DRD to ignore all writes performed by the current thread.
336#[inline(always)]
337pub fn annotate_ignore_writes_begin() {
338    do_client_request!(
339        "drd::annotate_ignore_writes_begin",
340        bindings::VR_DRDClientRequest::VR_DRD_RECORD_STORES,
341        0,
342        0,
343        0,
344        0,
345        0
346    );
347}
348
349/// Tell DRD to no longer ignore the writes performed by the current thread.
350#[inline(always)]
351pub fn annotate_ignore_writes_end() {
352    do_client_request!(
353        "drd::annotate_ignore_writes_end",
354        bindings::VR_DRDClientRequest::VR_DRD_RECORD_STORES,
355        1,
356        0,
357        0,
358        0,
359        0
360    );
361}
362
363/// Tell DRD to ignore all memory accesses performed by the current thread.
364#[inline(always)]
365pub fn annotate_ignore_reads_and_writes_begin() {
366    annotate_ignore_reads_begin();
367    annotate_ignore_writes_begin();
368}
369
370/// Tell DRD to no longer ignore the memory accesses performed by the current thread.
371#[inline(always)]
372pub fn annotate_ignore_reads_and_writes_end() {
373    annotate_ignore_reads_end();
374    annotate_ignore_writes_end();
375}
376
377/// Tell DRD that size bytes starting at addr has been allocated by a custom memory allocator
378#[inline(always)]
379pub fn annotate_new_memory(addr: *const (), size: usize) {
380    do_client_request!(
381        "drd::annotate_new_memory",
382        bindings::VR_DRDClientRequest::VR_DRD_CLEAN_MEMORY,
383        addr as usize,
384        size,
385        0,
386        0,
387        0
388    );
389}
390
391/// Ask DRD to report every access to the specified address
392///
393/// Trace all load and store activity that touches at least the single byte at the address `addr`.
394#[inline(always)]
395pub fn annotate_trace_memory(addr: *const ()) {
396    do_client_request!(
397        "drd::annotate_trace_memory",
398        bindings::VR_DRDClientRequest::VR_DRD_START_TRACE_ADDR,
399        addr as usize,
400        core::mem::size_of::<cty::c_char>(),
401        0,
402        0,
403        0
404    );
405}
406
407/// Tell DRD to assign the specified name to the current thread.
408///
409/// This name will be used in error messages printed by DRD.
410#[inline(always)]
411pub fn annotate_thread_name<T>(name: T)
412where
413    T: AsRef<CStr>,
414{
415    do_client_request!(
416        "drd::annotate_thread_name",
417        bindings::VR_DRDClientRequest::VR_DRD_SET_THREAD_NAME,
418        name.as_ref().as_ptr() as usize,
419        0,
420        0,
421        0,
422        0
423    );
424}