diff options
author | Alexey Dobriyan <adobriyan@gmail.com> | 2006-10-01 02:27:20 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-10-01 03:39:19 -0400 |
commit | 1a2f67b459bb7846d4a15924face63eb2683acc2 (patch) | |
tree | 4c010d4c4220c9523342fb0daac90a433f36b53e | |
parent | 9442e691e4aec85eba43ac60a3e77c77fd2e73a4 (diff) |
[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.h | 1 | ||||
-rw-r--r-- | mm/util.c | 18 |
2 files changed, 19 insertions, 0 deletions
diff --git a/include/linux/string.h b/include/linux/string.h index e4c755860316..4f69ef9e6eb5 100644 --- a/include/linux/string.h +++ b/include/linux/string.h | |||
@@ -99,6 +99,7 @@ extern void * memchr(const void *,int,__kernel_size_t); | |||
99 | #endif | 99 | #endif |
100 | 100 | ||
101 | extern char *kstrdup(const char *s, gfp_t gfp); | 101 | extern char *kstrdup(const char *s, gfp_t gfp); |
102 | extern void *kmemdup(const void *src, size_t len, gfp_t gfp); | ||
102 | 103 | ||
103 | #ifdef __cplusplus | 104 | #ifdef __cplusplus |
104 | } | 105 | } |
@@ -40,6 +40,24 @@ char *kstrdup(const char *s, gfp_t gfp) | |||
40 | } | 40 | } |
41 | EXPORT_SYMBOL(kstrdup); | 41 | EXPORT_SYMBOL(kstrdup); |
42 | 42 | ||
43 | /** | ||
44 | * kmemdup - duplicate region of memory | ||
45 | * | ||
46 | * @src: memory region to duplicate | ||
47 | * @len: memory region length | ||
48 | * @gfp: GFP mask to use | ||
49 | */ | ||
50 | void *kmemdup(const void *src, size_t len, gfp_t gfp) | ||
51 | { | ||
52 | void *p; | ||
53 | |||
54 | p = ____kmalloc(len, gfp); | ||
55 | if (p) | ||
56 | memcpy(p, src, len); | ||
57 | return p; | ||
58 | } | ||
59 | EXPORT_SYMBOL(kmemdup); | ||
60 | |||
43 | /* | 61 | /* |
44 | * strndup_user - duplicate an existing string from user space | 62 | * strndup_user - duplicate an existing string from user space |
45 | * | 63 | * |