Skip to main content

valgrind_requests/
lib.rs

1//! Idiomatic Rust bindings for [Valgrind's Client Request Mechanism][client-requests] with
2//! zero-indirection execution and zero-cost fallback.
3//!
4//!
5//! Valgrind has a trapdoor mechanism via which the client program can pass all manner of requests
6//! and queries to Valgrind and the current tool. The so-called client requests are provided to
7//! allow you to tell Valgrind facts about the behavior of your program, and also to make queries.
8//! In particular, your program can tell Valgrind about things that it otherwise would not know,
9//! leading to better results.
10//!
11//! # Installation/Building
12//!
13//! ```toml
14//! [dependencies]
15//! valgrind-requests = "1.0"
16//! ```
17//!
18//! or
19//!
20//! ```shell
21//! cargo add valgrind-requests
22//! ```
23//!
24//! `valgrind-requests` does not depend on any specific version of Valgrind. However, not all client
25//! requests are available in all Valgrind versions and this crate will abort the execution
26//! producing a panic message if a client request is used but not available in the header
27//! file.
28//!
29//! The client requests need to be built with the Valgrind header files. Usually, these header files
30//! are installed by your distribution's package manager with the Valgrind package into a global
31//! include path, and you don't need to do anything. Note that the used headers need to match the
32//! used Valgrind version.
33//!
34//! If you encounter problems because the Valgrind header files cannot be found, first ensure you
35//! have installed Valgrind and your package manager's package includes the header files. If not or
36//! you use a custom build of Valgrind, you can point the `VALGRIND_REQUESTS_VALGRIND_INCLUDE` or
37//! the `VALGRIND_REQUESTS_<triple>_VALGRIND_INCLUDE` environment variables to the include path
38//! where the Valgrind headers can be found. For example, if the Valgrind header files reside in
39//! `/home/foo/repo/valgrind/{valgrind.h, callgrind.h, ...}`, then the environment variable has to
40//! point to `VALGRIND_REQUESTS_VALGRIND_INCLUDE=/home/foo/repo` and not
41//! `VALGRIND_REQUESTS_VALGRIND_INCLUDE=/home/foo/repo/valgrind`.
42//!
43//! # Module Organization
44//!
45//! The client requests are organized into modules representing the source header file. So, if you
46//! search for a client request originating from the `valgrind.h` header file, the client request
47//! can be found in the [`valgrind`] module. `valgrind-requests` is a complete implementation of all
48//! client requests which can be found in the original header files.
49//!
50//! | Module | Header | Description |
51//! | ------ | ------ | ----------- |
52//! | [`valgrind`] | `valgrind.h` | Core client requests ([The Client request mechanism][client-requests]) |
53//! | [`memcheck`] | `memcheck.h` | [Memcheck: a memory error detector][memcheck-docs] |
54//! | [`callgrind`] | `callgrind.h` | [Callgrind: a call-graph generating cache and branch prediction profiler][callgrind-docs] |
55//! | [`cachegrind`] | `cachegrind.h` | [Cachegrind: a high-precision tracing profiler][cachegrind-docs] |
56//! | [`helgrind`] | `helgrind.h` | [Helgrind: a thread error detector][helgrind-docs] |
57//! | [`drd`] | `drd.h` | [DRD: a thread error detector][drd-docs] |
58//! | [`dhat`] | `dhat.h` | [DHAT: a dynamic heap analysis tool][dhat-docs] |
59//!
60//! Instead of using macros like in Valgrind we're using functions and small letter names, stripping
61//! the prefix if it is equal to the enclosing module. For example the client request
62//! `RUNNING_ON_VALGRIND` from the `valgrind.h` file equals [`valgrind::running_on_valgrind`]
63//! and `VALGRIND_COUNT_ERRORS` from the same `valgrind.h` header file equals
64//! [`valgrind::count_errors`].
65//!
66//! The only exception to this rule are the [`valgrind_printf`] macro and its descendants like
67//! [`valgrind_printf_unchecked`] which can be found in the crate root.
68//!
69//! # Features
70//!
71//! Core client request APIs are `no_std` compatible. The `std` feature which implies the `alloc`
72//! feature are enabled by default.
73//!
74//! This crate provides two execution feature levels:
75//!
76//! - **`act`** *(default)*: Enables actual execution of client requests when running under
77//!   Valgrind. Implies `stubs`.
78//! - **`stubs`**: Enables the same public API surface and build-time code generation, but all
79//!   client requests compile to no-ops that return default values. The compiler will optimize them
80//!   away entirely, making this a zero-cost option suitable for production code.
81//!
82//! Formatting convenience macros such as [`valgrind_printf`] and [`valgrind_println`] require the
83//! **`alloc`** feature because they allocate owned C strings. In allocation-free builds, you can
84//! use [`valgrind_print`] or [`valgrind_print_backtrace`] instead.
85//!
86//! To use the zero-cost fallback, for example if you want to use the client requests for tests or
87//! benchmarks and need to make annotations in production code:
88//!
89//! ```toml
90//! [dependencies]
91//! valgrind-requests = { version = "1.0", default-features = false, features = ["stubs"] }
92//!
93//! [dev-dependencies]
94//! valgrind-requests = { version = "1.0" }
95//! ```
96//!
97//! The stubs compile down to nothing and your production code is as performant as without any
98//! annotations. If your production code uses the formatting convenience macros, enable both `stubs`
99//! and `alloc` with `features = ["stubs", "alloc"]`.
100//!
101//! # Performance and implementation details
102//!
103//! If possible, client requests execute with zero indirection and the same overhead as the original
104//! Valgrind C macros usable [even in high performance code][client-requests]. On
105//! Valgrind-supported platforms for which zero-indirection isn't implemented by us, a native C FFI
106//! binding is used which introduces at least an additional frame on the stack and the costs for the
107//! function call. That means all targets covered by Valgrind are also covered by
108//! `valgrind-requests`. Targets not supported by Valgrind produce a compile error.
109//!
110//! | Target               | Zero-indirection | Notes                                         |
111//! | -------------------- | ---------------- | --------------------------------------------- |
112//! | `x86_64/linux`       | yes              | -                                             |
113//! | `x86_64/android`     | yes              | except the x32 ABI                            |
114//! | `x86_64/freebsd`     | yes              | -                                             |
115//! | `x86_64/macos`       | yes              | the versions supported by Valgrind            |
116//! | `x86_64/windows+gnu` | yes              | -                                             |
117//! | `x86_64/solaris`     | yes              | -                                             |
118//! | `x86/linux`          | yes              | -                                             |
119//! | `x86/android`        | yes              | -                                             |
120//! | `x86/freebsd`        | yes              | -                                             |
121//! | `x86/macos`          | yes              | the versions supported by Valgrind            |
122//! | `x86/windows+gnu`    | yes              | -                                             |
123//! | `x86/solaris`        | yes              | -                                             |
124//! | `arm/linux`          | yes              | -                                             |
125//! | `arm/android`        | yes              | -                                             |
126//! | `aarch64/linux`      | yes              | -                                             |
127//! | `aarch64/android`    | yes              | -                                             |
128//! | `aarch64/freebsd`    | yes              | -                                             |
129//! | `aarch64/macos`      | yes              | [LouisBrunner/valgrind-macos][valgrind-macos] |
130//! | `riscv64/linux`      | yes              | -                                             |
131//! | `s390x/linux`        | yes              | -                                             |
132//! | `powerpc/linux`      | yes              | rust >= 1.95.0                                |
133//! | `powerpc64/linux`    | yes              | rust >= 1.95.0                                |
134//! | `powerpc64le/linux`  | yes              | rust >= 1.95.0                                |
135//! | `mips32/linux`       | no               | no rust inline assembly available             |
136//! | `mips64/linux`       | no               | no rust inline assembly available             |
137//! | `nanomips/linux`     | no               | no zero-indirection planned                   |
138//! | `x86/windows+msvc`   | no               | no zero-indirection planned                   |
139//!
140//! To disable the native C FFI binding as fallback you can set the environment variable
141//! `VALGRIND_REQUESTS_STRATEGY=strict` (possible values are: `strict`, `fallback`).
142//!
143//! # Sources and additional documentation
144//!
145//! A lot of the library documentation of the client requests within this module and its submodules
146//! is taken from the online manual and the Valgrind header files. For more details see also [The
147//! Client Request mechanism][client-requests]
148//!
149//! [callgrind-docs]:
150//!     https://valgrind.org/docs/manual/cl-manual.html#cl-manual.clientrequests
151//! [cachegrind-docs]:
152//!     https://valgrind.org/docs/manual/cg-manual.html#cg-manual.clientrequests
153//! [client-requests]:
154//!     https://valgrind.org/docs/manual/manual-core-adv.html#manual-core-adv.clientreq
155//! [dhat-docs]: https://valgrind.org/docs/manual/dh-manual.html
156//! [drd-docs]:
157//!     https://valgrind.org/docs/manual/drd-manual.html#drd-manual.clientreqs
158//! [helgrind-docs]:
159//!     https://valgrind.org/docs/manual/hg-manual.html#hg-manual.client-requests
160//! [memcheck-docs]:
161//!     https://valgrind.org/docs/manual/mc-manual.html#mc-manual.clientreqs
162//! [valgrind-macos]: https://github.com/LouisBrunner/valgrind-macos
163
164#![cfg_attr(docsrs, feature(doc_cfg))]
165#![doc(test(attr(warn(unused))))]
166#![doc(test(attr(allow(unused_extern_crates))))]
167#![cfg_attr(not(feature = "std"), no_std)]
168#![expect(clippy::arbitrary_source_item_ordering)]
169
170#[cfg(feature = "alloc")]
171#[doc(hidden)]
172pub extern crate alloc as __alloc;
173#[cfg(feature = "std")]
174extern crate std;
175
176#[cfg(not(feature = "stubs"))]
177compile_error!("valgrind-requests requires either the `stubs` or `act` feature");
178
179/// Returns `true` if a client request is defined and available in the used Valgrind version.
180///
181/// For internal use only!
182///
183/// We do this check to avoid incompatibilities with older Valgrind versions which might not have
184/// all client requests available we're offering.
185///
186/// We're only using constant values known at compile time, which the compiler will finally optimize
187/// away, so this macro costs us nothing.
188macro_rules! is_def {
189    ($user_req:path) => {{ $user_req as cty::c_uint > 0x1000 }};
190}
191
192/// The macro which uses [`valgrind_do_client_request_stmt`] or [`valgrind_do_client_request_expr`]
193/// to execute the client request.
194///
195/// For internal use only!
196///
197/// This macro has two forms: The first takes 7 arguments `name, request, arg1, ..., arg5` and
198/// returns `()`. The expanded macro of this form calls [`valgrind_do_client_request_stmt`]. The
199/// second first has 8 arguments `name, default, request, arg1, ..., arg5` returning a `usize`. The
200/// expanded macro of this form calls [`valgrind_do_client_request_expr`].
201///
202/// Both forms will raise a [`fatal_error`] in case the [`is_def`] macro returns false.
203macro_rules! do_client_request {
204    ($name:literal, $request:path, $arg1:expr, $arg2:expr, $arg3:expr, $arg4:expr, $arg5:expr) => {{
205        if is_def!($request) {
206            valgrind_do_client_request_stmt(
207                $request as cty::c_uint,
208                $arg1,
209                $arg2,
210                $arg3,
211                $arg4,
212                $arg5,
213            );
214        } else {
215            fatal_error($name);
216        }
217    }};
218    (
219        $name:literal,
220        $default:expr,
221        $request:path,
222        $arg1:expr,
223        $arg2:expr,
224        $arg3:expr,
225        $arg4:expr,
226        $arg5:expr
227    ) => {{
228        if is_def!($request) {
229            valgrind_do_client_request_expr(
230                $default,
231                $request as cty::c_uint,
232                $arg1,
233                $arg2,
234                $arg3,
235                $arg4,
236                $arg5,
237            )
238        } else {
239            fatal_error($name);
240        }
241    }};
242}
243
244/// Convenience macro to create a `\0`-byte terminated `alloc::ffi::CString` from a literal string
245///
246/// This macro requires the `alloc` feature. In allocation-free builds, use [`valgrind_print`]
247/// instead.
248///
249/// The string literal passed to this macro must not contain or end with a `\0`-byte. If you need a
250/// checked version of `alloc::ffi::CString` you can use `alloc::ffi::CString::new`.
251///
252/// # Safety
253///
254/// This macro is unsafe but convenient and efficient. It is your responsibility to ensure that the
255/// input string literal does not contain any `\0` bytes.
256#[cfg(feature = "alloc")]
257#[macro_export]
258macro_rules! cstring {
259    ($string:literal) => {{
260        $crate::__alloc::ffi::CString::from_vec_with_nul_unchecked(
261            concat!($string, "\0").as_bytes().to_vec(),
262        )
263    }};
264}
265
266/// Convenience macro to create a `\0`-byte terminated `alloc::ffi::CString` from a format string
267///
268/// This macro requires the `alloc` feature. In allocation-free builds, use [`valgrind_print`]
269/// instead.
270///
271/// The format string passed to this macro must not contain or end with a `\0`-byte.
272///
273/// # Safety
274///
275/// The same safety conditions as to the [`cstring`] macro apply here
276#[cfg(feature = "alloc")]
277#[macro_export]
278macro_rules! format_cstring {
279    ($($args:tt)*) => {{
280        $crate::__alloc::ffi::CString::from_vec_with_nul_unchecked(
281            $crate::__alloc::format!("{}\0", format_args!($($args)*)).into_bytes()
282        )
283    }};
284}
285
286cfg_if! {
287    if #[cfg(feature = "act")] {
288        /// Prints to the Valgrind log.
289        ///
290        /// This macro requires the `alloc` feature. In allocation-free builds, use
291        /// [`valgrind_print`] instead.
292        ///
293        /// This macro is a safe variant of the `VALGRIND_PRINTF` function, checking for `\0` bytes
294        /// in the formatting string. However, if you're sure there are no `\0` bytes present you
295        /// can safely use [`crate::valgrind_printf_unchecked`] which performs better compared to
296        /// this macro.
297        #[cfg(feature = "alloc")]
298        #[macro_export]
299        macro_rules! valgrind_printf {
300            ($($args:tt)*) => {{
301                match $crate::__alloc::ffi::CString::from_vec_with_nul(
302                    $crate::__alloc::format!("{}\0", format_args!($($args)*)).into_bytes()
303                ) {
304                    Ok(c_string) => {
305                        unsafe {
306                            $crate::__valgrind_print(
307                                c_string.as_ptr()
308                            );
309                        }
310                        Ok(())
311                    },
312                    Err(error) => Err(
313                        $crate::error::ClientRequestError::from(error)
314                    )
315                }
316            }};
317        }
318
319        /// Prints to the Valgrind log.
320        ///
321        /// This macro requires the `alloc` feature. In allocation-free builds, use
322        /// [`valgrind_print`] instead.
323        ///
324        /// Use this macro only if you are sure there are no `\0`-bytes in the formatted string. If
325        /// unsure use the safe [`crate::valgrind_printf`] variant.
326        ///
327        /// This variant performs better than [`crate::valgrind_printf`].
328        #[cfg(feature = "alloc")]
329        #[macro_export]
330        macro_rules! valgrind_printf_unchecked {
331            ($($args:tt)*) => {{
332                let string = $crate::__alloc::format!("{}\0", format_args!($($args)*));
333                $crate::__valgrind_print(
334                    string.as_ptr() as *const $crate::__cty::c_char
335                );
336            }};
337        }
338
339        /// Prints to the Valgrind log ending with a newline.
340        ///
341        /// This macro requires the `alloc` feature. In allocation-free builds, use
342        /// [`valgrind_print`] instead.
343        ///
344        /// See also [`crate::valgrind_printf`]
345        #[cfg(feature = "alloc")]
346        #[macro_export]
347        macro_rules! valgrind_println {
348            () => { $crate::valgrind_printf!("\n") };
349            ($($arg:tt)*) => {{
350                match $crate::__alloc::ffi::CString::from_vec_with_nul(
351                    $crate::__alloc::format!("{}\n\0", format_args!($($arg)*)).into_bytes()
352                ) {
353                    Ok(c_string) => {
354                        unsafe {
355                            $crate::__valgrind_print(
356                                c_string.as_ptr()
357                            );
358                        }
359                        Ok(())
360                    },
361                    Err(error) => Err(
362                        $crate::error::ClientRequestError::from(error)
363                    )
364                }
365            }};
366        }
367
368        /// Prints to the Valgrind log ending with a newline.
369        ///
370        /// This macro requires the `alloc` feature. In allocation-free builds, use
371        /// [`valgrind_print`] instead.
372        ///
373        /// See also [`crate::valgrind_printf_unchecked`]
374        #[cfg(feature = "alloc")]
375        #[macro_export]
376        macro_rules! valgrind_println_unchecked {
377            () => { $crate::valgrind_printf_unchecked!("\n") };
378            ($($args:tt)*) => {{
379                let string = $crate::__alloc::format!("{}\n\0", format_args!($($args)*));
380                $crate::__valgrind_print(
381                    string.as_ptr() as *const $crate::__cty::c_char
382                );
383            }};
384        }
385
386        /// Prints to the Valgrind log with a backtrace.
387        ///
388        /// This macro requires the `alloc` feature. In allocation-free builds, use
389        /// [`valgrind_print_backtrace`] instead.
390        ///
391        /// See also [`crate::valgrind_printf`]
392        #[cfg(feature = "alloc")]
393        #[macro_export]
394        macro_rules! valgrind_printf_backtrace {
395            ($($arg:tt)*) => {{
396                match $crate::__alloc::ffi::CString::from_vec_with_nul(
397                    $crate::__alloc::format!("{}\0", format_args!($($arg)*)).into_bytes()
398                ) {
399                    Ok(c_string) => {
400                        unsafe {
401                            $crate::__valgrind_print_backtrace(
402                                c_string.as_ptr()
403                            );
404                        }
405                        Ok(())
406                    },
407                    Err(error) => Err(
408                        $crate::error::ClientRequestError::from(error)
409                    )
410                }
411            }};
412        }
413
414        /// Prints to the Valgrind log with a backtrace.
415        ///
416        /// This macro requires the `alloc` feature. In allocation-free builds, use
417        /// [`valgrind_print_backtrace`] instead.
418        ///
419        /// See also [`crate::valgrind_printf_unchecked`]
420        #[cfg(feature = "alloc")]
421        #[macro_export]
422        macro_rules! valgrind_printf_backtrace_unchecked {
423            ($($arg:tt)*) => {{
424                let string = $crate::__alloc::format!("{}\0", format_args!($($arg)*));
425                $crate::__valgrind_print_backtrace(
426                    string.as_ptr() as *const $crate::__cty::c_char
427                );
428            }};
429        }
430
431        /// Prints to the Valgrind log with a backtrace, ending the formatted string with a newline.
432        ///
433        /// This macro requires the `alloc` feature. In allocation-free builds, use
434        /// [`valgrind_print_backtrace`] instead.
435        ///
436        /// See also [`crate::valgrind_printf`]
437        #[cfg(feature = "alloc")]
438        #[macro_export]
439        macro_rules! valgrind_println_backtrace {
440            () => { $crate::valgrind_printf_backtrace!("\n") };
441            ($($arg:tt)*) => {{
442                match $crate::__alloc::ffi::CString::from_vec_with_nul(
443                    $crate::__alloc::format!("{}\n\0", format_args!($($arg)*)).into_bytes()
444                ) {
445                    Ok(c_string) => {
446                        unsafe {
447                            $crate::__valgrind_print_backtrace(
448                                c_string.as_ptr()
449                            );
450                        }
451                        Ok(())
452                    },
453                    Err(error) => Err(
454                        $crate::error::ClientRequestError::from(error)
455                    )
456                }
457            }};
458        }
459
460        /// Prints to the Valgrind log with a backtrace, ending the formatted string with a newline.
461        ///
462        /// This macro requires the `alloc` feature. In allocation-free builds, use
463        /// [`valgrind_print_backtrace`] instead.
464        ///
465        /// See also [`crate::valgrind_printf_unchecked`]
466        #[cfg(feature = "alloc")]
467        #[macro_export]
468        macro_rules! valgrind_println_backtrace_unchecked {
469            () => { $crate::valgrind_printf_backtrace_unchecked!("\n") };
470            ($($arg:tt)*) => {{
471                let string = $crate::__alloc::format!("{}\n\0", format_args!($($arg)*));
472                unsafe {
473                    $crate::__valgrind_print_backtrace(
474                        string.as_ptr() as *const $crate::__cty::c_char
475                    );
476                }
477            }};
478        }
479    } else {
480        /// No-op variant of [`valgrind_printf`] for stub builds.
481        ///
482        /// This macro requires the `alloc` feature to preserve the same fallible API as the active
483        /// formatting macro. In allocation-free builds, use [`valgrind_print`] instead.
484        ///
485        /// This macro is a safe variant of the `VALGRIND_PRINTF` function, checking for `\0` bytes
486        /// in the formatting string. However, if you're sure there are no `\0` bytes present you
487        /// can safely use [`crate::valgrind_printf_unchecked`] which performs better compared to
488        /// this macro.
489        #[cfg(feature = "alloc")]
490        #[macro_export]
491        macro_rules! valgrind_printf {
492            ($($arg:tt)*) => {{
493                let res: Result<(), $crate::error::ClientRequestError> = Ok(());
494                res
495            }};
496        }
497
498        /// No-op variant of [`valgrind_printf_unchecked`] for stub builds.
499        ///
500        /// This macro requires the `alloc` feature. In allocation-free builds, use
501        /// [`valgrind_print`] instead.
502        ///
503        /// Use this macro only if you are sure there are no `\0`-bytes in the formatted string. If
504        /// unsure use the safe [`crate::valgrind_printf`] variant.
505        ///
506        /// This variant performs better than [`crate::valgrind_printf`].
507        #[cfg(feature = "alloc")]
508        #[macro_export]
509        macro_rules! valgrind_printf_unchecked {
510            ($($arg:tt)*) => {{ $crate::__no_op() }};
511        }
512
513        /// No-op variant of [`valgrind_println`] for stub builds.
514        ///
515        /// This macro requires the `alloc` feature. In allocation-free builds, use
516        /// [`valgrind_print`] instead.
517        ///
518        /// See also [`crate::valgrind_printf`]
519        #[cfg(feature = "alloc")]
520        #[macro_export]
521        macro_rules! valgrind_println {
522            ($($arg:tt)*) => {{
523                let res: Result<(), $crate::error::ClientRequestError> = Ok(());
524                res
525            }};
526        }
527
528        /// No-op variant of [`valgrind_println_unchecked`] for stub builds.
529        ///
530        /// This macro requires the `alloc` feature. In allocation-free builds, use
531        /// [`valgrind_print`] instead.
532        ///
533        /// See also [`crate::valgrind_printf_unchecked`]
534        #[cfg(feature = "alloc")]
535        #[macro_export]
536        macro_rules! valgrind_println_unchecked {
537            ($($arg:tt)*) => {{ $crate::__no_op() }};
538        }
539
540        /// No-op variant of [`valgrind_printf_backtrace`] for stub builds.
541        ///
542        /// This macro requires the `alloc` feature. In allocation-free builds, use
543        /// [`valgrind_print_backtrace`] instead.
544        ///
545        /// See also [`crate::valgrind_printf`]
546        #[cfg(feature = "alloc")]
547        #[macro_export]
548        macro_rules! valgrind_printf_backtrace {
549            ($($arg:tt)*) => {{
550                let res: Result<(), $crate::error::ClientRequestError> = Ok(());
551                res
552            }};
553        }
554
555        /// No-op variant of [`valgrind_printf_backtrace_unchecked`] for stub builds.
556        ///
557        /// This macro requires the `alloc` feature. In allocation-free builds, use
558        /// [`valgrind_print_backtrace`] instead.
559        ///
560        /// See also [`crate::valgrind_printf_unchecked`]
561        #[cfg(feature = "alloc")]
562        #[macro_export]
563        macro_rules! valgrind_printf_backtrace_unchecked {
564            ($($arg:tt)*) => {{ $crate::__no_op() }};
565        }
566
567        /// No-op variant of [`valgrind_println_backtrace`] for stub builds.
568        ///
569        /// This macro requires the `alloc` feature. In allocation-free builds, use
570        /// [`valgrind_print_backtrace`] instead.
571        ///
572        /// See also [`crate::valgrind_printf`]
573        #[cfg(feature = "alloc")]
574        #[macro_export]
575        macro_rules! valgrind_println_backtrace {
576            ($($arg:tt)*) => {{
577                let res: Result<(), $crate::error::ClientRequestError> = Ok(());
578                res
579            }};
580        }
581
582        /// No-op variant of [`valgrind_println_backtrace_unchecked`] for stub builds.
583        ///
584        /// This macro requires the `alloc` feature. In allocation-free builds, use
585        /// [`valgrind_print_backtrace`] instead.
586        ///
587        /// See also [`crate::valgrind_printf_unchecked`]
588        #[cfg(feature = "alloc")]
589        #[macro_export]
590        macro_rules! valgrind_println_backtrace_unchecked {
591            ($($arg:tt)*) => {{ $crate::__no_op() }};
592        }
593    }
594}
595
596mod arch;
597mod bindings;
598pub mod cachegrind;
599pub mod callgrind;
600pub mod dhat;
601pub mod drd;
602#[cfg(feature = "alloc")]
603pub mod error;
604pub mod helgrind;
605pub mod memcheck;
606#[cfg(feature = "act")]
607mod native_bindings;
608pub mod valgrind;
609use core::ffi::CStr;
610
611use arch::imp::valgrind_do_client_request_expr;
612use arch::valgrind_do_client_request_stmt;
613use cfg_if::cfg_if;
614#[doc(hidden)]
615pub use cty as __cty;
616
617/// The `ThreadId` is used by some client requests to represent the `tid` which Valgrind uses or
618/// returns
619///
620/// This type has no relationship to `std::thread::ThreadId`!
621pub type ThreadId = usize;
622
623/// The `StackId` is used and returned by some client requests and represents an id on Valgrind's
624/// stack
625pub type StackId = usize;
626
627/// The raw file descriptor number
628///
629/// This type has no relationship to the standard library type definition of `RawFd` besides they
630/// are wrapping the same type on unix systems.
631pub type RawFd = cty::c_int;
632
633/// Valgrind's version number from the `valgrind.h` file
634///
635/// Note that the version numbers were introduced at Valgrind version 3.6 and so would not exist in
636/// version 3.5 or earlier. `VALGRIND_VERSION` is None is this case, else it is a tuple `(MAJOR,
637/// MINOR)`
638pub const VALGRIND_VERSION: Option<(u32, u32)> = {
639    if bindings::VR_VALGRIND_MAJOR == 0 {
640        None
641    } else {
642        Some((bindings::VR_VALGRIND_MAJOR, bindings::VR_VALGRIND_MINOR))
643    }
644};
645
646fn fatal_error(func: &str) -> ! {
647    if let Some((major, minor)) = VALGRIND_VERSION {
648        panic!(
649            "{0}: FATAL: {0}::{func} not available! To be able to use this client request, a \
650             newer Valgrind version is required. The detected Valgrind version of the \
651             `valgrind.h` header file is {major}.{minor}. Aborting...",
652            module_path!(),
653        );
654    } else {
655        panic!(
656            "{0}: FATAL: {0}::{func} not available! The Valgrind headers could not be found or \
657             the Valgrind version is too old. Check your Valgrind installation or set \
658             VALGRIND_REQUESTS_VALGRIND_INCLUDE to the Valgrind include path. Aborting...",
659            module_path!(),
660        );
661    }
662}
663
664cfg_if! {
665    if #[cfg(feature = "act")] {
666        /// Prints a C string to the Valgrind log.
667        ///
668        /// This function is the allocation-free equivalent of [`valgrind_printf_unchecked`]. It
669        /// accepts any value that can be borrowed as a [`CStr`], so it can be used in `no_std`
670        /// builds without the `alloc` feature. The stub implementation of this function is a no-op
671        /// and compiles away.
672        ///
673        /// The provided string must be NUL-terminated and must not contain interior NUL bytes, as
674        /// required by [`CStr`].
675        ///
676        /// # Examples
677        ///
678        /// ```rust
679        /// valgrind_requests::valgrind_print(c"hello from Valgrind\n");
680        /// ```
681        #[inline]
682        pub fn valgrind_print<T>(c_string: T)
683        where
684            T: AsRef<CStr>,
685        {
686            // SAFETY: `CStr` guarantees a valid NUL-terminated byte sequence for the duration of
687            // the call.
688            unsafe { __valgrind_print(c_string.as_ref().as_ptr()) }
689        }
690
691        /// Prints a C string with a backtrace to the Valgrind log.
692        ///
693        /// This function is the allocation-free equivalent of
694        /// [`valgrind_printf_backtrace_unchecked`]. It accepts any value that can be borrowed as a
695        /// [`CStr`], so it can be used in `no_std` builds without the `alloc` feature. The stub
696        /// implementation of this function is a no-op and compiles away.
697        ///
698        /// The provided string must be NUL-terminated and must not contain interior NUL bytes, as
699        /// required by [`CStr`].
700        ///
701        /// # Examples
702        ///
703        /// ```rust
704        /// valgrind_requests::valgrind_print_backtrace(c"important checkpoint\n");
705        /// ```
706        #[inline]
707        pub fn valgrind_print_backtrace<T>(c_string: T)
708        where
709            T: AsRef<CStr>,
710        {
711            // SAFETY: `CStr` guarantees a valid NUL-terminated byte sequence for the duration of
712            // the call.
713            unsafe { __valgrind_print_backtrace(c_string.as_ref().as_ptr()) }
714        }
715    } else {
716        /// No-op variant of [`valgrind_print`] for stub builds.
717        ///
718        /// This function preserves the same allocation-free API surface as active builds and
719        /// compiles away entirely.
720        #[inline]
721        pub fn valgrind_print<T>(_c_string: T)
722        where
723            T: AsRef<CStr>,
724        {}
725
726        /// No-op variant of [`valgrind_print_backtrace`] for stub builds.
727        ///
728        /// This function preserves the same allocation-free API surface as active builds and
729        /// compiles away entirely.
730        #[inline]
731        pub fn valgrind_print_backtrace<T>(_c_string: T)
732        where
733            T: AsRef<CStr>,
734        {}
735    }
736}
737
738#[cfg(feature = "act")]
739#[doc(hidden)]
740#[inline(always)]
741pub unsafe fn __valgrind_print(ptr: *const cty::c_char) {
742    // SAFETY: The safety of this function must be ensured by the caller
743    unsafe {
744        native_bindings::valgrind_printf(ptr);
745    }
746}
747
748#[cfg(feature = "act")]
749#[doc(hidden)]
750#[inline(always)]
751pub unsafe fn __valgrind_print_backtrace(ptr: *const cty::c_char) {
752    // SAFETY: The safety of this function must be ensured by the caller
753    unsafe {
754        native_bindings::valgrind_printf_backtrace(ptr);
755    }
756}
757
758#[doc(hidden)]
759#[inline(always)]
760pub unsafe fn __no_op() {}