We've found a bunch of uses for reallocarray() in userland, and I
think the idiom is worth reusing in the kernel.  There are enough
places where we do malloc(x * y) that I think it makes sense to add
mallocarray(x, y).

ok?

Index: share/man/man9/Makefile
===================================================================
RCS file: /home/matthew/cvs-mirror/cvs/src/share/man/man9/Makefile,v
retrieving revision 1.210
diff -u -p -r1.210 Makefile
--- share/man/man9/Makefile     30 Jun 2014 21:48:09 -0000      1.210
+++ share/man/man9/Makefile     10 Jul 2014 17:15:45 -0000
@@ -232,7 +232,7 @@ MLINKS+=ktrace.9 ktrcsw.9 ktrace.9 ktrem
        ktrace.9 ktrsysret.9 ktrace.9 KTRPOINT.9
 MLINKS+=lock.9 lockinit.9 lock.9 lockmgr.9 lock.9 lockstatus.9
 MLINKS+=log.9 addlog.9
-MLINKS+=malloc.9 free.9
+MLINKS+=malloc.9 mallocarray.9 malloc.9 free.9
 MLINKS+=membar_sync.9 membar_enter.9 membar_sync.9 membar_exit.9 \
        membar_sync.9 membar_producer.9 membar_sync.9 membar_consumer.9
 MLINKS+=mbuf.9 m_copym2.9 mbuf.9 m_copym.9 mbuf.9 m_free.9 mbuf.9 MFREE.9 \
Index: share/man/man9/malloc.9
===================================================================
RCS file: /home/matthew/cvs-mirror/cvs/src/share/man/man9/malloc.9,v
retrieving revision 1.52
diff -u -p -r1.52 malloc.9
--- share/man/man9/malloc.9     3 Apr 2014 04:10:34 -0000       1.52
+++ share/man/man9/malloc.9     10 Jul 2014 17:13:39 -0000
@@ -33,6 +33,7 @@
 .Os
 .Sh NAME
 .Nm malloc ,
+.Nm mallocarray ,
 .Nm free
 .Nd kernel memory allocator
 .Sh SYNOPSIS
@@ -40,6 +41,13 @@
 .In sys/malloc.h
 .Ft void *
 .Fn malloc "unsigned long size" "int type" "int flags"
+.Ft void *
+.Fo mallocarray
+.Fa "unsigned long nmemb"
+.Fa "unsigned long size"
+.Fa "int type"
+.Fa "int flags"
+.Fc
 .Ft void
 .Fn free "void *addr" "int type"
 .Sh DESCRIPTION
@@ -48,8 +56,17 @@ The
 function allocates uninitialized memory in kernel address space for an
 object whose size is specified by
 .Fa size .
+The
+.Fn mallocarray
+function is the same as
+.Fn malloc ,
+except it allocates space for an array of
+.Fa nmemb
+objects and checks for arithmetic overflow.
+.Pp
+The
 .Fn free
-releases memory at address
+function releases memory at address
 .Fa addr
 that was previously allocated by
 .Fn malloc
@@ -60,7 +77,8 @@ is a null pointer, no action occurs.
 .Pp
 The
 .Fa flags
-argument further qualifies malloc's
+argument further qualifies
+.Fn malloc Ns 's
 operational characteristics as follows:
 .Bl -tag -width xxx -offset indent
 .It Dv M_WAITOK
Index: sys/conf/files
===================================================================
RCS file: /home/matthew/cvs-mirror/cvs/src/sys/conf/files,v
retrieving revision 1.572
diff -u -p -r1.572 files
--- sys/conf/files      19 Apr 2014 12:27:06 -0000      1.572
+++ sys/conf/files      10 Jul 2014 17:09:03 -0000
@@ -679,6 +679,7 @@ file kern/kern_ktrace.c                     ktrace
 file kern/kern_lock.c
 file kern/kern_lkm.c                   lkm
 file kern/kern_malloc.c
+file kern/kern_mallocarray.c
 file kern/kern_malloc_debug.c          malloc_debug
 file kern/kern_rwlock.c
 file kern/kern_physio.c
Index: sys/sys/malloc.h
===================================================================
RCS file: /home/matthew/cvs-mirror/cvs/src/sys/sys/malloc.h,v
retrieving revision 1.108
diff -u -p -r1.108 malloc.h
--- sys/sys/malloc.h    19 May 2014 14:30:03 -0000      1.108
+++ sys/sys/malloc.h    10 Jul 2014 17:08:05 -0000
@@ -391,10 +391,12 @@ extern struct kmemusage *kmemusage;
 extern char *kmembase;
 extern struct kmembuckets bucket[];
 
-extern void *malloc(unsigned long size, int type, int flags);
-extern void free(void *addr, int type);
-extern int sysctl_malloc(int *, u_int, void *, size_t *, void *, size_t,
-                             struct proc *);
+void   *malloc(unsigned long size, int type, int flags);
+void   *mallocarray(unsigned long nmemb, unsigned long size,
+           int type, int flags);
+void   free(void *addr, int type);
+int    sysctl_malloc(int *, u_int, void *, size_t *, void *, size_t,
+           struct proc *);
 
 size_t malloc_roundup(size_t);
 void   malloc_printit(int (*)(const char *, ...));
Index: sys/kern/kern_mallocarray.c
===================================================================
RCS file: sys/kern/kern_mallocarray.c
diff -N sys/kern/kern_mallocarray.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ sys/kern/kern_mallocarray.c 10 Jul 2014 17:10:06 -0000
@@ -0,0 +1,38 @@
+/*     $OpenBSD: reallocarray.c,v 1.1 2014/05/08 21:43:49 deraadt Exp $        
*/
+/*
+ * Copyright (c) 2008 Otto Moerbeek <[email protected]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM 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.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+
+/*
+ * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX
+ * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW
+ */
+#define MUL_NO_OVERFLOW        (1UL << (sizeof(size_t) * 4))
+
+void *
+mallocarray(unsigned long nmemb, unsigned long size, int type, int flags)
+{
+       if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
+           nmemb > 0 && SIZE_MAX / nmemb < size) {
+               if (flags & M_CANFAIL)
+                       return (NULL);
+               panic("overflow");
+       }
+       return (malloc(size * nmemb, type, flags));
+}

Reply via email to