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