Home

pointer wizardry

2011/01/07

Very neat trick:

*((char *) mempcpy (dst, src, n)) = '\0';

[Thanks @mfukar]

Advertisements

11 Responses to “pointer wizardry”

  1. Aristotelis Says:

    Nice, although I’m a little reluctant to use anything that needs:
    #define _GNU_SOURCE
    for compilation.

    In my openbsd machine :
    >man mempcpy man: no entry for mempcpy in the manual.

  2. Michael Iatrou Says:

    This is rather controversial, I would actually put it in the same category of wizardry as the one that led to the Debian-OpenSSL fiasco. I would take strlcpy any day ( even if that means replacing glibc or/and shipping a custom implementation of it.)

  3. Angelos Karageorgiou Says:

    SmartAlecky code will always get you respect from juniors, a smirk from peers and a sigh of desperation from old code hounds.

  4. adamo Says:

    @Angelos Karageorgiou:
    Ulrich Drepper is currently the foremost contributor and has overall responsibility for maintenance and development for GNU libc. So I would not count this as a cheap trick. He dislikes strlcpy(3) and friends and not without good arguments.

    @Michael Iatrou:
    I tend to prefer strlcpy(3) more, although I am not using it often. I think it is mostly a matter of style and sticking (very) disciplined to it. One should decide on what to use while writing code and always have in mind what bombs it might draw near him.

    @Aristotelis:
    No manual page for memcpy(3)? Really? memcpy(3)


  5. I think Aris is referring to mempcpy, which indeed is a GNU extension, and a nice one at that.

    Here’s my take on Drepper’s “trick”, trying to be a bit cleaner, safer and more portable: bzero(memmove(dst, src, n) + n, 1)

    Also, with regards to strlcpy I think that Drepper’s arguments are solid, but that there’s no point in ignoring the need that strlcpy serves. Writing code that errs without segfaulting is a valid coding policy, just as valid as writing code without errors. There’s pros and cons to both policies. If strlcat was in glibc I would use it more for sure, but mostly when lazy, i.e. when I would probably be making tons of errors anyway, so I would be better of using strlcat. And I don’t think that there’s a moral hazard here because strlcat or no strlcat you are still responsible for your bugs and there is no less pressure on that account.

    • adamo Says:

      Given that Drepper is using mempcpy(), my eyes should not have skipped the extra ‘p’ in Aris’ comment :(

    • adamo Says:

      However on my OpenBSD-4.8 desktop I see /usr/src/gnu/lib/libiberty/src/mempcpy.c with:

      #include <ansidecl.h>
      #include <stddef.h>
      
      extern PTR memcpy (PTR, const PTR, size_t);
      
      PTR
      mempcpy (PTR dst, const PTR src, size_t len)
      {
        return (char *) memcpy (dst, src, len) + len;
      }
      

  6. Nice, on FreeBSD I’ve got two copies of the static lib:

    /usr/local/lib/gcc46/libiberty.a was installed by package gcc-4.6.0.20101016
    /usr/local/lib/libiberty.a was installed by package binutils-2.20.1_3
    

    And libiberty is in the ports as either {free,gnu}libiberty so a package could just build-depend on it.

  7. keramida Says:

    I don’t like this particular mempcpy() trick at all.

    It depends, exactly like plain strcpy() on an assumption that is ‘hidden’ for plain sight: that there is enough space for (n + 1) bytes in the ‘dest’ location. If dest[] is a memory area with space only for ‘n’ bytes, one should use:

    *((char *)mempcpy(src, dest, n – 1)) = ”;

    At which point the pointer trick is neat, but it nearly begs for a comment that explains why (n – 1) is used and what purpose ” serves. At that point it’s beginning to be difficult to justify the use of mempcpy() instead of strlcpy(), because they have similar portability & platform availability problems, but the strlcpy() version encourages cleaner writing style, e.g.:

        if (strlcpy(src, dest, n) >= n)
                error("overflow at %d bytes\n", n);
    
  8. mfukar Says:

    Don’t take this “idiom” out of context. Drepper was mentioning it as a reply to: “but memcpy will not null-terminate your strings”.

    When it comes to copying strings, though, if you make the assumption that you know (and you have to know) how long they are, you can use memcpy() instead of the various str* crap. Drepper’s argument is that while strl*() are advertised as safe, it merely unconditionally substitutes one class of errors for another.

    At any rate, using mempcpy() then just leads to a somewhat neater version of:
    *((char *)memcpy(src, dest, n) + n) = 0;

    Granted, it’s a GNU extension, but the context is GNU libc.

    If, on the other hand, one wants to use strlcpy() and friends, one can do so with mandatory overflow and underflow checks. Talk about code clutter. And strl*() aren’t parts of any standards, either.

  9. Konstantinos Koukopoulos Says:

    glibc is not just another library dependency, and both mempcpy and strlcpy are not standard. So no wins here for both. And it’s correct that both function families offers the possibility of different errors that can be avoided with extra code and logic. If it’s a matter of style though then why the insistence of having just one of these non-standard extensions in glibc? Are the programmers themselves not able to decide what fits their need at a given time? It would make sense, although funny, if Drepper maintained that adding non-standard functions to glibc is a bad idea. But to say that overflow checking is a bad idea in principal is I think taking it too far.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: