[svn.haxx.se] · SVN Dev · SVN Users · SVN Org · TSVN Dev · TSVN Users · Subclipse Dev · Subclipse Users · this month's index

Re: BUG: svn enters unkillable state, tracked down to UTF conv in locale!=C

From: Denis Vlasenko <vda.linux_at_googlemail.com>
Date: 2006-07-04 10:16:41 CEST

On Monday 03 July 2006 18:33, Malcolm Rowe wrote:
> On Mon, Jul 03, 2006 at 05:28:20PM +0200, Denis Vlasenko wrote:
> > /.share/usr/src/subversion-1.1.3/apr/misc/unix/errorcodes.c:apr_strerror():390
> This is a rather old version of Subversion - could you see if you still
> get the same behaviour with 1.3.2?

Yes, I forgot to mention it. I tried the same on 1.3.2,
still fails.

> And if you do...
> > xlate.c:apr_xlate_conv_buffer():353 iconv() inbytes_left=0 outbytes_left=11 translated=0 errno=2 inbuf='.svn/format'
> > xlate.c:apr_xlate_conv_buffer():353 iconv() inbytes_left=2 outbytes_left=2 translated=-1 errno=7 inbuf='5.Р╖Ь(Д╖╪JЦ╞ .С╖^M'
> ... could you get a backtrace from the svn_io_file_open() call that opens
> this file? Yes, if we're trying to open a file with a garbage name,
> that's probably a bug.

The call chain is:

SVN_ERR(svn_path_cstring_from_utf8(&fname_apr, fname, pool));
apr_file_open(new_file, fname_apr, flag | APR_BINARY, perm, pool);
if (status) return svn_error_wrap_apr(status, _("Can't open file '%s'"), svn_path_local_style (fname, pool));
  make_error_internal(status, NULL);
  apr_strerror(status, errbuf, sizeof (errbuf));
  svn_utf_cstring_to_utf8(&msg_apr, errbuf, err->pool);
    SVN_ERR(get_ntou_xlate_handle_node(&node, pool));
    err = convert_cstring (dest, src, node, pool);
      SVN_ERR(convert_to_stringbuf(node, src, strlen (src), &destbuf, pool));

I think I see the problem:

svn_error_t *
svn_io_file_open (apr_file_t **new_file, const char *fname,
                  apr_int32_t flag, apr_fileperms_t perm,
                  apr_pool_t *pool)
  const char *fname_apr;
  apr_status_t status;

  SVN_ERR (svn_path_cstring_from_utf8 (&fname_apr, fname, pool));
  status = apr_file_open (new_file, fname_apr, flag | APR_BINARY, perm, pool);

  if (status)
    return svn_error_wrap_apr (status, _("Can't open file '%s'"),
                               svn_path_local_style (fname, pool));
    return SVN_NO_ERROR;

The filename is passed to svn_error_wrap_apr() in third argument,
but svn_error_wrap_apr() is a variadic function and:

svn_error_t *
svn_error_wrap_apr (apr_status_t status,
                    const char *fmt,
  svn_error_t *err, *utf8_err;
  va_list ap;
  char errbuf[255];
  const char *msg_apr, *msg;

  err = make_error_internal (status, NULL);

  if (fmt)
      /* Grab the APR error message. */
      apr_strerror (status, errbuf, sizeof (errbuf));
      utf8_err = svn_utf_cstring_to_utf8 (&msg_apr, errbuf, err->pool); // <---- HERE
      if (utf8_err)
        msg_apr = NULL;
      svn_error_clear (utf8_err);

      /* Append it to the formatted message. */
      va_start (ap, fmt);
      msg = apr_pvsprintf (err->pool, fmt, ap);
      va_end (ap);
      err->message = apr_psprintf (err->pool, "%s%s%s", msg,
                                   (msg_apr) ? ": " : "",
                                   (msg_apr) ? msg_apr : "");

  return err;

See? we call svn_utf_cstring_to_utf8() but it has no chance in hell
to get a filename, because va_start() is not yet called,
and therefore it has no way to obtain 3rd argument.

I inserted a fprintf(stderr, "%s: errbuf='%s'\n", __FUNCTION__, errbuf)
directly after apr_strerror (status, errbuf, sizeof (errbuf))
call and I see this:

svn_io_file_open: fname='busybox/.svn/dir-props'
svn_error_wrap_apr: errbuf='ФЁ╧╖юдд╖.╗Ю╖..╟╞h.╟╞A.Ю╖юдд╖.╗Ю╖Л╖Ю╖a.'
apr_xlate_conv_buffer():353 iconv() inbytes_left=4 outbytes_left=1 translated=-1 errno=7 inbuf='ФЁ╧╖юдд╖.╗Ю╖..╟╞h.╟╞A.Ю╖юдд╖.╗Ю╖Л╖Ю╖a.'
apr_xlate_conv_buffer():353 iconv() inbytes_left=4 outbytes_left=1 translated=-1 errno=7 inbuf='Ю╖a.'
apr_xlate_conv_buffer():353 iconv() inbytes_left=4 outbytes_left=1 translated=-1 errno=7 inbuf='Ю╖a.'
apr_xlate_conv_buffer():353 iconv() inbytes_left=4 outbytes_left=1 translated=-1 errno=7 inbuf='Ю╖a.'

That probably explains why the bug shows variable behaviour
(it happens in semi-random place). Seems like it is using
some uninitialized data (stack?).

However, no matter what garbage we feed to utf8 converter,
it still have to convert it, should not loop forever, right?

To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org
Received on Tue Jul 4 10:17:18 2006

This is an archived mail posted to the Subversion Dev mailing list.

This site is subject to the Apache Privacy Policy and the Apache Public Forum Archive Policy.