2008/11/9 Matt Wozniski <[EMAIL PROTECTED]>:

> On Sat, Nov 8, 2008 at 11:18 PM, Tony Mechelynck wrote:
>>
>> Configure is supposed to check whether one of the system provided
>> string-move operations handle overlap. Here's what I see in the logs and
>> files produced by configure on my system:
>
> <snip>
>
>> So I suppose mch_memmove should be used everywhere for moves of byte
>> strings (overlapping or not), and it will be resolved by bcopy, memmove,
>> memcpy or the owncoded function according to what configure has found.
>
> You're right up til this point, but mch_memmove() should only be used
> where the bytes are overlapping, since it's so much less efficient
> than just a normal memcpy() and that loss is only justified when its
> extra feature is being used.  memmove() should never be used in the
> vim sources.
>
> ~Matt


Yes, memcpy() is more efficient then memmove() for copying
memory, and can/should be used when there we can guarantee
that there is such overlap.  If there can be overlap, memmove()
must be used, but it does not exists on all systems, hence the
need for mch_memmove() for portability.  See man pages of
memcpy() & memmove().

In practice, memcpy() may actually work on some system,
or may not work depending on compiler, optimization options
or whether copy goes upward or downward, etc.  In any case,
don't rely on it, it's not portable.

I just wrote a simple test case, to see how my system (linux x86)
behaves, it shows that memcpy() does not work in practice for
overlapping memory:

$ gcc -Wall -o test-memcpy-memmove test-memcpy-memmove.c
$ ./memcpy-memmove
testing descending memcpy()  with overlapping mem...OK
testing ascending  memcpy()  with overlapping mem...FAIL
  expected=[abcdeabcdeabcdepqrstuvwxyz]
  actual  =[abcdeabcdefghijpqrstuvwxyz]
testing descending memmove() with overlapping mem...OK
testing ascending  memmove() with overlapping mem...OK

Interestingly, running the same test case under valgrind gives
different results:

$ valgrind ./test-memcpy-memmove 2> vg.log
testing descending memcpy()  with overlapping mem...OK
testing ascending  memcpy()  with overlapping mem...OK
testing descending memmove() with overlapping mem...OK
testing ascending  memmove() with overlapping mem...OK

Results may be different on other systems, but at least,
on Linux x86, using memcpy() for overlapping memory
does not give the correct results.  So don't treat those
overlapping memory messages from valgrind as theoretical
bugs, but as real severe nasty bugs.

I attach the source code of my test case if you want to
run it on your system.

-- Dominique

--~--~---------~--~----~------------~-------~--~----~
You received this message from the "vim_dev" maillist.
For more information, visit http://www.vim.org/maillist.php
-~----------~----~----~----~------~----~------~--~---

/*
 * Test whether memcpy()/memmove() give the correct
 * results when moving overlapping memory upward or
 * backward.  mempcy() is not guarantee to be correct
 * when memory overlaps, memmove() should be correct.
 *
 * Results on my system (Linux x86):
 *
 * $ gcc -O2 -Wall -o test-memcpy-memmove test-memcpy-memmove.c
 * $ ./test-memcpy-memmove 
 * testing descending memcpy()  with overlapping mem...OK
 * testing ascending  memcpy()  with overlapping mem...FAIL
 *   expected=[abcdeabcdefghijpqrstuvwxyz] 
 *   actual  =[abcdeabcdeabcdepqrstuvwxyz]
 * testing descending memmove() with overlapping mem...OK
 * testing ascending  memmove() with overlapping mem...OK
 *
 * Dominique Pelle <[EMAIL PROTECTED]>
 */
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

/* Compare expected and actual results, and print outcome */
static void compare(const char *expected, const char *actual)
{
  if (strcmp(expected, actual) == 0) {
    printf("OK\n");
  } else {
    printf("FAIL\n"
           "  expected=[%s]\n"
           "  actual  =[%s]\n", expected, actual);
  }
}

int main()
{
  /*                          0         1         2
   * .........................01234567890123456789012345 */
  const char *pristine_str = "abcdefghijklmnopqrstuvwxyz";
  char *str;

  /* Expected results when copying 10 char by 5 positions (hence
   * overlapping memory).
   *
   * When copying downward memmove(str, str + 5, 10)
   * (.) for unchanged char (X) for changed char:
   *
   *                  pristine:  abcdefghijklmnopqrstuvwxyx
   *                             XXXXXXXXXX................ */
  const const char *expected1 = "fghijklmnoklmnopqrstuvwxyz";

  /*                             
   * When copying upward memmove(str + 5, str, 10)
   * (.) for unchanged char (X) for changed char:
   *
   *                  pristine:  abcdefghijklmnopqrstuvwxyx
   *                             .....XXXXXXXXXX........... */
  const const char *expected2 = "abcdeabcdefghijpqrstuvwxyz";

  
  printf("testing descending memcpy()  with overlapping mem...");
  str = strdup(pristine_str);
  memcpy(str, str + 5, 10);
  compare(str, expected1);

  printf("testing ascending  memcpy()  with overlapping mem...");
  strcpy(str, pristine_str);
  memcpy(str + 5, str, 10);
  compare(str, expected2);

  printf("testing descending memmove() with overlapping mem...");
  strcpy(str, pristine_str);
  memmove(str, str + 5, 10);
  compare(str, expected1);

  printf("testing ascending  memmove() with overlapping mem...");
  strcpy(str, pristine_str);
  memmove(str + 5, str, 10);
  compare(str, expected2);

  free(str);
  return 0;
}

Raspunde prin e-mail lui