summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexey Dobriyan <adobriyan@gmail.com>2006-09-30 23:27:20 -0700
committerLinus Torvalds <torvalds@g5.osdl.org>2006-10-01 00:39:19 -0700
commit1a2f67b459bb7846d4a15924face63eb2683acc2 (patch)
tree4c010d4c4220c9523342fb0daac90a433f36b53e
parent9442e691e4aec85eba43ac60a3e77c77fd2e73a4 (diff)
downloadlinux-3.10-1a2f67b459bb7846d4a15924face63eb2683acc2.tar.gz
linux-3.10-1a2f67b459bb7846d4a15924face63eb2683acc2.tar.bz2
linux-3.10-1a2f67b459bb7846d4a15924face63eb2683acc2.zip
[PATCH] kmemdup: introduce
One of idiomatic ways to duplicate a region of memory is dst = kmalloc(len, GFP_KERNEL); if (!dst) return -ENOMEM; memcpy(dst, src, len); which is neat code except a programmer needs to write size twice. Which sometimes leads to mistakes. If len passed to kmalloc is smaller that len passed to memcpy, it's straight overwrite-beyond-end. If len passed to memcpy is smaller than len passed to kmalloc, it's either a) legit behaviour ;-), or b) cloned buffer will contain garbage in second half. Slight trolling of commit lists shows several duplications bugs done exactly because of diverged lenghts: Linux: [CRYPTO]: Fix memcpy/memset args. [PATCH] memcpy/memset fixes OpenBSD: kerberosV/src/lib/asn1: der_copy.c:1.4 If programmer is given only one place to play with lengths, I believe, such mistakes could be avoided. With kmemdup, the snippet above will be rewritten as: dst = kmemdup(src, len, GFP_KERNEL); if (!dst) return -ENOMEM; This also leads to smaller code (kzalloc effect). Quick grep shows 200+ places where kmemdup() can be used. Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--include/linux/string.h1
-rw-r--r--mm/util.c18
2 files changed, 19 insertions, 0 deletions
diff --git a/include/linux/string.h b/include/linux/string.h
index e4c75586031..4f69ef9e6eb 100644
--- a/include/linux/string.h
+++ b/include/linux/string.h
@@ -99,6 +99,7 @@ extern void * memchr(const void *,int,__kernel_size_t);
#endif
extern char *kstrdup(const char *s, gfp_t gfp);
+extern void *kmemdup(const void *src, size_t len, gfp_t gfp);
#ifdef __cplusplus
}
diff --git a/mm/util.c b/mm/util.c
index 7368479220b..e14fa84ef39 100644
--- a/mm/util.c
+++ b/mm/util.c
@@ -40,6 +40,24 @@ char *kstrdup(const char *s, gfp_t gfp)
}
EXPORT_SYMBOL(kstrdup);
+/**
+ * kmemdup - duplicate region of memory
+ *
+ * @src: memory region to duplicate
+ * @len: memory region length
+ * @gfp: GFP mask to use
+ */
+void *kmemdup(const void *src, size_t len, gfp_t gfp)
+{
+ void *p;
+
+ p = ____kmalloc(len, gfp);
+ if (p)
+ memcpy(p, src, len);
+ return p;
+}
+EXPORT_SYMBOL(kmemdup);
+
/*
* strndup_user - duplicate an existing string from user space
*