I have my socket comms pretty much working. The only thing that I'm not sure about is why I'm getting some garbage values at the end of my message. The first message I send contains some extra characters at the end, and every message after that is as expected...does anyone have any insight as to why this is happening?
Send:
CString string = "TEST STRING TO SEND";
char* szDest;
szDest = new char[string.GetLength()];
strcpy(szDest,string);
m_pClientSocket->Send(szDest,strlen(pMsg));
Receive: (this is using Qt)
char* temp;
int size = tcpSocket->bytesAvailable();
temp = new char[size];
tcpSocket->read(temp,size);
You will be missing the \0 in your temp after read, since it's not really transmitted (and probably shouldn't be)
You likely need to change the receive a little bit:
temp = new char[size + 1];
int realSize = tcpSocket->read(temp, size);
temp[realSize] = 0;
Btw, you would be better off with QTcpSocket::readAll() in this little snipped.
I don't know this CString class, but I see two bugs here:
Does GetLength() include the terminating NUL? If not, your char buffer is one byte smaller than it needs to be, and the strcpy is clobbering memory after the end of the buffer.
strlen(pMsg) is the length of something other than szDest. This is probably the immediate cause of your problem.
The char buffer appears to be unnecessary: why don't you just do
CString string = "TEST STRING TO SEND";
m_pClientSocket->Send(string, string.GetLength());
?
Related
This is a very easy problem but im stunned that i cant find a easy solution.
I am tring to create two strings that are path to files.
/Metadata/bitmap
/Metadata/Metadata.bin
but the second time i try to do the strcat() with the same src variable explodes into memory corruption
//create the dir strign to append
char* metadata_dir = strdup(MNT_POINT);
strcat(metadata_dir, "Metadata/");
char* bitmap_file = strdup("");
strcat(bitmap_file,metadata_dir);
strcat(bitmap_file,"bitmap");
printf("%s\n",bitmap_file);
char* meta_file = strdup("");
strcat(meta_file, metadata_dir);
strcat(meta_file, "Metadata.bin");
printf("%s\n",meta_file);
rigth in the line
strcat(meta_file, metadata_dir);
the memory corruption happens.
I am shure that metadata_dir is not corrupted because i can print it anywhere in the code and it looks fine.
The weird thing is that this happens depenend on the machine that is running on. In Ubuntu 64 works just fine. But in the 32bits version no.
strdup is only guaranteed to return a buffer big enough for the string you're duplicating (null terminator included); it may not (and often will not) have room for concatenating other things to it. You're overwriting random memory when you write past the end of the string with strcat.
EDIT: the solution, of course, is to malloc a buffer large enough in advance, instead of letting strdup do that.
Code fails as metadata_dir is only certainly big enough for MNT_POINT, not MNT_POINT and "Metadata/"
char* metadata_dir = strdup(MNT_POINT);
strcat(metadata_dir, "Metadata/");
To allocate and concatenate:
char *allocate_cat(const char *s1, const char *s2) {
size_t len1 = strlen(s1);
size_t size2 = strlen(s2) + 1;
char *s12 = malloc(len1 + size2); // allocate enough room for both
if (s12) {
memcpy(s12, s1, len1);
memcpy(s12 + s1, s2, size2);
}
return s12;
}
I'm using RAW socket to capture udp packets. After capturing I want to parse the packet and see what's inside.
The input I get from the socket is an unsigned char* buffer and it's length. I tried to put the buffer into a string but I guess I did it wrong because when I checked the string it was empty.
Any advice?
I don't know what you want to parse, but your have the buffer and it's length. So you can do everything you want with this memory. Look for pointer arithmetic. If you want to make an C-String out of the content, simply add an '\0' to the end of the memory block. But this assumes, that no other 0x00 are inside the buffer. So maybe you have to check that. Like πάντα ῥεῖ said.
Steps:
1: receive UDP package
2: cast like:
unsigned char* buffer;
char* cString = (char*) buffer;
3: check casted cString if an '\0' occurred before buffer size was reached. If it does, then create a new char* pointer to the byte after the '\0', but be aware of the buffer size. Save the pointer in an vector.
I made an code example, but haven't checked if it is runnable!
char* firstPtr = (char*) buffer;
size_t indexer = 0;
std::vector<char*> pointerVec;
pointerVec.push_back(firstPtr);
while(indexer < bufferSize) {
if(*(buffer + indexer) == '\0') {
if(indexer + 1 < bufferSize) {
char* cString = (char*) (buffer + indexer);
pointerVec.push_back(cString);
}
}
} // end while
After that you should have the positions of the different strings saved with the pointers inside of the vector. Now you can handle them to an copy mechanism which takes every C-String pointer and saves it's content to one C-String or String.
Hope you searched for something like that, because you question was unclear.
I'm having a string is not null terminated error, though I'm not entirely sure why. The usage of std::string in the second part of the code is one of my attempt to fix this problem, although it still doesn't work.
My initial codes was just using the buffer and copy everything into client_id[]. The error than occurred. If the error is correct, that means I've got either client_ id OR theBuffer does not have a null terminator. I'm pretty sure client_id is fine, since I can see it in debug mode. Strange thing is buffer also has a null terminator. No idea what is wrong.
char * next_token1 = NULL;
char * theWholeMessage = &(inStream[3]);
theTarget = strtok_s(theWholeMessage, " ",&next_token1);
sendTalkPackets(next_token1, sizeof(next_token1) + 1, id_clientUse, (unsigned int)std::stoi(theTarget));
Inside sendTalkPackets is. I'm getting a string is not null terminated at the last line.
void ServerGame::sendTalkPackets(char * buffer, unsigned int buffersize, unsigned int theSender, unsigned int theReceiver)
{
std::string theMessage(buffer);
theMessage += "0";
const unsigned int packet_size = sizeof(Packet);
char packet_data[packet_size];
Packet packet;
packet.packet_type = TALK;
char client_id[MAX_MESSAGE_SIZE];
char theBuffer[MAX_MESSAGE_SIZE];
strcpy_s(theBuffer, theMessage.c_str());
//Quick hot fix for error "string not null terminated"
const char * test = theMessage.c_str();
sprintf_s(client_id, "User %s whispered: ", Usernames.find(theSender)->second.c_str());
printf("This is it %s ", buffer);
strcat_s(client_id, buffersize , theBuffer);
Methinks that problem lies in this line:
sendTalkPackets(next_token1, sizeof(next_token1) + 1, id_clientUse, (unsigned int)std::stoi(theTarget));
sizeof(next_token1)+1 will always gives 5 (on 32 bit platform) because it return size of pointer not size of char array.
One thing which could be causing this (or other problems): As
buffersize, you pass sizeof(next_token1) + 1. next_token1 is
a pointer, which will have a constant size of (typically) 4 or 8. You
almost certainly want strlen(next_token1) + 1. (Or maybe without the
+ 1; conventions for passing sizes like this generally only include
the '\0' if it is an output buffer. There are a couple of other
places where you're using sizeof, which may have similar problems.
But it would probably be better to redo the whole logic to use
std::string everywhere, rather than all of these C routines. No
worries about buffer sizes and '\0' terminators. (For protocol
buffers, I've also found std::vector<char> or std::vector<unsigned char>
quite useful. This was before the memory in std::string was
guaranteed to be contiguous, but even today, it seems to correspond more
closely to the abstraction I'm dealing with.)
You can't just do
std::string theMessage(buffer);
theMessage += "0";
This fails on two fronts:
The std::string constructor doesn't know where buffer ends, if buffer is not 0-terminated. So theMessage will potentially be garbage and include random stuff until some zero byte was found in the memory beyond the buffer.
Appending string "0" to theMessage doesn't help. What you want is to put a zero byte somewhere, not value 0x30 (which is the ascii code for displaying a zero).
The right way to approach this, is to poke a literal zero byte buffersize slots beyond the start of the buffer. You can't do that in buffer itself, because buffer may not be large enough to accomodate that extra zero byte. A possibility is:
char *newbuffer = malloc(buffersize + 1);
strncpy(newbuffer, buffer, buffersize);
newbuffer[buffersize] = 0; // literal zero value
Or you can construct a std::string, whichever you prefer.
I've just finished C++ The Complete Reference and I'm creating a few test classes to learn the language better. The first class I've made mimics the Java StringBuilder class and the method that returns the string is as follows:
char *copy = new char[index];
register int i;
for(i = 0; i <= index; i++) {
*(copy + i) = *(stringArray + i);
} //f
return copy;
stringArray is the array that holds the string that is being built, index represents the amount of characters that have been entered.
When the string returns there is some junk after it, such as if the string created is abcd the result is abcd with 10 random characters after it. Where is this junk coming from? If you need to see more of the code please ask.
You need to null terminate the string. That null character tells the computer when when string ends.
char * copy = new char[ length + 1];
for(int i = 0; i < length; ++i) copy[i] = stringArray[i];
copy[length] = 0; //null terminate it
Just a few things. Declare the int variable in the tighest scope possible for good practice. It is good practice so that unneeded scope wont' be populate, also easier on debugging and kepping track. And drop the 'register' keyword, let the compiler determine what needs to be optimized. Although the register keyword just hints, unless your code is really tight on performance, ignore stuff like that for now.
Does index contain the length of the string you're copying from including the terminating null character? If it doesn't then that's your problem right there.
If stringArrary isn't null-terminated - which can be fine under some circumstances - you need to ensure that you append the null terminator to the string you return, otherwise you don't have a valid C string and as you already noticed, you get a "bunch of junk characters" after it. That's actually a buffer overflow, so it's not quite as harmless as it seems.
You'll have to amend your code as follows:
char *copy = new char[index + 1];
And after the copy loop, you need to add the following line of code to add the null terminator:
copy[index] = '\0';
In general I would recommend to copy the string out of stringArray using strncpy() instead of hand rolling the loop - in most cases strncpy is optimized by the library vendor for maximum performance. You'll still have to ensure that the resulting string is null terminated, though.
The following code fragment ends in an exception when executing the strncpy function:
#define MAX_FILENAME_LEN 127
typedef struct {
unsigned long nameLength;
char name[MAX_FILENAME_LEN + 1];
} filestructure;
char *fileName;
strncpy( fileName, filestructure->name, MAX_FILENAME_LEN );
*( fileName + MAX_FILENAME_LEN+1 ) = 0;
Ayone an idea what could go wrong? In the filestructure I have a filename that is 50 characters long so it is within the bounds... I am really a bit lost what could cause the problem in this simple code fragement...
You haven't allocated space for the destination buffer and fileName is uninitialized. So you try to copy somewhere. You should allocate memory and then bother freeing it.
char *fileName = new char[MAX_FILENAME_LEN + 1];
strncpy(...);
*(...) = 0;
doStuffWithTheBuffer( fileName );
delete[] fileName;// free memory
Also if you have a buffer of size N + 1 and want to copy N bytes maximum and null-terminate the buffer you should do
*(buffer + N) = 0;
Your question is tagged C++ but the code is pure C. Why do you do it the hard way? The fact that C string handling isn't all that easy to grasp (and that it isn't all that uncommon to get something wrong once in a while even for programmers who have a good grasp of it) is the very reason C++ let's you do without.
If you're writing C++, do it the C++ way. Use std::string. Honestly, it will spare you many hours of debugging such code.
You haven't allocated space for filename. Either do
filename = malloc (MAX_FILENAME_LEN * sizeof(char));
or
filename = strndup (filestructure->name, MAX_FILENAME_LEN);