* buffer = xmalloc(1024);
* xrealloc(buffer, 2048);
* free(buffer);
- * buffer = xcalloc(1024);
+ * buffer = xcalloc(1, 1024);
* free(buffer);
* buffer = xstrdup(string);
* free(buffer);
* allocation function will try its allocation again (calling the handler
* again if it still fails).
*
+ * xreallocarray behaves the same as the OpenBSD reallocarray function but for
+ * the same error checking, which in turn is the same as realloc but with
+ * calloc-style arguments and size overflow checking.
+ *
* xstrndup behaves like xstrdup but only copies the given number of
* characters. It allocates an additional byte over its second argument and
* always nul-terminates the string.
* line number to these functions.
*
* The canonical version of this file is maintained in the rra-c-util package,
- * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+ * which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
*
- * Copyright 2012
+ * Written by Russ Allbery <eagle@eyrie.org>
+ * Copyright 2015, 2023 Russ Allbery <eagle@eyrie.org>
+ * Copyright 2012-2014
* The Board of Trustees of the Leland Stanford Junior University
- * Copyright (c) 2004, 2005, 2006
- * by Internet Systems Consortium, Inc. ("ISC")
- * Copyright (c) 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
- * 2002, 2003 by The Internet Software Consortium and Rich Salz
+ * Copyright 2004-2006 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright 1991, 1994-2003 The Internet Software Consortium and Rich Salz
*
* This code is derived from software contributed to the Internet Software
* Consortium by Rich Salz.
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
+ *
+ * SPDX-License-Identifier: ISC
*/
#include <config.h>
void
xmalloc_fail(const char *function, size_t size, const char *file, int line)
{
- sysdie("failed to %s %lu bytes at %s line %d", function,
- (unsigned long) size, file, line);
+ if (size == 0)
+ sysdie("failed to format output with %s at %s line %d", function, file,
+ line);
+ else
+ sysdie("failed to %s %lu bytes at %s line %d", function,
+ (unsigned long) size, file, line);
}
/* Assign to this variable to choose a handler other than the default. */
real_size = (size > 0) ? size : 1;
p = malloc(real_size);
while (p == NULL) {
- (*xmalloc_error_handler)("malloc", size, file, line);
+ xmalloc_error_handler("malloc", size, file, line);
p = malloc(real_size);
}
return p;
size = (size > 0) ? size : 1;
p = calloc(n, size);
while (p == NULL) {
- (*xmalloc_error_handler)("calloc", n * size, file, line);
+ xmalloc_error_handler("calloc", n * size, file, line);
p = calloc(n, size);
}
return p;
void *newp;
newp = realloc(p, size);
- while (newp == NULL && size > 0) {
- (*xmalloc_error_handler)("realloc", size, file, line);
+ if (size == 0)
+ return newp;
+
+ /*
+ * GCC 13.2.0 (and some earlier versions) misdiagnose this error
+ * handling as a use-after-free of p, but the C standard guarantees
+ * that if realloc fails (which is true in every case when it returns
+ * NULL when size > 0), p is unchanged and still valid.
+ */
+#if __GNUC__ >= 12 && !defined(__clang__)
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wuse-after-free"
+#endif
+ while (newp == NULL) {
+ xmalloc_error_handler("realloc", size, file, line);
newp = realloc(p, size);
}
return newp;
+#if __GNUC__ >= 12 && !defined(__clang__)
+# pragma GCC diagnostic pop
+#endif
+}
+
+
+void *
+x_reallocarray(void *p, size_t n, size_t size, const char *file, int line)
+{
+ void *newp;
+
+ newp = reallocarray(p, n, size);
+ if (size == 0 || n == 0)
+ return newp;
+
+ /*
+ * GCC 13.2.0 (and some earlier versions) misdiagnose this error
+ * handling as a use-after-free of p, but the documentation of
+ * reallocarray guarantees that if reallocarray fails (which is true in
+ * every case when it returns NULL when size > 0 and n > 0), p is
+ * unchanged and still valid.
+ */
+#if __GNUC__ >= 12 && !defined(__clang__)
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wuse-after-free"
+#endif
+ while (newp == NULL) {
+ xmalloc_error_handler("reallocarray", n * size, file, line);
+ newp = reallocarray(p, n, size);
+ }
+#if __GNUC__ >= 12 && !defined(__clang__)
+# pragma GCC diagnostic pop
+#endif
+ return newp;
}
len = strlen(s) + 1;
p = malloc(len);
while (p == NULL) {
- (*xmalloc_error_handler)("strdup", len, file, line);
+ xmalloc_error_handler("strdup", len, file, line);
p = malloc(len);
}
memcpy(p, s, len);
length = p - s;
copy = malloc(length + 1);
while (copy == NULL) {
- (*xmalloc_error_handler)("strndup", length + 1, file, line);
+ xmalloc_error_handler("strndup", length + 1, file, line);
copy = malloc(length + 1);
}
memcpy(copy, s, length);
va_copy(args_copy, args);
status = vsnprintf(NULL, 0, fmt, args_copy);
va_end(args_copy);
- (*xmalloc_error_handler)("vasprintf", status + 1, file, line);
+ status = (status < 0) ? 0 : status + 1;
+ xmalloc_error_handler("vasprintf", status, file, line);
va_copy(args_copy, args);
status = vasprintf(strp, fmt, args_copy);
va_end(args_copy);
va_copy(args_copy, args);
status = vsnprintf(NULL, 0, fmt, args_copy);
va_end(args_copy);
- (*xmalloc_error_handler)("asprintf", status + 1, file, line);
+ status = (status < 0) ? 0 : status + 1;
+ xmalloc_error_handler("asprintf", status, file, line);
va_copy(args_copy, args);
status = vasprintf(strp, fmt, args_copy);
va_end(args_copy);
}
+ va_end(args);
}
-#else /* !(HAVE_C99_VAMACROS || HAVE_GNU_VAMACROS) */
+#else /* !(HAVE_C99_VAMACROS || HAVE_GNU_VAMACROS) */
void
x_asprintf(char **strp, const char *fmt, ...)
{
va_copy(args_copy, args);
status = vsnprintf(NULL, 0, fmt, args_copy);
va_end(args_copy);
- (*xmalloc_error_handler)("asprintf", status + 1, __FILE__, __LINE__);
+ status = (status < 0) ? 0 : status + 1;
+ xmalloc_error_handler("asprintf", status, __FILE__, __LINE__);
va_copy(args_copy, args);
status = vasprintf(strp, fmt, args_copy);
va_end(args_copy);
}
+ va_end(args);
}
#endif /* !(HAVE_C99_VAMACROS || HAVE_GNU_VAMACROS) */