Commit 1a2f67b4 authored by Alexey Dobriyan's avatar Alexey Dobriyan Committed by Linus Torvalds

[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: default avatarAlexey Dobriyan <adobriyan@gmail.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 9442e691
...@@ -99,6 +99,7 @@ extern void * memchr(const void *,int,__kernel_size_t); ...@@ -99,6 +99,7 @@ extern void * memchr(const void *,int,__kernel_size_t);
#endif #endif
extern char *kstrdup(const char *s, gfp_t gfp); extern char *kstrdup(const char *s, gfp_t gfp);
extern void *kmemdup(const void *src, size_t len, gfp_t gfp);
#ifdef __cplusplus #ifdef __cplusplus
} }
......
...@@ -40,6 +40,24 @@ char *kstrdup(const char *s, gfp_t gfp) ...@@ -40,6 +40,24 @@ char *kstrdup(const char *s, gfp_t gfp)
} }
EXPORT_SYMBOL(kstrdup); 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 * strndup_user - duplicate an existing string from user space
* *
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment