Hi Stefan,

APR is a moving target...

On Sep 7, 2010, at 6:42 , Greg Stein wrote:

> The buildbots are failing all over the place after this revision...
> 
> On Mon, Sep 6, 2010 at 20:09,  <s...@apache.org> wrote:
>> Author: stsp
>> Date: Tue Sep  7 00:09:46 2010
>> New Revision: 993183
>> 
>> URL: http://svn.apache.org/viewvc?rev=993183&view=rev
>> Log:
>> Introduce a new family of functions to parse numbers from strings.
>> 
>> The goal is to replace direct calls to functions like atoi() and 
>> apr_atoi64(),
>> which have very inconvenient error handling to the point where a lot of
>> our code simply ignores conversion errors and continues operating with
>> the converted data in potentially undefined state.
>> The new functions, on the other hand, report conversion errors via the
>> standard Subversion error handling interface, thereby not allowing callers
>> to ignore conversion errors.
>> 
>> This commit also switches selected pieces of code over to the new functions.
>> More conversion to come.
>> 
>> * subversion/include/svn_string.h
>>  (svn_cstring_strtoi64, svn_cstring_atoi64, svn_cstring_atoi,
>>   svn_cstring_strtoui64, svn_cstring_atoui64, svn_cstring_atoui): Declare.

Uh oh, some buildbots complain about APR_UINT{32,64}_MAX being 
undefined.  It looks like they were first defined in APR 1.3.

>> 
>> * subversion/libsvn_subr/svn_string.c
>>  (): Include svn_private_config.h for the _() gettext macro.
>>  (svn_cstring_strtoi64, svn_cstring_strtoui64, svn_cstring_atoi64,
>>   svn_cstring_atoi): New.
>> 
>> * subversion/libsvn_ra_serf/serf.c
>>  (dirent_walker): Use svn_cstring_atoi64() instead of apr_atoi64().
>> 
>> * subversion/libsvn_diff/parse-diff.c
>>  (parse_offset): Call svn_cstring_strtoui64() instead of calling
>>   apr_atoi64() and performing manual overflow checking.
>> 
>> * subversion/mod_dav_svn/reports/log.c
>>  (dav_svn__log_report): Use svn_cstring_atoi() instead of atoi() for
>>   parsing CDATA of the "limit" element.

subversion/mod_dav_svn/reports/log.c:320: warning: implicit declaration of 
function ‘malformed_element_error’

I get just a warning, but this is an error on some buildbots.  

FWIW, copy-pasting the static function from replay.c makes the 
compiler happy.

