Daniel Shahaf wrote:
> But... isn't there a bug here?
> 
> [[[
> Index: subversion/libsvn_ra_svn/marshal.c
> ===================================================================
> --- subversion/libsvn_ra_svn/marshal.c        (revision 1133231)
> +++ subversion/libsvn_ra_svn/marshal.c        (working copy)
> @@ -285,14 +285,15 @@ static svn_error_t *readbuf_input(svn_r
>  
>                                    apr_size_t *len, apr_pool_t *pool)
>  {
>    svn_ra_svn__session_baton_t *session = conn->session;
> +  apr_size_t wanted = len;
>  
>    if (session && session->callbacks &&
>        session->callbacks->cancel_func)
>      SVN_ERR((session->callbacks->cancel_func)(
>                session->callbacks_baton));
>  
>    SVN_ERR(svn_ra_svn__stream_read(conn->stream, data, len));
> -  if (*len == 0)
> +  if (*len < wanted)
>      return svn_error_create(SVN_ERR_RA_SVN_CONNECTION_CLOSED, NULL, NULL);
>  
>    if (session)
> ]]]
> 
> >From svn_stream_t doxygen:
> 
>  * Handlers are obliged to complete a read or write to the maximum
>  * extent possible; thus, a short read with no associated error implies
>  * the end of the input stream, and a short write should never occur
>  * without an associated error.

I'm not sure what you're claiming.  If you're suggesting we should apply
the tweak above, that would make a "short read" throw a "hard" error (by
which I mean one that's not handled as EOF), whereas the doc string you
quoted says a short read should be treated as EOF.

That said, I can't quite follow why the code you quoted throws an error
if it reads no data.

 
> > -/* Read LEN bytes from CONN into a supposedly empty STRINGBUF.
> > - * POOL will be used for temporary allocations. */
> > -static svn_error_t *
> > -read_long_string(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
> > -                 svn_stringbuf_t *stringbuf, apr_uint64_t len)
> > +/* Read LEN bytes from CONN into already-allocated structure ITEM.
> > + * Afterwards, *ITEM is of type 'SVN_RA_SVN_STRING', and its string
> > + * data is allocated in POOL. */
> > +static svn_error_t *read_string(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
> > +                                svn_ra_svn_item_t *item, apr_uint64_t len)
> >  {
> > -  char readbuf[4096];
> > -  apr_size_t readbuf_len;
> > +  svn_stringbuf_t *stringbuf;
> >  
> >    /* We can't store strings longer than the maximum size of apr_size_t,
> >     * so check for wrapping */
> > @@ -578,67 +577,36 @@ read_long_string(svn_ra_svn_conn_t *conn
> >      return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
> >                              _("String length larger than maximum"));
> >  
> > +  /* Read the string in chunks.  The chunk size is large enough to avoid
> > +   * re-allocation in typical cases, and small enough to ensure we do not
> > +   * pre-allocate an unreasonable amount of memory if (perhaps due to
> > +   * network data corruption or a DOS attack), we receive a bogus claim 
> > that
> > +   * a very long string is going to follow.  In that case, we start small
> > +   * and wait for all that data to actually show up.  This does not fully
> > +   * prevent DOS attacks but makes them harder (you have to actually send
> > +   * gigabytes of data). */
> > +  stringbuf = svn_stringbuf_create_ensure(
> > +                (apr_size_t)(len < SUSPICIOUSLY_HUGE_STRING_SIZE_THRESHOLD
> > +                             ? len : 
> > SUSPICIOUSLY_HUGE_STRING_SIZE_THRESHOLD),
> > +                pool);
> > +
> 
> Sorry to point this just now, but this change seems to be problematic
> for the common case:
> 
> It will make *every* string read allocate 1MB of memory [...]

No it won't.  LEN is the expected length of the string being received,
and it will allocate the smaller of LEN and 1MB.

- Julian


Reply via email to