C++ merge 2 wchar_t*

0

I have an interesting problem and I'm not sure why.

inline void mergeWChar(wchar_t*& dest, const wchar_t* source) {
    if (dest == nullptr) {
        dest = const_cast<wchar_t*>(source);
        return;
    }
    int size = wcslen(dest);
    wcscat_s(dest, size, source);
}
inline void test() {
    wchar_t* msg = nullptr;
    wchar_t* t = L"BLA.BLA.BLA";
    mergeWChar(msg, L"Ts is jut a phrase in order to test my function");
    mergeWChar(msg, t);
}

I'm trying to make a function that will merge tougher 2 wchar_t* using the wcscat_s function but from some reason is not working and I'm receiving this error message.

Exception thrown at 0x5D8C3A18 (ucrtbased.dll) in ConsoleApplication1.exe: 0xC0000005: Access violation writing location 0x0082DD60.

Also, I've checked these 2 questions already and is not really helped me.

wcscat_s problem

wcscat_s function - buffer error

WHAT I CAN'T DO

I'm working with some legacy code and I can NOT use some things like:

  1. wstring
  2. to_wstring
  3. wchar_t var[size] <- that's not going to work.
c++
visual-c++
asked on Stack Overflow Jun 14, 2019 by Mircea • edited Jun 14, 2019 by Werner Henze

1 Answer

1

Here:

mergeWChar(msg, t);

msg points to the string literal L"Ts is jut a phrase in order to test my function". You cannot modify a string literal.

You want this:

inline void mergeWChar(wchar_t*& dest, const wchar_t* source) {
  if (dest == nullptr) {
    dest = const_cast<wchar_t*>(source);
    return;
  }

  wchar_t *newdest = (wchar_t*)malloc((wcslen(dest) + wcslen(source) + 1) * sizeof *newdest);
  wcscpy(newdest, dest);      // the *_s functions are useless here
  wcscat(newdest, source);    // as you know that newdest point to
                              // a long enough buffer
  dest = newdest;
}

Disclaimer: no error checking is done here for brevity.

The origin of the problem is the poor design of the mergeWChar function and the questionable use of const_cast<wchar_t*> which basically allows you to assign a pointer to a constant string to a normal pointer, which then allows you to modify that constant memory which eventually fails.

However there is a problem with this design: you cannot free the allocated memory because the dest pointer is not necessarily a pointer that has been obained via malloc. Therefore following design is better IMO:

inline void mergeWChar(wchar_t*& dest, const wchar_t* source) {
  int size = (dest ? wcslen(dest) : 0) + wcslen(source) + 1;
  wchar_t *newdest = (wchar_t*)malloc(size * sizeof *newdest);
  if (dest)
    wcscpy(newdest, dest);
  else
    newdest[0] = 0;
  wcscat(newdest, source);
  dest = newdest;
}

That way there is no ugly cast and no risc of a non const pointer pointing to constant memory and you can be sure that the pointer modified by mergeWChar can be freed no matter what. The cost is that you need more memory.

Example of usage:

...
wchar_t* msg = nullptr;
wchar_t* t = L"BLA.BLA.BLA";
mergeWChar(msg, L"Ts is jut a phrase in order to test my function");
mergeWChar(msg, t);
...
free(msg);
...
answered on Stack Overflow Jun 14, 2019 by Jabberwocky • edited Jun 14, 2019 by Jabberwocky

User contributions licensed under CC BY-SA 3.0