4

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:

//header
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;"

    packet_data.insert(packetSize-packetNum,QString(packet)); 
    QString d = packet_data.first(); d = "TOKEN=a7nCrDbaycWx2JzMir4m;UUU"

Debugger Data for verbosity's sake

Locals      
    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?

CybeX
  • 2,060
  • 3
  • 48
  • 115
  • This is doesn't really solve your problem, but you can ditch the bzero() call if you just allocate your *header_buffer* array like this: char data_buffer[maxSize]={}; That will set all elements of the array to 0. – antred Oct 22 '16 at 21:35
  • 1
    By the way, how did you even get this to compile?? C++ doesn't support variable-length arrays. In other words, the length of an array must be known at compile time, but you're using a runtime value to set the size of your array in the line that reads char data_buffer[maxSize]; //char[27] – antred Oct 22 '16 at 21:39
  • You reserve one char for null but is the buffer actually null terminated? – dtech Oct 22 '16 at 21:41

2 Answers2

3

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.

krzaq
  • 16,240
  • 4
  • 46
  • 61
  • Tried with QByteArray, same result as QString(), I'll try latin, i recall i used local8bit serverside, think that might be causing this issue, will let you know – CybeX Oct 22 '16 at 21:39
  • @KGCybeX Are you passing the correct number of bytes value? – krzaq Oct 22 '16 at 21:40
  • just tried with this `QByteArray ba = packet;` , `QString st = ba.toStdString().c_str();`, QString stri = QString(packet);`; both st and stri have the same output as described above, i.e. contains the UUU at the end. I have also change the server side code to use the QByteArray too. – CybeX Oct 23 '16 at 07:20
  • 1
    @KGCybeX that's unlikely to work. You should try `QByteArray`'s constructor that takes the second parameter that is number of bytes to read. – krzaq Oct 23 '16 at 07:21
  • Thank you, that did the trick. If possible, please edit your answer to include this, and a short explanation what might have caused this error of mine i.e the 3 "UUU" 's – CybeX Oct 23 '16 at 07:25
  • @KGCybeX edited, let me know if it's not clear enough – krzaq Oct 23 '16 at 07:34
1

What compiler you use (version and cppflags)?

//returns the size of largest packet using the received "header packet" - done successfully
int maxSize = getMaxPacketSize(header_buffer);
//maxSize = 27 char, etc

char data_buffer[maxSize]; //char[27]
//               ^
// really?-------+ Variable Length Array on standard C++?
// does this even compile?

VLA on SO.

Array declaration on cppreference.com:

noptr-declarator [ expr(optional) ] attr(optional)

...

  • expr - an integral constant expression (until C++14) a converted constant expression of type std::size_t (since C++14), which evaluates to a value greater than zero

How's the above relevant: if the code compiles (assumed with warning instead of error), this may result in Undefined Behaviour - e.g. where a subsequent function call (e.g. QString constructor) overwrites part of the VLA (on stack), wiping out the nul terminating character in this case, maybe other effects in other case.
If this happens, examining (at debug time) the content of the buffer (in the last example, the packet var instead of the d var) should reveal alterations.

Community
  • 1
  • 1
Adrian Colomitchi
  • 3,974
  • 1
  • 14
  • 23