diff --git a/include/nuttx/compiler.h b/include/nuttx/compiler.h index 8eeba9bec6d36..c995c4b219cd9 100644 --- a/include/nuttx/compiler.h +++ b/include/nuttx/compiler.h @@ -303,6 +303,7 @@ # define malloc_like1(a) __attribute__((__malloc__(__builtin_free, 1))) __attribute__((__alloc_size__(a))) # define malloc_like2(a, b) __attribute__((__malloc__(__builtin_free, 1))) __attribute__((__alloc_size__(a, b))) # define realloc_like(a) __attribute__((__alloc_size__(a))) +# define realloc_like2(a, b) __attribute__((__alloc_size__(a, b))) # else # define fopen_like __attribute__((__malloc__)) # define popen_like __attribute__((__malloc__)) @@ -310,6 +311,7 @@ # define malloc_like1(a) __attribute__((__malloc__)) __attribute__((__alloc_size__(a))) # define malloc_like2(a, b) __attribute__((__malloc__)) __attribute__((__alloc_size__(a, b))) # define realloc_like(a) __attribute__((__alloc_size__(a))) +# define realloc_like2(a, b) __attribute__((__alloc_size__(a, b))) # endif /* Some versions of GCC have a separate __syslog__ format. diff --git a/include/stdlib.h b/include/stdlib.h index b29e59a5bd099..eefce6b57107a 100644 --- a/include/stdlib.h +++ b/include/stdlib.h @@ -233,6 +233,7 @@ FAR void *malloc(size_t) malloc_like1(1); FAR void *valloc(size_t) malloc_like1(1); void free(FAR void *); FAR void *realloc(FAR void *, size_t) realloc_like(2); +FAR void *reallocarray(FAR void *, size_t, size_t) realloc_like2(2, 3); FAR void *memalign(size_t, size_t) malloc_like1(2); FAR void *zalloc(size_t) malloc_like1(1); FAR void *calloc(size_t, size_t) malloc_like2(1, 2); diff --git a/libs/libc/stdlib/CMakeLists.txt b/libs/libc/stdlib/CMakeLists.txt index bc233a9b74589..f2a21cd7da336 100644 --- a/libs/libc/stdlib/CMakeLists.txt +++ b/libs/libc/stdlib/CMakeLists.txt @@ -39,6 +39,7 @@ set(SRCS lib_bsearch.c lib_rand.c lib_rand48.c + lib_reallocarray.c lib_qsort.c lib_srand.c lib_strtol.c diff --git a/libs/libc/stdlib/Make.defs b/libs/libc/stdlib/Make.defs index be2833c1d9a32..4f719d4a04512 100644 --- a/libs/libc/stdlib/Make.defs +++ b/libs/libc/stdlib/Make.defs @@ -28,6 +28,7 @@ CSRCS += lib_strtoll.c lib_strtoul.c lib_strtoull.c lib_strtold.c CSRCS += lib_checkbase.c lib_mktemp.c lib_mkstemp.c lib_mkdtemp.c CSRCS += lib_aligned_alloc.c lib_posix_memalign.c lib_valloc.c lib_mblen.c CSRCS += lib_mbtowc.c lib_wctomb.c lib_mbstowcs.c lib_wcstombs.c lib_atexit.c +CSRCS += lib_reallocarray.c ifeq ($(CONFIG_PSEUDOTERM),y) CSRCS += lib_ptsname.c lib_ptsnamer.c lib_unlockpt.c lib_openpty.c diff --git a/libs/libc/stdlib/lib_reallocarray.c b/libs/libc/stdlib/lib_reallocarray.c new file mode 100644 index 0000000000000..1931a9891dbc6 --- /dev/null +++ b/libs/libc/stdlib/lib_reallocarray.c @@ -0,0 +1,78 @@ +/**************************************************************************** + * libs/libc/stdlib/lib_reallocarray.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include "libc.h" + +/**************************************************************************** + * Pre-processor definitions + ****************************************************************************/ + +/* Set overflow control only if larger than 65536 for bit platforms. The + * limit is the same as in OpenBSD. + */ + +#define CHECK_OVERFLOW_LIMIT (1UL << (sizeof(size_t) * 4)) + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: reallocarray + * + * Description: + * The reallocarray function has the same functionality as realloc but + * it fails safely if multiplication overflow occurs. + * + * Input Parameters: + * ptr - old memory to be reallocated and freed + * nmemb - number of elements + * size - size of one element in bytes + * + * Returned Value: + * Upon successful completion, the address of the re-allocated memory + * is returned and previous pointer is freed. NULL is returned on error + * with original block of memory left unchanged. + * + ****************************************************************************/ + +FAR void *reallocarray(FAR void *ptr, size_t nmemb, size_t size) +{ + if (nmemb != 0 && (nmemb >= CHECK_OVERFLOW_LIMIT || + size >= CHECK_OVERFLOW_LIMIT)) + { + /* Do division only if at least one element is larget than limit */ + + if ((SIZE_MAX / nmemb) < size) + { + set_errno(ENOMEM); + return NULL; + } + } + + return lib_realloc(ptr, nmemb * size); +}