Skip to main content

relibc/
macros.rs

1/// Print to stdout
2#[macro_export]
3macro_rules! print {
4    ($($arg:tt)*) => {{
5        use core::fmt::Write;
6        let _ = $crate::platform::FileWriter::new(1).write_fmt(format_args!($($arg)*));
7    }};
8}
9
10/// Print with new line to stdout.
11/// Deprecated, consider using log::info instead
12#[macro_export]
13macro_rules! println {
14    () => {
15        $crate::print!("\n")
16    };
17    ($($arg:tt)*) => {
18        $crate::print!("{}\n", format_args!($($arg)*))
19    };
20}
21
22/// Print to stderr
23#[macro_export]
24macro_rules! eprint {
25    ($($arg:tt)*) => {{
26        use core::fmt::Write;
27        let _ = $crate::platform::FileWriter::new(2).write_fmt(format_args!($($arg)*));
28    }};
29}
30
31/// Print with new line to stderr.
32/// Deprecated, consider using log::info instead
33#[macro_export]
34macro_rules! eprintln {
35    () => {
36        $crate::eprint!("\n")
37    };
38    ($($arg:tt)*) => {
39        $crate::eprint!("{}\n", format_args!($($arg)*))
40    };
41}
42
43pub const ISSUE_URL: &str = "https://gitlab.redox-os.org/redox-os/relibc/-/issues/";
44
45// Skippable todo!(issue, fmt)
46#[macro_export]
47macro_rules! todo_skip {
48    ($issue:expr, $($arg:tt)*) => {
49        if $issue != 0 {
50            log::info!("TODO ({}{}): {}", $crate::macros::ISSUE_URL, $issue, format_args!($($arg)*))
51        } else {
52            log::info!("TODO: {}", format_args!($($arg)*))
53        }
54    };
55}
56
57// Recoverable error todo!(issue, fmt, err)
58#[macro_export]
59macro_rules! todo_error {
60    ($issue:expr, $err:expr, $($arg:tt)*) => {
61        if $issue != 0 {
62            log::error!("TODO ({}{}): {}: {}", $crate::macros::ISSUE_URL, $issue, format_args!($($arg)*), $err)
63        } else {
64            log::error!("TODO: {}: {:?}", format_args!($($arg)*), $err)
65        }
66    };
67}
68
69// Unrecoverable error todo!(issue, fmt)
70#[macro_export]
71macro_rules! todo_panic {
72    ($issue:expr, $($arg:tt)*) => {
73        if $issue != 0 {
74            todo!("{} ({}{})", format_args!($($arg)*), $crate::macros::ISSUE_URL, $issue)
75        } else {
76            todo!("{}", format_args!($($arg)*))
77        }
78    };
79}
80
81#[macro_export]
82#[cfg(feature = "no_trace")]
83macro_rules! trace_expr {
84    ($expr:expr, $($arg:tt)*) => {
85        $expr
86    };
87}
88
89#[macro_export]
90#[cfg(not(feature = "no_trace"))]
91macro_rules! trace_expr {
92    ($expr:expr, $($arg:tt)*) => ({
93        use $crate::header::errno::STR_ERROR;
94        use $crate::platform;
95
96        log::trace!("{}", format_args!($($arg)*));
97
98        let trace_old_errno = platform::ERRNO.get();
99        platform::ERRNO.set(0);
100
101        let ret = $expr;
102
103        let trace_errno = platform::ERRNO.get() as isize;
104        if trace_errno == 0 {
105            platform::ERRNO.set(trace_old_errno);
106        }
107
108        let trace_strerror = if trace_errno >= 0 && trace_errno < STR_ERROR.len() as isize {
109            STR_ERROR[trace_errno as usize]
110        } else {
111            "Unknown error"
112        };
113
114        log::trace!("{} = {} ({}, {})", format_args!($($arg)*), ret, trace_errno, trace_strerror);
115
116        ret
117    });
118}
119
120#[macro_export]
121macro_rules! skipws {
122    ($ptr:expr) => {
123        while isspace(unsafe { *$ptr }) != 0 {
124            $ptr = unsafe { $ptr.add(1) };
125        }
126    };
127}
128
129#[macro_export]
130macro_rules! wcsto_impl {
131    ($type:ident, $ptr:expr, $base:expr) => {{
132        let has_minus = unsafe { *$ptr } == '-' as wchar_t;
133        let has_plus = unsafe { *$ptr } == '+' as wchar_t;
134        if has_minus || has_plus {
135            $ptr = unsafe { $ptr.add(1) };
136        }
137
138        let type_is_signed = $type::MIN != 0;
139
140        let mut base = $base;
141
142        if (base == 16 || base == 0)
143            && unsafe { *$ptr } == '0' as wchar_t
144            && (unsafe { *$ptr.add(1) } == 'x' as wchar_t
145                || unsafe { *$ptr.add(1) } == 'X' as wchar_t)
146        {
147            $ptr = unsafe { $ptr.add(2) };
148            base = 16;
149        }
150
151        if base == 0 {
152            base = if unsafe { *$ptr } == '0' as wchar_t {
153                8
154            } else {
155                10
156            };
157        };
158
159        let mut result: $type = 0;
160        while let Some(digit) =
161            char::from_u32(unsafe { *$ptr } as u32).and_then(|c| c.to_digit(base as u32))
162        {
163            let new = result.checked_mul(base as $type).and_then(|result| {
164                if has_minus && type_is_signed {
165                    #[cfg(target_arch = "x86")]
166                    {
167                        result.checked_sub(
168                            $type::try_from(digit).expect("single digit never overflows"),
169                        )
170                    }
171                    #[cfg(not(target_arch = "x86"))]
172                    {
173                        result.checked_sub($type::from(digit))
174                    }
175                } else {
176                    #[cfg(target_arch = "x86")]
177                    {
178                        result.checked_add(
179                            $type::try_from(digit).expect("single digit never overflows"),
180                        )
181                    }
182                    #[cfg(not(target_arch = "x86"))]
183                    {
184                        result.checked_add($type::from(digit))
185                    }
186                }
187            });
188            result = match new {
189                Some(new) => new,
190                None => {
191                    platform::ERRNO.set(ERANGE);
192                    return !0;
193                }
194            };
195
196            $ptr = unsafe { $ptr.add(1) };
197        }
198        if has_minus && !type_is_signed {
199            result = $type::MAX - result + 1;
200        }
201        result
202    }};
203}
204
205#[macro_export]
206macro_rules! strto_impl {
207    // this variant is used by inttypes and stdlib
208    (
209        $rettype:ty, $signed:expr, $maxval:expr, $minval:expr, $s:ident, $endptr:ident, $base:ident
210    ) => {{
211        // ensure these are constants
212        const CHECK_SIGN: bool = $signed;
213        const MAX_VAL: $rettype = $maxval;
214        const MIN_VAL: $rettype = $minval;
215
216        let set_endptr = |idx: isize| {
217            if !$endptr.is_null() {
218                // This is stupid, but apparently strto* functions want
219                // const input but mut output, yet the man page says
220                // "stores the address of the first invalid character in *endptr"
221                // so obviously it doesn't want us to clone it.
222                unsafe {
223                    *$endptr = $s.offset(idx).cast_mut();
224                }
225            }
226        };
227
228        let invalid_input = || {
229            platform::ERRNO.set(EINVAL);
230            set_endptr(0);
231        };
232
233        // only valid bases are 2 through 36
234        if $base != 0 && !(2..=36).contains(&$base) {
235            invalid_input();
236            return 0;
237        }
238
239        let mut idx = 0;
240
241        // skip any whitespace at the beginning of the string
242        while ctype::isspace(c_int::from(unsafe { *$s.offset(idx) })) != 0 {
243            idx += 1;
244        }
245
246        // check for +/-
247        let positive = match is_positive(unsafe { *$s.offset(idx) }) {
248            Some((pos, i)) => {
249                idx += i;
250                pos
251            }
252            None => {
253                invalid_input();
254                return 0;
255            }
256        };
257
258        // convert the string to a number
259        let num_str = unsafe { $s.offset(idx) };
260        let res = match $base {
261            0 => unsafe { detect_base(num_str) }.and_then(|($base, i)| {
262                idx += i;
263                unsafe { convert_integer(num_str.offset(i), $base) }
264            }),
265            8 => unsafe { convert_octal(num_str) },
266            16 => unsafe { convert_hex(num_str) },
267            _ => unsafe { convert_integer(num_str, $base) },
268        };
269
270        // check for error parsing octal/hex prefix
271        // also check to ensure a number was indeed parsed
272        let (num, i, overflow) = match res {
273            Some(res) => res,
274            None => {
275                invalid_input();
276                return 0;
277            }
278        };
279        idx += i;
280
281        let overflow = if CHECK_SIGN {
282            overflow || (num as c_long).is_negative()
283        } else {
284            overflow
285        };
286        // account for the sign
287        let num = num as $rettype;
288        let num = if overflow {
289            platform::ERRNO.set(ERANGE);
290            if CHECK_SIGN {
291                if positive { MAX_VAL } else { MIN_VAL }
292            } else {
293                MAX_VAL
294            }
295        } else {
296            if positive {
297                num
298            } else {
299                // not using -num to keep the compiler happy
300                num.overflowing_neg().0
301            }
302        };
303
304        set_endptr(idx);
305
306        num
307    }};
308}
309
310#[macro_export]
311macro_rules! strto_float_impl {
312    ($type:ident, $s:expr, $endptr:expr) => {{
313        let mut s = $s;
314        let endptr = $endptr;
315
316        while ctype::isspace(c_int::from(unsafe{*s})) != 0 {
317            s = unsafe{ s.offset(1)};
318        }
319
320        let mut result: $type = 0.0;
321        let mut exponent: Option<$type> = None;
322        let mut radix = 10;
323
324        let result_sign = match unsafe{*s} as u8 {
325            b'-' => {
326                s = unsafe{s.offset(1)};
327                -1.0
328            }
329            b'+' => {
330                s = unsafe{s.offset(1)};
331                1.0
332            }
333            _ => 1.0,
334        };
335
336        let rust_s = unsafe{CStr::from_ptr(s)}.to_string_lossy();
337
338        // detect NaN, Inf
339        if rust_s.to_lowercase().starts_with("inf") {
340            result = $type::INFINITY;
341            s = unsafe{s.offset(3)};
342        } else if rust_s.to_lowercase().starts_with("nan") {
343            // we cannot signal negative NaN in LLVM backed languages
344            // https://github.com/rust-lang/rust/issues/73328 , https://github.com/rust-lang/rust/issues/81261
345            result = $type::NAN;
346            s = unsafe{s.offset(3)};
347        } else {
348            if unsafe{*s} as u8 == b'0' && unsafe{*s.offset(1)} as u8 == b'x' {
349                s = unsafe{s.offset(2)};
350                radix = 16;
351            }
352
353            while let Some(digit) = (unsafe{*s} as u8 as char).to_digit(radix) {
354                result *= radix as $type;
355                result += digit as $type;
356                s = unsafe{s.offset(1)};
357            }
358
359            if unsafe{*s} as u8 == b'.' {
360                s = unsafe{s.offset(1)};
361
362                let mut i = 1.0;
363                while let Some(digit) = (unsafe{*s} as u8 as char).to_digit(radix) {
364                    i *= radix as $type;
365                    result += digit as $type / i;
366                    s = unsafe{s.offset(1)};
367                }
368            }
369
370            let s_before_exponent = s;
371
372            exponent = match (unsafe{*s} as u8, radix) {
373                (b'e' | b'E', 10) | (b'p' | b'P', 16) => {
374                    s = unsafe{s.offset(1)};
375
376                    let is_exponent_positive = match unsafe{*s} as u8 {
377                        b'-' => {
378                            s = unsafe{s.offset(1)};
379                            false
380                        }
381                        b'+' => {
382                            s = unsafe{s.offset(1)};
383                            true
384                        }
385                        _ => true,
386                    };
387
388                    // Exponent digits are always in base 10.
389                    if (unsafe{*s} as u8 as char).is_digit(10) {
390                        let mut exponent_value = 0;
391
392                        while let Some(digit) = (unsafe{*s} as u8 as char).to_digit(10) {
393                            exponent_value *= 10;
394                            exponent_value += digit;
395                            s = unsafe{s.offset(1)};
396                        }
397
398                        let exponent_base = match radix {
399                            10 => 10u128,
400                            16 => 2u128,
401                            _ => unreachable!(),
402                        };
403
404                        if is_exponent_positive {
405                            Some(exponent_base.pow(exponent_value) as $type)
406                        } else {
407                            Some(1.0 / (exponent_base.pow(exponent_value) as $type))
408                        }
409                    } else {
410                        // Exponent had no valid digits after 'e'/'p' and '+'/'-', rollback
411                        s = s_before_exponent;
412                        None
413                    }
414                }
415                _ => None,
416            };
417        }
418
419        if !endptr.is_null() {
420            // This is stupid, but apparently strto* functions want
421            // const input but mut output, yet the man page says
422            // "stores the address of the first invalid character in *endptr"
423            // so obviously it doesn't want us to clone it.
424            unsafe{*endptr = s.cast_mut()};
425        }
426
427        if let Some(exponent) = exponent {
428            result_sign * result * exponent
429        } else {
430            result_sign * result
431        }
432    }};
433}
434
435/// Project an `Out<struct X { field: Type }>` to `struct X { field: Out<Type> }`.
436///
437/// It is allowed to include only a subset of the struct's fields. The struct must implement
438/// `OutProject`.
439#[macro_export]
440macro_rules! out_project {
441    {
442        let $struct:ty { $($field:ident : $fieldty:ty),*$(,)? } = $src:ident;
443    } => {
444        // Verify $src actually has type Out<$struct>. Also verify it implements `OutProject`. This
445        // excludes
446        //
447        // - the case where $src is Out<&Struct>, where it would be very UB to just construct a
448        // writable reference to $src.$field, or a smart pointer
449        // - the case where there are unaligned fields where it would be UB to call ptr::write to
450        // them (requiring packed structs)
451        {
452            fn ensure_type<U: $crate::out::OutProject>(_t: &$crate::out::Out<U>) {}
453            ensure_type::<$struct>(&$src);
454        }
455        // Verify there are no duplicate struct fields. This is not strictly necessary as Out lacks
456        // the noalias requirement, but forbidding the same field to occur multiple times would
457        // allow both cases. The compiler will reject any struct that reuses the same identifier.
458        const _: () = {
459            $(
460                if ::core::mem::offset_of!($struct, $field) % ::core::mem::align_of::<$fieldty>() != 0 {
461                    panic!(concat!("unaligned field ", stringify!($field), " of struct ", stringify!($struct), "."));
462                }
463            )*
464            struct S {
465                $(
466                    $field: $fieldty
467                ),*
468            }
469        };
470
471        // Finally, create an Out<$fieldty> for each field.
472        $(
473            // getting the pointer to $field is safe
474            let $field = unsafe { &raw mut (*$crate::out::Out::<_>::as_mut_ptr(&mut $src)).$field };
475        )*
476        $(
477            let mut $field: $crate::out::Out<$fieldty> = unsafe {
478                // SAFETY: the only guarantee is that the pointer is valid and writable for the
479                // duration of 'b where $src: Out<'b, T>. But if so, and T is a struct, that
480                // must also be true for all the struct fields.
481                $crate::out::Out::with_lifetime_of(
482                    $crate::out::Out::nonnull($field),
483                    &$src,
484                )
485            };
486        )*
487    }
488}
489#[macro_export]
490macro_rules! OutProject {
491    derive() { $(#[$($attrs:meta),*])* $v:vis struct $name:ident {
492        $(
493            $(#[$($fa:meta),*])* $fv:vis $field:ident : $type:ty
494        ),*$(,)?
495    } } => {
496        // SAFETY: As simple as it is, OutProject is valid for any struct, and the pattern we have
497        // matched above ensures $name is one.
498        unsafe impl $crate::out::OutProject for $name {}
499    }
500}
501#[macro_export]
502#[cfg(not(feature = "check_against_libc_crate"))]
503macro_rules! CheckVsLibcCrate {
504    derive() { $(#[$($attrs:meta),*])* $v:vis struct $name:ident {
505        $(
506            $(#[$($fa:meta),*])* $fv:vis $field:ident : $type:ty
507        ),*$(,)?
508    } } => {
509    }
510}
511
512// TODO: probably exists nice nightly features that allow conflicting impls. Then we wouldn't need
513// much of this redundant code just to say A == B -> B == A and say A == B -> *mut A == *mut B.
514pub trait LibcTypeEquals<A, B> {}
515//impl<A, B> LibcTypeEquals<A, B> for () {}
516impl<A, B> LibcTypeEquals<*mut A, *mut B> for () where (): LibcTypeEquals<A, B> {}
517impl<A, B> LibcTypeEquals<*const A, *const B> for () where (): LibcTypeEquals<A, B> {}
518impl<A, B, const N: usize> LibcTypeEquals<[A; N], [B; N]> for () where (): LibcTypeEquals<A, B> {}
519macro_rules! for_primitive_int(
520    ($i:ident) => {
521        impl LibcTypeEquals<$i, $i> for () {}
522    }
523);
524for_primitive_int!(u8);
525for_primitive_int!(u16);
526for_primitive_int!(u32);
527for_primitive_int!(u64);
528for_primitive_int!(u128);
529for_primitive_int!(usize);
530for_primitive_int!(i8);
531for_primitive_int!(i16);
532for_primitive_int!(i32);
533for_primitive_int!(i64);
534for_primitive_int!(i128);
535for_primitive_int!(isize);
536impl LibcTypeEquals<crate::platform::types::c_void, crate::platform::types::c_void> for () {}
537#[cfg(feature = "check_against_libc_crate")]
538impl LibcTypeEquals<__libc_only_for_layout_checks::c_void, crate::platform::types::c_void> for () {}
539#[cfg(feature = "check_against_libc_crate")]
540impl LibcTypeEquals<crate::platform::types::c_void, __libc_only_for_layout_checks::c_void> for () {}
541
542//impl LibcTypeEquals<__libc_only_for_layout_checks::c_void>
543
544/// Derive macro which checks that structs here are defined the same as in the libc crate. Perhaps
545/// not sufficiently rigorous to soundly cast between the types, but should catch most mistakes.
546#[macro_export]
547#[cfg(feature = "check_against_libc_crate")]
548macro_rules! CheckVsLibcCrate {
549    // XXX: not sure we can have the name be different from libc::$name without parameters to the
550    // derive macro
551    derive() { $(#[$($attrs:meta),*])* $v:vis struct $name:ident {
552        $(
553            $(#[$($fa:meta),*])* $fv:vis $field:ident : $type:ty
554        ),*$(,)?
555    } } => {
556        // TODO: check repr(C)? probably possible to match on $attrs
557        #[allow(dead_code)]
558        const _: () = {
559            if ::core::mem::size_of::<$name>() != ::core::mem::size_of::<::__libc_only_for_layout_checks::$name>() {
560                panic!("struct size mismatch");
561            }
562            if ::core::mem::align_of::<$name>() != ::core::mem::align_of::<::__libc_only_for_layout_checks::$name>() {
563                panic!("struct alignment mismatch");
564            }
565            $(
566                if ::core::mem::offset_of!($name, $field) != ::core::mem::offset_of!(__libc_only_for_layout_checks::$name, $field) {
567                    panic!("struct field offset mismatch");
568                }
569            )*
570        };
571        $(
572            // check all field types are equivalent
573            #[allow(dead_code)]
574            const _: () = {
575                fn ensure_ty<A, B>(a: A, b: B) where (): $crate::macros::LibcTypeEquals::<A, B> {}
576                fn for_libc(a: $name, b: __libc_only_for_layout_checks::$name) {
577                    #[allow(clippy::diverging_sub_expression)]
578                    let a: $type = panic!("never called");
579                    ensure_ty(a, b.$field);
580                }
581            };
582        )*
583        impl $crate::macros::LibcTypeEquals<$name, __libc_only_for_layout_checks::$name> for () {}
584        impl $crate::macros::LibcTypeEquals<__libc_only_for_layout_checks::$name, $name> for () {}
585    }
586}