KGCybeX KGCybeX - 11 months ago 70
C++ Question

Convert char[] to Qstring adding extra 3 chars

See bottom for TL;DR

Background info: (for perspective)

I am implementing a client-server, the client requests data, sending via a set char buffer, with set size of char[256]

The server responds in kind with a 2 stage response,
first sending a 'header packet' using a header buffer (on both client and server with size char[20]), containing the number of packets to follow and the size of the largest packet to be sent (to allocate the "data" buffer),

assume the text sent from server is as follows

QString text = QString("TOKEN=1SOMETOKENSTRING123;");
//length of text = 26 char

this "header packet" is successfully received, parsed and implemented with no defects in converting to a QString by using:

char header_buffer[20];
bzero(header_buffer, sizeof (header_buffer));
//assign header_buffer using socket.recv()
QString header = QString(header_buffer);

This is done successfully

Problem info:

The header is parsed and outputs attributes size (The max packet size) and count(number of 'data' packets to follow)

Here lies the problem area:

//data packet section

//returns the size of largest packet using the received "header packet" - done successfully
int maxSize = getMaxPacketSize(header_buffer);
//maxSize = 27 char, which is the length of the 'text' String sent from the server, thus

char data_buffer[maxSize]; //char[27]
bzero(data_buffer, sizeof (data_buffer));
//assign data_buffer using socket.recv()
QString data = QString(data_buffer);
qDebug() << data_buffer; CORRECT //displays "TOKEN=1SOMETOKENSTRING123;"
qDebug() << data; ERROR //displays "TOKEN=1SOMETOKENSTRING123;UUU"

Exact Problem:

Creating new QString from a char[] adds 3 'U' characters to the end of string:

Basic example:

char cArray[27] //assume it has contents to fill all, size/count = 27
QString str = QString(cArray);
int len = str.length();
//len = 30, last 3 char of str = "UUU"

Data Example(**actually data):

int packetSize = getMaxPacketSize(buffer); buffer[20] = "COUNT=2;SIZE=27;\000\000\000\000"
char packet[packetSize]; // = 27
size_t size = sizeof (packet); // = 27
bzero(packet, sizeof (packet));

if (recv(sockfd,packet,sizeof (packet),0) < 0) {
qDebug() << "ERROR netman: reading data from socket";
//more code here

//Add packet to packet_data list

//NOTE : QList<QString> packet_data = QList<QString>();
//NOTE: packet[27] = "TOKEN=a7nCrDbaycWx2JzMir4m;"

QString d = packet_data.first(); d = "TOKEN=a7nCrDbaycWx2JzMir4m;UUU"

Debugger Data for verbosity's sake

d "TOKEN=a7nCrDbaycWx2JzMir4m;UUU" QString
[0] 'T' 84 0x0054 QChar
[1] 'O' 79 0x004f QChar
[2] 'K' 75 0x004b QChar
[3] 'E' 69 0x0045 QChar
[4] 'N' 78 0x004e QChar
[5] '=' 61 0x003d QChar
[6] 'a' 97 0x0061 QChar
[7] '7' 55 0x0037 QChar
[8] 'n' 110 0x006e QChar
[9] 'C' 67 0x0043 QChar
[10] 'r' 114 0x0072 QChar
[11] 'D' 68 0x0044 QChar
[12] 'b' 98 0x0062 QChar
[13] 'a' 97 0x0061 QChar
[14] 'y' 121 0x0079 QChar
[15] 'c' 99 0x0063 QChar
[16] 'W' 87 0x0057 QChar
[17] 'x' 120 0x0078 QChar
[18] '2' 50 0x0032 QChar
[19] 'J' 74 0x004a QChar
[20] 'z' 122 0x007a QChar
[21] 'M' 77 0x004d QChar
[22] 'i' 105 0x0069 QChar
[23] 'r' 114 0x0072 QChar
[24] '4' 52 0x0034 QChar
[25] 'm' 109 0x006d QChar
[26] ';' 59 0x003b QChar
[27] 'U' 85 0x0055 QChar
[28] 'U' 85 0x0055 QChar
[29] 'U' 85 0x0055 QChar
message "AUTH;U=user@example;P=Pass;" char *
packet "TOKEN=a7nCrDbaycWx2JzMir4m;" char [27]
packetNum 1 int
packetSize 27 int
s "COUNT=2;SIZE=27;" QString
size 27 size_t
this @0x7fffffffd190 netman
buffer "COUNT=2;SIZE=27;\000\000\000\000" char [20]
cli_addr @0x7fffffffd1c0 sockaddr_in
clilen 1431695692 socklen_t
n 1436538608 int
newsockfd 32767 int
packet_data <1 items> QList<QString>
serv_addr @0x7fffffffd1b0 sockaddr_in
server @0x7ffff5f071c0 hostent
sockfd 13 int

I have no idea where these 3 extra char's come from!

Anyone any suggestions/ideas?

Answer Source

The major problem here is that you're passing a char* to functions that expect a c-string. That is, a string with a zero value at the end. But your input from the socket doesn't contain such a byte.

Reading past the end of an array is undefined behavior, but in this case it's fairly easy to reason what happens: bytes are read until a null value isn't found, and it's found fairly soon (after 3 more bytes)1.

You can easily fix it by using functions that take exact number of bytes they're supposed to read from an array.

The simplest way is to use fromUtf8 or fromLatin1 or fromLocal8Bit member function of QString to provide the number of bytes you want to read:

QString str = QString::fromUtf8(cArray, number_of_bytes);

That being said, consider using QByteArray for data read from the network:

QByteArray data(cArray, number_of_bytes);

1 reasoning what happens with undefined behavior should be taken with grain of salt, because compilers are free to do almost anything if they can probe it happens.