Random exception thrown??

Hello folks! It has been a fair while since I came here, but alas I have some questions.

Alright, to start off, I have a structure with a constructor:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
typedef struct _Wl {

    std::wstring category;
    std::wstring name;
    int rank;
    inline _Wl(std::wstring, int);

} weaponList, WL;

inline _Wl::_Wl(std::wstring nameStr, int rankInt) : name(nameStr), rank(rankInt) {

    for (int i = 0; i < 32; i++) { //determines category of weapon

        if (name == categories::BattleRifles[i]) { //comparing strings

            category = _T("Battle Rifles");
            break;

        } 
        //more cases...
    }
}


Now, this is all fine and dandy (100+ objects that have no problems with this struct).

However, something interesting on some certain objects occurs. For example take this innocent looking object:
static _Wl MJOLNIR(_T("Mjolnir"), NULL);

(Do note that the '_T("Mjolnir")' should be viewed as 'L"Mjolnir"'.)

Whenever I try to execute my program with this exact typing, I get an exception in the wide character library (wchar.h):
1
2
3
4
5
6
7
8
9
10
11
12
__inline int __CRTDECL wmemcmp(
        _In_reads_(_N) wchar_t const* _S1,
        _In_reads_(_N) wchar_t const* _S2,
        _In_           size_t         _N
        )
    {
        for (; 0 < _N; ++_S1, ++_S2, --_N)
            if (*_S1 != *_S2) //this line in particular
                return *_S1 < *_S2 ? -1 : 1;

        return 0;
    }


Apparently, the function cannot read '_S2', but can read '_S1' ( L"Mjolnir"), _N (7), and *_S1 (77 ['M' in ASCII]) just fine. This is strange, so I thought it had to do with my code, but I searched my whole thing and couldn't find one single invocation of the wmemcmp() function.

So, I added one space to the line in the string:
static _Wl MJOLNIR(_T("Mjolnir "), NULL);

And it suddenly threw no exceptions, leading me conclude that it could read the memory.

So that leads me to the question, why does a single space manage to differentiate an exception? Although I did not invocate the exact function, does my comparison operator invoke it indirectly? And if so, why does it throw that error?
Any help would be appreciated!

does my comparison operator invoke it indirectly?

Now is a good time to investigate your debugger.

I get an exception

Which exception?

typedef struct _Wl

This is illegal. Names that begin with an underscore followed by a capital letter are strictly reserved to the implementation for any use (i.e., they're potentially macro names), and so user code that uses those names has undefined behavior. You will generally get away with this, but it is poor practice nevertheless.

Further, there is no separate name space for tag names in C++. Is is therefore a waste of time to typedef class names. (N.B.: name space is a C language concept unrelated to C++'s namespace keyword.)

It makes no sense to combine width-agnostic TCHAR with wide character strings. Indeed, it makes no sense to use TCHAR at all in modern software.

If your code must be encoding-sensitive, stick exclusively to Unicode, but disfavor UTF-16.

wmemcmp is likely being called by line 14 in the provided code, from the standard library.

I can't help but suspect that either nameStr or the elements of categories:BattleRifles have been mis-initialized in some way. And there's an obvious potential culprit: how is _T defined? You say that _T("some literal") is equivalent to L"some literal", but what is it actually?

In particular if it's actually a typedef for wchar_t *, that would explain why your code is segfaulting.

Additionally, +1 to what mbozzi said.

-Albatross
Last edited on
@mbozzi
Now is a good time to investigate your debugger.


I use Visual Studio 2019, but I have basically 0 idea where things are most of the time (it's overwhelming for me, personally), so if you could point me where to investigate this, that would be useful. (Nevermind, the debugger is right in front of my face)


Which exception?


It says "read access violation". I'm guessing that's an overflow? (yikes...)


This is illegal. Names that begin with an underscore followed by a capital letter are strictly reserved to the implementation for any use (i.e., they're potentially macro names), and so user code that uses those names has undefined behavior. You will generally get away with this, but it is poor practice nevertheless.


I used it as a shorthand for easy implementation of new objects, since it's faster to type 3 characters rather than 10. I'll change it though, since it shouldn't be too hard to change it.


It makes no sense to combine width-agnostic TCHAR with wide character strings. Indeed, it makes no sense to use TCHAR at all in modern software.


I went a bit back into digging why my past self wrote it like this, and guess what? The article I had been using was from 2002!. I had been using the article because I was trying to figure out the conversions for certain WIN32 functions. Probably the biggest facepalm I've ever had since I wasted like 4+ hours implementing encoding. Guess I'll have to waste another 4 fixing it back...

@Albatross
wmemcmp is likely being called by line 14 in the provided code, from the standard library.


Found it in the XString library in my compiler, but strangely, there is no mention of wmemcmp in the operator of the code I gave (well of course, since they're different libraries).


In particular if it's actually a typedef for wchar_t *, that would explain why your code is segfaulting.


Surprise surprise, it's a segfault. I guess I now learned my lesson on obsolescence and stupidity.

Thanks for showing the problems! Ah now, the fixing...
Last edited on
Topic archived. No new replies allowed.