bug-gnulib
[Top][All Lists]
Advanced

[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








reply via email to

[Prev in Thread] Current Thread [Next in Thread]