>> 
>> * subversion/mod_dav_svn/reports/replay.c
>>  (dav_svn__replay_report): Use svn_cstring_strtoi64() instead of atoi() for
>>   parsing CDATA of the "send-deltas" element.
>> 
>> * subversion/libsvn_subr/win32_xlate.c
>>  (get_page_id_from_name): Use svn_cstring_atoui() instead of atoi() to parse
>>   the number of a codepage.
>> 
>> * subversion/libsvn_subr/io.c
>>  (svn_io_read_version_file): Use svn_cstring_atoi() instead of atoi().
>> 
>> * subversion/libsvn_subr/hash.c
>>  (svn_hash_read): Use svn_cstring_atoi() instead of atoi().
>> 
>> Modified:
>>    subversion/trunk/subversion/include/svn_string.h
>>    subversion/trunk/subversion/libsvn_diff/parse-diff.c
>>    subversion/trunk/subversion/libsvn_ra_serf/serf.c
>>    subversion/trunk/subversion/libsvn_subr/hash.c
>>    subversion/trunk/subversion/libsvn_subr/io.c
>>    subversion/trunk/subversion/libsvn_subr/svn_string.c
>>    subversion/trunk/subversion/libsvn_subr/win32_xlate.c
>>    subversion/trunk/subversion/mod_dav_svn/reports/log.c
>>    subversion/trunk/subversion/mod_dav_svn/reports/replay.c
>> 
>> Modified: subversion/trunk/subversion/include/svn_string.h
>> URL: 
>> http://svn.apache.org/viewvc/subversion/trunk/subversion/include/svn_string.h?rev=993183&r1=993182&r2=993183&view=diff
>> ==============================================================================
>> --- subversion/trunk/subversion/include/svn_string.h (original)
>> +++ subversion/trunk/subversion/include/svn_string.h Tue Sep  7 00:09:46 2010
>> @@ -388,6 +388,71 @@ svn_cstring_join(const apr_array_header_
>>  int
>>  svn_cstring_casecmp(const char *str1, const char *str2);
>> 
>> +/**
>> + * Parse the C string @a str into a 64 bit number, and return it in @a *n.
>> + * Assume that the number is represented in base @a base.
>> + * Raise an error if conversion fails (e.g. due to overflow), or if the
>> + * converted number is smaller than @a minval or larger than @a maxval.
>> + *
>> + * @since New in 1.7.
>> + */
>> +svn_error_t *
>> +svn_cstring_strtoi64(apr_int64_t *n, const char *str,
>> +                     apr_int64_t minval, apr_int64_t maxval,
>> +                     int base);
>> +
>> +/**
>> + * Parse the C string @a str into a 64 bit number, and return it in @a *n.
>> + * Assume that the number is represented in base 10.
>> + * Raise an error if conversion fails (e.g. due to overflow).
>> + *
>> + * @since New in 1.7.
>> + */
>> +svn_error_t *
>> +svn_cstring_atoi64(apr_int64_t *n, const char *str);
>> +
>> +/**
>> + * Parse the C string @a str into a 32 bit number, and return it in @a *n.
>> + * Assume that the number is represented in base 10.
>> + * Raise an error if conversion fails (e.g. due to overflow).
>> + *
>> + * @since New in 1.7.
>> + */
>> +svn_error_t *
>> +svn_cstring_atoi(int *n, const char *str);
>> +
>> +/**
>> + * Parse the C string @a str into an unsigned 64 bit number, and return
>> + * it in @a *n. Assume that the number is represented in base @a base.
>> + * Raise an error if conversion fails (e.g. due to overflow), or if the
>> + * converted number is smaller than @a minval or larger than @a maxval.
>> + *
>> + * @since New in 1.7.
>> + */
>> +svn_error_t *
>> +svn_cstring_strtoui64(apr_uint64_t *n, const char *str,
>> +                      apr_uint64_t minval, apr_uint64_t maxval,
>> +                      int base);
>> +
>> +/**
>> + * Parse the C string @a str into an unsigned 64 bit number, and return
>> + * it in @a *n. Assume that the number is represented in base 10.
>> + * Raise an error if conversion fails (e.g. due to overflow).
>> + *
>> + * @since New in 1.7.
>> + */
>> +svn_error_t *
>> +svn_cstring_atoui64(apr_uint64_t *n, const char *str);
>> +
>> +/**
>> + * Parse the C string @a str into an unsigned 32 bit number, and return
>> + * it in @a *n. Assume that the number is represented in base 10.
>> + * Raise an error if conversion fails (e.g. due to overflow).
>> + *
>> + * @since New in 1.7.
>> + */
>> +svn_error_t *
>> +svn_cstring_atoui(unsigned int *n, const char *str);
>> 
>>  /** @} */
>> 
>> 
>> Modified: subversion/trunk/subversion/libsvn_diff/parse-diff.c
>> URL: 
>> http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_diff/parse-diff.c?rev=993183&r1=993182&r2=993183&view=diff
>> ==============================================================================
>> --- subversion/trunk/subversion/libsvn_diff/parse-diff.c (original)
>> +++ subversion/trunk/subversion/libsvn_diff/parse-diff.c Tue Sep  7 00:09:46 
>> 2010
>> @@ -28,6 +28,7 @@
>>  #include "svn_error.h"
>>  #include "svn_io.h"
>>  #include "svn_pools.h"
>> +#include "svn_string.h"
>>  #include "svn_utf.h"
>>  #include "svn_dirent_uri.h"
>>  #include "svn_diff.h"
>> @@ -119,20 +120,15 @@ svn_diff_hunk_get_trailing_context(const
>>  static svn_boolean_t
>>  parse_offset(svn_linenum_t *offset, const char *number)
>>  {
>> -  apr_int64_t parsed_offset;
>> +  svn_error_t *err;
>> 
>> -  errno = 0; /* apr_atoi64() in APR-0.9 does not always set errno */
>> -  parsed_offset = apr_atoi64(number);
>> -  if (errno == ERANGE || parsed_offset < 0)
>> -    return FALSE;
>> -
>> -  /* In case we cannot fit 64 bits into an svn_linenum_t,
>> -   * check for overflow. */
>> -  if (sizeof(svn_linenum_t) < sizeof(parsed_offset) &&
>> -      parsed_offset > SVN_LINENUM_MAX_VALUE)
>> -    return FALSE;
>> -
>> -  *offset = parsed_offset;
>> +  err = svn_cstring_strtoui64(offset, number, 0, SVN_LINENUM_MAX_VALUE, 10);
>> +  if (err)
>> +    {
>> +      svn_error_clear(err);
>> +      return FALSE;
>> +    }
>> +
>>   return TRUE;
>>  }
>> 
>> 
>> Modified: subversion/trunk/subversion/libsvn_ra_serf/serf.c
>> URL: 
>> http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_ra_serf/serf.c?rev=993183&r1=993182&r2=993183&view=diff
>> ==============================================================================
>> --- subversion/trunk/subversion/libsvn_ra_serf/serf.c (original)
>> +++ subversion/trunk/subversion/libsvn_ra_serf/serf.c Tue Sep  7 00:09:46 
>> 2010
>> @@ -721,7 +721,7 @@ dirent_walker(void *baton,
>>         }
>>       else if (strcmp(name, "getcontentlength") == 0)
>>         {
>> -          entry->size = apr_atoi64(val->data);
>> +          SVN_ERR(svn_cstring_atoi64(&entry->size, val->data));
>>         }
>>       else if (strcmp(name, "resourcetype") == 0)
>>         {
>> 
>> Modified: subversion/trunk/subversion/libsvn_subr/hash.c
>> URL: 
>> http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_subr/hash.c?rev=993183&r1=993182&r2=993183&view=diff
>> ==============================================================================
>> --- subversion/trunk/subversion/libsvn_subr/hash.c (original)
>> +++ subversion/trunk/subversion/libsvn_subr/hash.c Tue Sep  7 00:09:46 2010
>> @@ -344,11 +344,16 @@ svn_hash_read(apr_hash_t *hash,
>>         }
>>       else if ((buf[0] == 'K') && (buf[1] == ' '))
>>         {
>> +          size_t keylen;
>> +          int parsed_len;
>> +          void *keybuf;
>> +
>>           /* Get the length of the key */
>> -          size_t keylen = (size_t) atoi(buf + 2);
>> +          SVN_ERR(svn_cstring_atoi(&parsed_len, buf + 2));
>> +          keylen = parsed_len;
>> 
>>           /* Now read that much into a buffer, + 1 byte for null terminator 
>> */
>> -          void *keybuf = apr_palloc(pool, keylen + 1);
>> +          keybuf = apr_palloc(pool, keylen + 1);
>>           SVN_ERR(svn_io_file_read_full(srcfile,
>>                                         keybuf, keylen, &num_read, pool));
>>           ((char *) keybuf)[keylen] = '\0';
>> @@ -365,12 +370,15 @@ svn_hash_read(apr_hash_t *hash,
>>           if ((buf[0] == 'V') && (buf[1] == ' '))
>>             {
>>               svn_string_t *value = apr_palloc(pool, sizeof(*value));
>> +              apr_size_t vallen;
>> +              void *valbuf;
>> 
>>               /* Get the length of the value */
>> -              apr_size_t vallen = atoi(buf + 2);
>> +              SVN_ERR(svn_cstring_atoi(&parsed_len, buf + 2));
>> +              vallen = parsed_len;
>> 
>>               /* Again, 1 extra byte for the null termination. */
>> -              void *valbuf = apr_palloc(pool, vallen + 1);
>> +              valbuf = apr_palloc(pool, vallen + 1);
>>               SVN_ERR(svn_io_file_read_full(srcfile,
>>                                             valbuf, vallen,
>>                                             &num_read, pool));
>> 
>> Modified: subversion/trunk/subversion/libsvn_subr/io.c
>> URL: 
>> http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_subr/io.c?rev=993183&r1=993182&r2=993183&view=diff
>> ==============================================================================
>> --- subversion/trunk/subversion/libsvn_subr/io.c (original)
>> +++ subversion/trunk/subversion/libsvn_subr/io.c Tue Sep  7 00:09:46 2010
>> @@ -3472,7 +3472,7 @@ svn_io_read_version_file(int *version,
>>   }
>> 
>>   /* Convert to integer. */
>> -  *version = atoi(buf);
>> +  SVN_ERR(svn_cstring_atoi(version, buf));
>> 
>>   return SVN_NO_ERROR;
>>  }
>> 
>> Modified: subversion/trunk/subversion/libsvn_subr/svn_string.c
>> URL: 
>> http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_subr/svn_string.c?rev=993183&r1=993182&r2=993183&view=diff
>> ==============================================================================
>> --- subversion/trunk/subversion/libsvn_subr/svn_string.c (original)
>> +++ subversion/trunk/subversion/libsvn_subr/svn_string.c Tue Sep  7 00:09:46 
>> 2010
>> @@ -25,12 +25,15 @@
>> 
>> 
>> 
>> +#include <apr.h>
>> +
>>  #include <string.h>      /* for memcpy(), memcmp(), strlen() */
>>  #include <apr_lib.h>     /* for apr_isspace() */
>>  #include <apr_fnmatch.h>
>>  #include "svn_string.h"  /* loads "svn_types.h" and <apr_pools.h> */
>>  #include "svn_ctype.h"
>> 
>> +#include "svn_private_config.h"
>> 
>> 
>>  /* Our own realloc, since APR doesn't have one.  Note: this is a
>> @@ -605,3 +608,88 @@ svn_cstring_casecmp(const char *str1, co
>>         return cmp;
>>     }
>>  }
>> +
>> +svn_error_t *
>> +svn_cstring_strtoui64(apr_uint64_t *n, const char *str,
>> +                      apr_uint64_t minval, apr_uint64_t maxval,
>> +                      int base)
>> +{
>> +  apr_int64_t parsed;
>> +
>> +  /* We assume errno is thread-safe. */
>> +  errno = 0; /* APR-0.9 doesn't always set errno */
>> +
>> +  /* ### We're throwing away half the number range here.
>> +   * ### Maybe implement our own number parser? */
>> +  parsed = apr_strtoi64(str, NULL, base);
>> +  if (errno != 0)
>> +    return svn_error_return(
>> +             svn_error_createf(SVN_ERR_INCORRECT_PARAMS, NULL,
>> +                               _("Could not convert '%s' into a number"),
>> +                               str));
>> +  if (parsed < 0 || parsed < minval || parsed > maxval)
>> +    return svn_error_return(
>> +             svn_error_createf(SVN_ERR_INCORRECT_PARAMS, NULL,
>> +                               _("Number '%s' is out of range"), str));
>> +  *n = parsed;
>> +  return SVN_NO_ERROR;
>> +}
>> +
>> +svn_error_t *
>> +svn_cstring_atoui64(apr_uint64_t *n, const char *str)
>> +{
>> +  return svn_error_return(svn_cstring_strtoui64(n, str, 0,
>> +                                                APR_UINT64_MAX, 10));
>> +}
>> +
>> +svn_error_t *
>> +svn_cstring_atoui(unsigned int *n, const char *str)
>> +{
>> +  apr_uint64_t parsed;
>> +
>> +  SVN_ERR(svn_cstring_strtoui64(&parsed, str, 0, APR_UINT32_MAX, 10));
>> +  *n = (unsigned int)parsed;
>> +  return SVN_NO_ERROR;
>> +}
>> +
>> +svn_error_t *
>> +svn_cstring_strtoi64(apr_int64_t *n, const char *str,
>> +                     apr_int64_t minval, apr_int64_t maxval,
>> +                     int base)
>> +{
>> +  apr_int64_t parsed;
>> +
>> +  /* We assume errno is thread-safe. */
>> +  errno = 0; /* APR-0.9 doesn't always set errno */
>> +
>> +  parsed = apr_strtoi64(str, NULL, base);
>> +  if (errno != 0)
>> +    return svn_error_return(
>> +             svn_error_createf(SVN_ERR_INCORRECT_PARAMS, NULL,
>> +                               _("Could not convert '%s' into a number"),
>> +                               str));
>> +  if (parsed < minval || parsed > maxval)
>> +    return svn_error_return(
>> +             svn_error_createf(SVN_ERR_INCORRECT_PARAMS, NULL,
>> +                               _("Number '%s' is out of range"), str));
>> +  *n = parsed;
>> +  return SVN_NO_ERROR;
>> +}
>> +
>> +svn_error_t *
>> +svn_cstring_atoi64(apr_int64_t *n, const char *str)
>> +{
>> +  return svn_error_return(svn_cstring_strtoi64(n, str, APR_INT64_MIN,
>> +                                               APR_INT64_MAX, 10));
>> +}
>> +
>> +svn_error_t *
>> +svn_cstring_atoi(int *n, const char *str)
>> +{
>> +  apr_int64_t parsed;
>> +
>> +  SVN_ERR(svn_cstring_strtoi64(&parsed, str, APR_INT32_MIN,
>> +                               APR_INT32_MAX, 10));
>> +  *n = (int)parsed;
>> +  return SVN_NO_ERROR;
>> +}
>> 
>> Modified: subversion/trunk/subversion/libsvn_subr/win32_xlate.c
>> URL: 
>> http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_subr/win32_xlate.c?rev=993183&r1=993182&r2=993183&view=diff
>> ==============================================================================
>> --- subversion/trunk/subversion/libsvn_subr/win32_xlate.c (original)
>> +++ subversion/trunk/subversion/libsvn_subr/win32_xlate.c Tue Sep  7 
>> 00:09:46 2010
>> @@ -110,7 +110,7 @@ get_page_id_from_name(UINT *page_id_p, c
>>   if ((page_name[0] == 'c' || page_name[0] == 'C')
>>       && (page_name[1] == 'p' || page_name[1] == 'P'))
>>     {
>> -      *page_id_p = atoi(page_name + 2);
>> +      SVN_ERR(svn_cstring_atoui(page_id_p, page_name + 2));
>>       return APR_SUCCESS;
>>     }
>> 
>> 
>> Modified: subversion/trunk/subversion/mod_dav_svn/reports/log.c
>> URL: 
>> http://svn.apache.org/viewvc/subversion/trunk/subversion/mod_dav_svn/reports/log.c?rev=993183&r1=993182&r2=993183&view=diff
>> ==============================================================================
>> --- subversion/trunk/subversion/mod_dav_svn/reports/log.c (original)
>> +++ subversion/trunk/subversion/mod_dav_svn/reports/log.c Tue Sep  7 
>> 00:09:46 2010
>> @@ -311,7 +311,15 @@ dav_svn__log_report(const dav_resource *
>>       else if (strcmp(child->name, "end-revision") == 0)
>>         end = SVN_STR_TO_REV(dav_xml_get_cdata(child, resource->pool, 1));
>>       else if (strcmp(child->name, "limit") == 0)
>> -        limit = atoi(dav_xml_get_cdata(child, resource->pool, 1));
>> +        {
>> +          serr = svn_cstring_atoi(&limit,
>> +                                  dav_xml_get_cdata(child, resource->pool, 
>> 1));
>> +          if (serr)
>> +            {
>> +              svn_error_clear(serr);
>> +              return malformed_element_error("limit", resource->pool);
>> +            }
>> +        }
>>       else if (strcmp(child->name, "discover-changed-paths") == 0)
>>         discover_changed_paths = TRUE; /* presence indicates positivity */
>>       else if (strcmp(child->name, "strict-node-history") == 0)
>> 
>> Modified: subversion/trunk/subversion/mod_dav_svn/reports/replay.c
>> URL: 
>> http://svn.apache.org/viewvc/subversion/trunk/subversion/mod_dav_svn/reports/replay.c?rev=993183&r1=993182&r2=993183&view=diff
>> ==============================================================================
>> --- subversion/trunk/subversion/mod_dav_svn/reports/replay.c (original)
>> +++ subversion/trunk/subversion/mod_dav_svn/reports/replay.c Tue Sep  7 
>> 00:09:46 2010
>> @@ -466,10 +466,18 @@ dav_svn__replay_report(const dav_resourc
>>             }
>>           else if (strcmp(child->name, "send-deltas") == 0)
>>             {
>> +              apr_int64_t parsed_val;
>> +
>>               cdata = dav_xml_get_cdata(child, resource->pool, 1);
>>               if (! cdata)
>>                 return malformed_element_error("send-deltas", 
>> resource->pool);
>> -              send_deltas = atoi(cdata);
>> +              err = svn_cstring_strtoi64(&parsed_val, cdata, 0, 1, 10);
>> +              if (err)
>> +                {
>> +                  svn_error_clear(err);
>> +                  return malformed_element_error("send-deltas", 
>> resource->pool);
>> +                }
>> +              send_deltas = parsed_val ? TRUE : FALSE;
>>             }
>>         }
>>     }
>> 
>> 
>> 

--
Stephen Butler | Senior Consultant
elego Software Solutions GmbH
Gustav-Meyer-Allee 25 | 13355 Berlin | Germany
fon: +49 30 2345 8696 | mobile: +49 163 25 45 015
fax: +49 30 2345 8695 | http://www.elegosoft.com
Geschäftsführer: Olaf Wagner | Sitz der Gesellschaft: Berlin
Amtsgericht Charlottenburg HRB 77719 | USt-IdNr: DE163214194


Reply via email to