This is the mail archive of the gcc-help@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

GCC 5/6: C++'s std::string with "qsort" - works with old ABI, fails with new one


Hello,

first, I know that std::sort() is better than qsort. Still, I'd like to understand
why this legacy code fails with GCC 5's new string ABI.

Namely, with the new ABI, the second call to the compare function is wrong - and
hence the final order. Additionally, with ASAN enabled, it fails with
"attempting free on address which was not malloc".


The following is the output with the new/old ABI and at the end is the
program.


WORKING / OLD ABI:
==================================================================
$ g++ -D_GLIBCXX_USE_CXX11_ABI=0 -fsanitize=address -std=c++11 -g test.cc
$ ./a.out
-1: 8
 0: 8
 1: 8 <-> 8
 2: 8 <-> 8
sort_function: 'L2' (len=2) <-> 'L1' (len=2) ---> 1
sort_function: '1' (len=1) <-> 'L1' (len=2) ---> -1
0: 1
1: L1
2: L2
0
==================================================================


FAILING / NEW ABI:
==================================================================
$ g++ -D_GLIBCXX_USE_CXX11_ABI=1 -fsanitize=address -std=c++11 -g test.cc
$ ./a.out
-1: 32
 0: 32
 1: 32 <-> 32
 2: 32 <-> 32
sort_function: 'L2' (len=2) <-> 'L1' (len=2) ---> 1
sort_function: '1' (len=1) <-> 'L2' (len=2) ---> -1
0: 1
1: L2
2: L1
=================================================================
==23500==ERROR: AddressSanitizer: attempting free on address which was not malloc()-ed: 0x7fff6a0f51b0 in thread T0
    #0 0x7eff5773be5a in operator delete(void*) ../../../../libsanitizer/asan/asan_new_delete.cc:92
    #1 0x4011b6 in Mystr::~Mystr() test.cc:9
    #2 0x40108f in main test.cc:41
    #3 0x37af01ed5c in __libc_start_main (/lib64/libc.so.6+0x37af01ed5c)
    #4 0x400c88  (a.out+0x400c88)

==================================================================

Any idea whether it is valid or not - and if the latter, why? And
why it fails?

Tobias

PS: Test case
==================================================================
#include <assert.h>
#include <string.h>
#include <string>

#define MY_LEN 3

typedef int (*compare_f)(const void *e1, const void *e2);

class Mystr {
 public:
  std::string str[MY_LEN];
  void resort(compare_f comparef);
};

void Mystr::resort(compare_f comparef) {
  assert(comparef != NULL);
  qsort(str, std::size_t( MY_LEN ), sizeof(std::string), comparef);

__builtin_printf("0: %s\n", str[0].c_str());
__builtin_printf("1: %s\n", str[1].c_str());
__builtin_printf("2: %s\n", str[2].c_str());
}


static int
sort_function (const void* p1, const void* p2)
{
  const std::string *p_layer1 = reinterpret_cast<const std::string*>(p1 );
  const std::string *p_layer2 = reinterpret_cast<const std::string*>(p2 );

  int res = strcmp(p_layer1->c_str(), p_layer2->c_str());
  __builtin_printf("sort_function: '%s' (len=%lu) "
                   "<-> '%s' (len=%lu) ---> %d\n", p_layer1->c_str(),
                   p_layer1->length(), p_layer2->c_str(), p_layer2->length(),
                   res);
  return res;
}

int
main () {
  class Mystr ms;
  ms.str[0] = "1";
  ms.str[1] = "L2";
  ms.str[2] = "L1";
  __builtin_printf("-1: %lu\n", sizeof(std::string));
  __builtin_printf(" 0: %lu\n", sizeof(ms.str[0]));
  long diff = (char*)&ms.str[1] - (char*)&ms.str[0];
  __builtin_printf(" 1: %lu <-> %ld\n", sizeof(ms.str[1]), diff);
  __builtin_printf(" 2: %lu <-> %ld\n", sizeof(ms.str[2]), diff);
  diff = &ms.str[2] - &ms.str[1];
  ms.resort((compare_f) sort_function);

  return 0;
}


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]