10b57cec5SDimitry Andric //===-- wrappers_c_checks.h -------------------------------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric
90b57cec5SDimitry Andric #ifndef SCUDO_CHECKS_H_
100b57cec5SDimitry Andric #define SCUDO_CHECKS_H_
110b57cec5SDimitry Andric
120b57cec5SDimitry Andric #include "common.h"
130b57cec5SDimitry Andric
140b57cec5SDimitry Andric #include <errno.h>
150b57cec5SDimitry Andric
160b57cec5SDimitry Andric #ifndef __has_builtin
170b57cec5SDimitry Andric #define __has_builtin(X) 0
180b57cec5SDimitry Andric #endif
190b57cec5SDimitry Andric
200b57cec5SDimitry Andric namespace scudo {
210b57cec5SDimitry Andric
220b57cec5SDimitry Andric // A common errno setting logic shared by almost all Scudo C wrappers.
setErrnoOnNull(void * Ptr)23480093f4SDimitry Andric inline void *setErrnoOnNull(void *Ptr) {
240b57cec5SDimitry Andric if (UNLIKELY(!Ptr))
250b57cec5SDimitry Andric errno = ENOMEM;
260b57cec5SDimitry Andric return Ptr;
270b57cec5SDimitry Andric }
280b57cec5SDimitry Andric
290b57cec5SDimitry Andric // Checks return true on failure.
300b57cec5SDimitry Andric
310b57cec5SDimitry Andric // Checks aligned_alloc() parameters, verifies that the alignment is a power of
320b57cec5SDimitry Andric // two and that the size is a multiple of alignment.
checkAlignedAllocAlignmentAndSize(uptr Alignment,uptr Size)33480093f4SDimitry Andric inline bool checkAlignedAllocAlignmentAndSize(uptr Alignment, uptr Size) {
34*0fca6ea1SDimitry Andric return !isPowerOfTwo(Alignment) || !isAligned(Size, Alignment);
350b57cec5SDimitry Andric }
360b57cec5SDimitry Andric
370b57cec5SDimitry Andric // Checks posix_memalign() parameters, verifies that alignment is a power of two
380b57cec5SDimitry Andric // and a multiple of sizeof(void *).
checkPosixMemalignAlignment(uptr Alignment)39480093f4SDimitry Andric inline bool checkPosixMemalignAlignment(uptr Alignment) {
40*0fca6ea1SDimitry Andric return !isPowerOfTwo(Alignment) || !isAligned(Alignment, sizeof(void *));
410b57cec5SDimitry Andric }
420b57cec5SDimitry Andric
430b57cec5SDimitry Andric // Returns true if calloc(Size, N) overflows on Size*N calculation. Use a
440b57cec5SDimitry Andric // builtin supported by recent clang & GCC if it exists, otherwise fallback to a
450b57cec5SDimitry Andric // costly division.
checkForCallocOverflow(uptr Size,uptr N,uptr * Product)46480093f4SDimitry Andric inline bool checkForCallocOverflow(uptr Size, uptr N, uptr *Product) {
47349cc55cSDimitry Andric #if __has_builtin(__builtin_umull_overflow) && (SCUDO_WORDSIZE == 64U)
4881ad6265SDimitry Andric return __builtin_umull_overflow(Size, N,
4981ad6265SDimitry Andric reinterpret_cast<unsigned long *>(Product));
50349cc55cSDimitry Andric #elif __has_builtin(__builtin_umul_overflow) && (SCUDO_WORDSIZE == 32U)
5181ad6265SDimitry Andric // On, e.g. armv7, uptr/uintptr_t may be defined as unsigned long
5281ad6265SDimitry Andric return __builtin_umul_overflow(Size, N,
5381ad6265SDimitry Andric reinterpret_cast<unsigned int *>(Product));
540b57cec5SDimitry Andric #else
550b57cec5SDimitry Andric *Product = Size * N;
560b57cec5SDimitry Andric if (!Size)
570b57cec5SDimitry Andric return false;
580b57cec5SDimitry Andric return (*Product / Size) != N;
590b57cec5SDimitry Andric #endif
600b57cec5SDimitry Andric }
610b57cec5SDimitry Andric
620b57cec5SDimitry Andric // Returns true if the size passed to pvalloc overflows when rounded to the next
630b57cec5SDimitry Andric // multiple of PageSize.
checkForPvallocOverflow(uptr Size,uptr PageSize)64480093f4SDimitry Andric inline bool checkForPvallocOverflow(uptr Size, uptr PageSize) {
6506c3fb27SDimitry Andric return roundUp(Size, PageSize) < Size;
660b57cec5SDimitry Andric }
670b57cec5SDimitry Andric
680b57cec5SDimitry Andric } // namespace scudo
690b57cec5SDimitry Andric
700b57cec5SDimitry Andric #endif // SCUDO_CHECKS_H_
71