[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: xmemdup0
From: |
Eric Blake |
Subject: |
Re: xmemdup0 |
Date: |
Fri, 9 May 2008 20:34:51 +0000 (UTC) |
User-agent: |
Loom/3.14 (http://gmane.org/) |
Paul Eggert <eggert <at> CS.UCLA.EDU> writes:
> In the strlen case, wouldn't it be more efficient to look for the NUL
> while you're copying the block of memory? That way, you need to do
> only one pass over the source.
Maybe. But both memcpy and rawmemchr(s,0)/strlen(s) are generally coded to
operate on long words rather than bytes; without a new primitive designed to
copy an entire block but also identify the first NUL (if any) in that block, it
is probably more efficient to stick to the existing primitives than open-coding
a naive byte-wise copy-and-search loop, and certainly more maintainable than
open-coding a longword copy-and-search loop. Without an open-coded loop, I
don't have any current alternatives. This doesn't work:
void *copy = xmalloc (orig, n);
void *embedded = stpncpy (copy, orig, n);
since it writes the rest of the copy with NULs, which is wasted effort if it
truly made sense to copy the remaining bytes from orig.
It seems like implementing xstrndup makes sense for gnulib, but that only
covers the case where the content after the embedded NUL does not need to be
copied, and it still traverses twice (once to find the length to copy, and once
do the copy).
BSD's strlcpy might be useful in gnulib; this does a single traversal and
detects the first embedded NUL, but requires the space for a terminating NUL:
void *copy = xmalloc (orig, n + 1);
size_t embedded_offset = strlcpy (copy, orig, n + 1);
memcpy (copy + embedded_offset, orig + embedded_offset, n - embedded_offset);
Maybe it makes sense to invent something like this?
/* Copy the object P of size S. Set *L to the offset of the first NUL byte
encountered in the copy, or to S if it does not contain one. */
void *xmemldup (void const *p, size_t s, size_t *l);
> > void *result = memcpy (xmalloc (n + 1), ptr, n);
>
> One portability glitch: this local variable should be of type 'char *',
> not 'void *'; otherwise the next line is not portable.
I noticed that too. Here's what I'm committing.
>From 34ebad3df7a99eea326f9170f2517b5d23873d1b Mon Sep 17 00:00:00 2001
From: Eric Blake <address@hidden>
Date: Fri, 9 May 2008 13:54:18 -0600
Subject: [PATCH] Add xmemdup0.
* lib/xalloc.h (xmemdup0): New prototype and C++ typesafe
implementation.
* lib/xmalloc.c (xmemdup0): New C implementation.
Signed-off-by: Eric Blake <address@hidden>
---
ChangeLog | 7 +++++++
lib/xalloc.h | 7 +++++++
lib/xmalloc.c | 20 +++++++++++++++++++-
3 files changed, 33 insertions(+), 1 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 06ca955..d864de1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2008-05-09 Eric Blake <address@hidden>
+
+ Add xmemdup0.
+ * lib/xalloc.h (xmemdup0): New prototype and C++ typesafe
+ implementation.
+ * lib/xmalloc.c (xmemdup0): New C implementation.
+
2008-05-08 Bruno Haible <address@hidden>
* m4/wctype.m4 (gl_WCTYPE_H): Correct indentation.
diff --git a/lib/xalloc.h b/lib/xalloc.h
index 40dcf4b..314ed6d 100644
--- a/lib/xalloc.h
+++ b/lib/xalloc.h
@@ -50,6 +50,7 @@ void *xcalloc (size_t n, size_t s);
void *xrealloc (void *p, size_t s);
void *x2realloc (void *p, size_t *pn);
void *xmemdup (void const *p, size_t s);
+void *xmemdup0 (void const *p, size_t s);
char *xstrdup (char const *str);
/* Return 1 if an array of N objects, each of size S, cannot exist due
@@ -264,6 +265,12 @@ xmemdup (T const *p, size_t s)
return (T *) xmemdup ((void const *) p, s);
}
+template <typename T> inline T *
+xmemdup0 (T const *p, size_t s)
+{
+ return (T *) xmemdup0 ((void const *) p, s);
+}
+
# endif
diff --git a/lib/xmalloc.c b/lib/xmalloc.c
index 3a12345..b1f6993 100644
--- a/lib/xmalloc.c
+++ b/lib/xmalloc.c
@@ -1,7 +1,7 @@
/* xmalloc.c -- malloc with out of memory checking
Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2002, 2003, 2004, 2005, 2006 Free Software Foundation,
+ 1999, 2000, 2002, 2003, 2004, 2005, 2006, 2008 Free Software Foundation,
Inc.
This program is free software: you can redistribute it and/or modify
@@ -113,6 +113,24 @@ xmemdup (void const *p, size_t s)
return memcpy (xmalloc (s), p, s);
}
+/* Clone an object P of size S, with error checking, and include a
+ terminating NUL byte.
+
+ The terminating NUL makes it safe to use strlen or rawmemchr to
+ check for embedded NUL; it also speeds up algorithms such as escape
+ sequence processing on arbitrary memory, by making it always safe
+ to read the byte after the escape character rather than having to
+ check if each escape character is the last byte in the object. */
+
+void *
+xmemdup0 (void const *p, size_t s)
+{
+ char *result = xcharalloc (s + 1);
+ memcpy (result, p, s);
+ result[s] = 0;
+ return result;
+}
+
/* Clone STRING. */
char *
--
1.5.5.1