[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#498825: Apollon sends UTF-8 strings to giFT with incorrect length



Package: apollon
Severity: important
Version: 1.0.2.1-4
Tags: patch

Hello,

Since Apollon seems to be unmaintained, I thought that I would report
this bug and its solution to Debian directly.

As you can guess from the subject line, Apollon sends UTF-8 strings
to giFT with an incorrect length. I noticed this bug after trying to
search for strings which contain UTF-8 characters in an UTF-8 locale.

To reproduce, simply do the following:

1) Make sure that you are using an UTF-8 enabled locale such as en_US.UTF-8
2) Launch Apollon
3) Make sure that "Allow downloads in the background" is enabled in
   the "Behaviour" tab of Apollon's configuration dialog.
4) Now exit Apollon by right-clicking its icon on the system tray and
   selecting "Quit"
5) In a terminal window, run the following commands:
   === 8< ===
   killall giftd
   giftd -v
   === >8 ===
   Do not close this terminal window; we will use it to see the bug's
   effects.
6) Now launch Apollon and wait until it connects to the Gnutella network.
7) Search for the following string in Apollon's search section:

   "aşk kırıntıları"

   I hope that you are able to copy and paste this string into Apollon.
   The second character is a small "s" with a cedilla whereas the remaining
   "i"s are small dotless Turkish "i"s.

8) Observe that giftd is printing something similar to the following
   messages in the terminal window you have opened in step 5.

=== 8< ===
[00:55:22] giFT: if_port.c:68(if_connection): packet 'SEARCH (900) query (aşk
kırıntıları) realm (everythSTATS;' appears incomplete, waiting for more input...
[00:55:27] giFT: if_port.c:68(if_connection): packet 'SEARCH (900) query (aşk
kırıntıları) realm (everythSTATS;STATS;' appears incomplete, waiting for more
input...
[00:55:32] giFT: if_port.c:68(if_connection): packet 'SEARCH (900) query (aşk
kırıntıları) realm (everythSTATS;STATS;STATS;' appears incomplete, waiting for
more input...
[00:55:37] giFT: if_port.c:68(if_connection): packet 'SEARCH (900) query (aşk
kırıntıları) realm (everythSTATS;STATS;STATS;STATS;' appears incomplete, waiting
for more input...
[00:55:42] giFT: if_port.c:68(if_connection): packet 'SEARCH (900) query (aşk
kırıntıları) realm (everythSTATS;STATS;STATS;STATS;STATS;' appears incomplete,
waiting for more input...
[00:55:47] giFT: if_port.c:68(if_connection): packet 'SEARCH (900) query (aşk
kırıntıları) realm (everythSTATS;STATS;STATS;STATS;STATS;STATS;' appears
incomplete, waiting for more input...
[00:55:52] giFT: if_port.c:68(if_connection): packet 'SEARCH (900) query (aşk
kırıntıları) realm (everythSTATS;STATS;STATS;STATS;STATS;STATS;STATS;' appears
incomplete, waiting for more input...
[00:55:57] giFT: if_port.c:68(if_connection): packet 'SEARCH (900) query (aşk
kırıntıları) realm (everythSTATS;STATS;STATS;STATS;STATS;STATS;STATS;STATS;'
appears incomplete, waiting for more input...
[00:56:02] giFT: if_port.c:68(if_connection): packet 'SEARCH (900) query (aşk
kırıntıları) realm
(everythSTATS;STATS;STATS;STATS;STATS;STATS;STATS;STATS;STATS;' appears
incomplete, waiting for more input...
[00:56:07] giFT: if_port.c:68(if_connection): packet 'SEARCH (900) query (aşk
kırıntıları) realm
(everythSTATS;STATS;STATS;STATS;STATS;STATS;STATS;STATS;STATS;STATS;' appears
incomplete, waiting for more input...
=== >8 ===

As you can see, there is something going wrong regarding the calculated
length of the message that is being passed to giFT. The dotless small
Turkish "i", is made up of /two/ bytes but should be treated as /one/
character. This appears to confuse Apollon, which can be seen from the
cut off string "everyth" and the string "STATS;" appended to it.

Well, about a year ago, I have gone into Apollon's source code and found
out that the function named "giFTSocket::writeBlock" in
"apollon/libapollon/giftsocket.cpp" is responsible for sending messages
to the giFT daemon:

=== apollon/libapollon/giftsocket.cpp ===
91  Q_LONG giFTSocket::writeBlock(QString data , Q_ULONG len)
92  {
93          QCString localdata = m_codec->fromUnicode(data);
94
95          return QSocket::writeBlock(localdata, len);
96  }
=== apollon/libapollon/giftsocket.cpp ===

As you can see, before the block of data is sent to giFT, it goes under
a conversion via the function "fromUnicode". This inevitably means that
the resulting QCString "localdata" has a different length compared to
that of "data" when "data" contains multi-byte UTF-8 characters.

And it turns out that it is this small detail which triggers this bug.
The solution is to use the "length()" method of the QCString class to
calculate the new length of the QCString variable "localdata" and pass
that newly calculated length to the QSocket::writeBlock function.

When one applies the patch below, the bug ceases to exist.

Regards,

M. Vefa Bicakci

Note: This patch has been in Pardus's (a Turkish GNU/Linux distribution)
      package repository for about a year or so.

Note: I am attaching the patch as well, in case my e-mail client
      messes up the appended patch.

=== 8< ===
--- apollon-1.0.2.1.orig/apollon/libapollon/giftsocket.cpp
+++ apollon-1.0.2.1/apollon/libapollon/giftsocket.cpp
@@ -92,7 +92,10 @@
 {
 	QCString localdata = m_codec->fromUnicode(data);

-	return QSocket::writeBlock(localdata, len);
+	/* Use localdata.length() instead of "len" because
+         * localdata.length() compensates for multibyte UTF-8
+         * characters whereas "len" does not */
+	return QSocket::writeBlock(localdata, localdata.length());
 }

 }

=== >8 ===



--- apollon-1.0.2.1.orig/apollon/libapollon/giftsocket.cpp
+++ apollon-1.0.2.1/apollon/libapollon/giftsocket.cpp
@@ -92,7 +92,10 @@
 {
 	QCString localdata = m_codec->fromUnicode(data);
 
-	return QSocket::writeBlock(localdata, len);
+	/* Use localdata.length() instead of "len" because
+         * localdata.length() compensates for multibyte UTF-8
+         * characters whereas "len" does not */
+	return QSocket::writeBlock(localdata, localdata.length());
 }
 
 }



Reply to: