0

I've been trying to learn a bit about socket programming in C++ and so have been developing a basic IRC bot. I've got it connecting and working, but I'm having an issue determining who has joined the channel (i.e. was the JOIN command for the bot itself, for a random user, or for me).

I'm using CLion on Windows 7.

I've got the following code:

//determine if message is JOIN command if(regex_search(line, match, std::regex(R"(:([^!]*)!.*?JOIN)"))) { //get the nickname of the bot (details.getNickName() shown in next code segment) const char *trueNick = details.getNickName(); //reformat nickname because the following is returned from the method alone //0x10042d0f9 <_ZStL6ignore+119> "CPlusPlusBotTest" const char *nick = string(details.getNickName()).c_str(); //get the name of the user who joined const char *name = match.str(1).c_str(); //debugging std::cout << name << " - name\n"; std::cout << nick << " - nick\n"; //might not be the correct way to compare the two? but I'll sort that out later if(name != nick) { //welcome the user char param[1024]; sprintf(param, "%s :Hello, %s", details.getChannel(), name); sendData("PRIVMSG", param); } } 

I am unsure why I get the excess "stuff" (I have no idea what it is) from my getter, as it's simply a case of returning a private variable:

const char* BotDetails::getNickName() { return nickName; } 

Regardless, that's not my issue given I can get rid of it (despite it possibly being rather hacky).

My issue is that when I connect to the channel for testing, and I set a breakpoint on the line assigning trueNick so I can see what happens as I step through the program, the following occurs:

1) trueNick is assigned the value: 0x10042d0f9 <_ZStL6ignore+119> "CPlusPlusBotTest"

2) nick is assigned the value: "CPlusPlusBotTest"

3) name is assigned the value: "Seanharrs" and nick is assigned the value: "Seanharrs"

This means when my debug statements run, nick and name are the same value. I am not sure why nick is being reassigned to be the same value as name, this should not occur. It happens every time as well, not just for my name. I tried using char arrays and strings instead but to no avail. I also find it strange that trueNick is never affected, it's only these two variables. Any help is appreciated (even if it's just an alt/better way to check this rather than a fix, because it may well be just an oddity on my end that nobody else experiences).

15
  • You have some things similar to the common string stream problem happening: stackoverflow.com/questions/1374468/… Commented Jan 9, 2016 at 7:59
  • 2
    Stop using char *s, and use std::string instead. This will automagically solve a lot of your issues. Commented Jan 9, 2016 at 8:00
  • 3
    const char *nick = string(details.getNickName()).c_str(); Won't using nick be UB? Commented Jan 9, 2016 at 8:02
  • 6
    Then convert at the last possible step only. Commented Jan 9, 2016 at 8:10
  • 1
    @Seanharrs char param[1024]; sprintf(param, "%s :Hello, %s", details.getChannel(), name); Hope that the details.getChannel() function plus the other text is a string less than 1024 characters. Since you're using C++, use std::ostringstream to ensure there is no buffer overflow. Commented Jan 9, 2016 at 8:34

1 Answer 1

2

This line causes undefined behavior:

const char *nick = string(details.getNickName()).c_str(); 

It will construct a temporary string object and return a pointer to the data. However, being temporary means that it will be destructed immediately and the pointer will be invalid.

EDIT:

It turned out that OP misunderstood the additional information displayed by the debugger and interpreted it as the value of the variable. After clarifying that, there is no need for the "conversion" which causes undefined behavior and the code can just be:

const char *nick = details.getNickName(); const char *name = match.str(1).c_str(); if( strcmp(name, nick) == 0 ) { //.... } 

The example of undefined behavior is still shown below.

EXAMPLE CODE FOR THE UNDEFINED BEHAVIOR

Consider this code:

#include <iostream> using namespace std; int main() { const char t[] = "0x10042d0f9 <_ZStL6ignore+119> \"CPlusPlusBotTest\""; const char* pTrue = t; const char* p = std::string(t).c_str(); std::cout << pTrue << std::endl; std::cout << p << std::endl; return 0; } 

it will output (rather: it may output):

0x10042d0f9 <_ZStL6ignore+119> "CPlusPlusBotTest" 0x10042d0f9 <_ZStL6ignore+119> "CPlusPlusBotTest" 

(ideone.com used for this example and gave above output)

So from this you might think it was okay. (note however: I don't get the conversion mentioned by OP).

Now consider this code:

#include <iostream> using namespace std; int main() { const char tdemo[] = "Some demo text"; // Added this line const char t[] = "0x10042d0f9 <_ZStL6ignore+119> \"CPlusPlusBotTest\""; const char* pTrue = t; const char* p = std::string(t).c_str(); const char* pdemo = std::string(tdemo).c_str(); // Added this line std::cout << pTrue << std::endl; std::cout << p << std::endl; return 0; } 

it will output (rather: it may output)

0x10042d0f9 <_ZStL6ignore+119> "CPlusPlusBotTest" Some demo text 

(ideone.com used for this example and gave above output)

As you can see the value of *p changed "unexpectedly". It changed because the pointer was invalid in the sense that it pointed to memory that was freed already. The extra line

const char* pdemo = std::string(tdemo).c_str(); 

caused the compiler to reuse that memory and consequently the value *p changed.

In other words - you have undefined behavior.

My guess is that your problem is inside details.getNickName();

It seems to me that the pointer returned is not pointing to the same test every time. Maybe it has some initialization problem so that it returns the wrong value the first time and then correct values afterwards.

The line causing undefined behavior can not do the conversion claimed by OP so it must be the return value from the function that changes.

Sign up to request clarification or add additional context in comments.

3 Comments

That makes sense, thanks. I see now why it was troublesome and will avoid using that method in the future. Still doesn't explain why the 0x10042d0f9 <_ZStL6ignore+119> existed outside my 'string' variable though (it did not appear on std::cout << trueNick; but it appeared when I viewed the value of trueNick in a debugger, it was "outside" the 'string', but still affecting its value so it was considered different to "CPlusPlusBotTest", even though the only 'string' part of trueNick was "CPlusPlusBotTest")
@Seanharrs - Read my comment under the question. 0x10042d0f9 <_ZStL6ignore+119> does not exists!! It is just some additional information displayed by the debugger. It has nothing to do with the value of the string.
I assumed it would be "extra" info that has nothing to do with the value of the string, except it appeared to change the value because 0x10042d0f9 <_ZStL6ignore+119> "CPlusPlusBotTest" was considered different to "CPlusPlusBotTest". I assume this was just because I was comparing with ==, though. Thanks again. :) and I didn't accept because I couldn't find the button :P I have now.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.