misc/182102: bug in libiconv_none prevents MPD from starting
Henry Hu
henry.hu.sh at gmail.com
Sat Sep 14 23:30:01 UTC 2013
>Number: 182102
>Category: misc
>Synopsis: bug in libiconv_none prevents MPD from starting
>Confidential: no
>Severity: non-critical
>Priority: low
>Responsible: freebsd-bugs
>State: open
>Quarter:
>Keywords:
>Date-Required:
>Class: sw-bug
>Submitter-Id: current-users
>Arrival-Date: Sat Sep 14 23:30:00 UTC 2013
>Closed-Date:
>Last-Modified:
>Originator: Henry Hu
>Release: FreeBSD 10-CURRENT
>Organization:
Columbia University
>Environment:
FreeBSD pepsi 10.0-CURRENT FreeBSD 10.0-CURRENT #1 r255532M: Sat Sep 14 17:30:47 PDT 2013 root at pepsi:/usr/obj/usr/src/sys/MYKERNEL amd64
>Description:
Recently I updated to latest -CURRENT which enables WITH_ICONV.
Then I found MPD(audio/musicpd) failed to start.
It says:
path: invalid filesystem charset: UTF-8
MPD now uses the system iconv. I found the call in MPD to g_convert() failed.
After some tracing, I found that the iconv() call is not working properly.
Here is the test program:
#include <stdio.h>
#include <iconv.h>
int main() {
iconv_t cd = iconv_open("UTF-8", "UTF-8");
char *inbuf = " ";
char *inp = inbuf;
size_t inl = 1;
char outbuf[100];
char *outp = outbuf;
size_t oul = 1;
printf("%p %d %p %d\n", inp, inl, outp, oul);
int ret = iconv(cd, &inp, &inl, &outp, &oul);
printf("%d %p %d %p %d\n", ret, inp, inl, outp, oul);
}
This essentially loads the iconv_none module, because the input and output encodings are the same.
If you run it, you get something like this:
0x40094c 1 0x7fffffffd4d0 1
0 0x40094c 0 0x7fffffffd4d0 0
However, according to iconv()'s manpage, after iconv():
*src Pointer to the byte just after the last character fetched.
*srcleft Number of remaining bytes in the source buffer.
*dst Pointer to the byte just after the last character stored.
*dstleft Number of remainder bytes in the destination buffer.
So both src (inp) and dst (outp) should move forward, but they stay the same. This makes g_convert() think that the conversion is not completed and there are partial inputs.
In /usr/src/lib/libiconv_modules/iconv_none/citrus_iconv_none.c, we have:
static int
/*ARGSUSED*/
_citrus_iconv_none_iconv_convert(struct _citrus_iconv * __restrict ci __unused,
char * __restrict * __restrict in, size_t * __restrict inbytes,
char * __restrict * __restrict out, size_t * __restrict outbytes,
uint32_t flags __unused, size_t * __restrict invalids)
{
....
memcpy(*out, *in, len);
in += len;
*inbytes -= len;
out += len;
*outbytes -= len;
*invalids = 0;
....
Here, the function attempted to move the in & out pointers forward. However, now it just moves the local copy. It should do
*in += len;
..
*out += len;
instead.
After applying the patch, it works correctly, and MPD starts.
Please fix this.
>How-To-Repeat:
Compile and run this:
#include <stdio.h>
#include <iconv.h>
int main() {
iconv_t cd = iconv_open("UTF-8", "UTF-8");
char *inbuf = " ";
char *inp = inbuf;
size_t inl = 1;
char outbuf[100];
char *outp = outbuf;
size_t oul = 1;
printf("%p %d %p %d\n", inp, inl, outp, oul);
int ret = iconv(cd, &inp, &inl, &outp, &oul);
printf("%d %p %d %p %d\n", ret, inp, inl, outp, oul);
}
And observe that the input & output pointers of iconv() are not increased.
>Fix:
Patch attached.
Patch attached with submission follows:
Index: lib/libiconv_modules/iconv_none/citrus_iconv_none.c
===================================================================
--- lib/libiconv_modules/iconv_none/citrus_iconv_none.c (çæ¬ 255575)
+++ lib/libiconv_modules/iconv_none/citrus_iconv_none.c (å·¥ä½å¯æ¬)
@@ -115,9 +115,9 @@
len = *outbytes;
}
memcpy(*out, *in, len);
- in += len;
+ *in += len;
*inbytes -= len;
- out += len;
+ *out += len;
*outbytes -= len;
*invalids = 0;
if (e2big)
>Release-Note:
>Audit-Trail:
>Unformatted:
More information about the freebsd-bugs
mailing list