This is the mail archive of the libc-alpha@sourceware.cygnus.com mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

final iconv call is buggy



In glibc-2.1.1, calling iconv(3) with a NULL pointer as inptr (the documented
way to emit the shift sequences which returns to the initial state) produces
wrong results. It produces many output bytes even though the previous
iconv() call has terminated with inbytesleft == 0 and both encodings are
stateless. In this case it should simply return 0 without doing anything.

$ gcc -O foo.c
$ a.out 
Before normal iconv call: inptr = 0x8048780, insize = 48, outptr = 0xbfffe708, outsize = 4096
After  normal iconv call: inptr = 0x80487b0, insize = 0, outptr = 0xbfffe738, outsize = 4048
Output bytes produced in this call: 48

Before final iconv call: outptr = 0xbfffe708, outsize = 4096
After  final iconv call: outptr = 0xbfffe738, outsize = 4048
Output bytes produced in this call: 48

So the total number of bytes produced is 96, although the string is really
only 48 bytes long.

                       Bruno


============================= foo.c ==========================================
#include <stdio.h>
#include <iconv.h>
#include <errno.h>

int main ()
{
  iconv_t cd = iconv_open ("UTF-8", "ISO-8859-1");
  const char *start = "This is an _uninteresting_ string of length 47.";
  const char *end = start + strlen (start) + 1;
  size_t dummy = 0;
  size_t length;
  char *result;

  /* Determine the length we need. */
  iconv (cd, NULL, NULL, NULL, &dummy);
  {
    size_t count = 0;
    char tmpbuf[4096];
    const char *inptr = start;
    size_t insize = end - start;
    while (insize > 0)
      {
        char *outptr = tmpbuf;
        size_t outsize = sizeof(tmpbuf);
        size_t res;
        printf ("Before normal iconv call: inptr = %p, insize = %zd, outptr = %p, outsize = %zd\n", inptr, insize, outptr, outsize);
        res = iconv (cd, &inptr, &insize, &outptr, &outsize);
        printf ("After  normal iconv call: inptr = %p, insize = %zd, outptr = %p, outsize = %zd\n", inptr, insize, outptr, outsize);
        printf ("Output bytes produced in this call: %zd\n\n", outptr - tmpbuf);
        if (res == (size_t)(-1))
          {
            if (errno == EINVAL)
              break;
            else
              return 1;
          }
        count += outptr - tmpbuf;
      }
    {
      char *outptr = tmpbuf;
      size_t outsize = sizeof(tmpbuf);
      size_t res;
      printf ("Before final iconv call: outptr = %p, outsize = %zd\n", outptr, outsize);
      res = iconv (cd, NULL, NULL, &outptr, &outsize);
      printf ("After  final iconv call: outptr = %p, outsize = %zd\n", outptr, outsize);
      printf ("Output bytes produced in this call: %zd\n\n", outptr - tmpbuf);
      if (res == (size_t)(-1))
        return 1;
      count += outptr - tmpbuf;
    }
    length = count;
  }

  return 0;
}
===============================================================================

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]