[cairo] Nasty bug in _cairo_strtod: no negative numbers!

Bill Spitzak spitzak at gmail.com
Wed Jul 15 15:20:33 UTC 2020


That also is not copying exponents. What it should do is copy all the
numbers letters and signs to the output, replace '.' with the decimal
point, then run the other one.

On Wed, Jul 15, 2020 at 5:44 AM Tobias Fleischer (reduxFX) <
tobias.fleischer at reduxfx.com> wrote:

> After spending several days of trying to track down weird behaviour when
> using Cairo, I finally found the culprit:
> In cairo-misc.c there is a function called _cairo_strtod() that is
> intended as a replacement to the standard strtod(), meaning it should
> convert a string to a double. The difference according to the comment is
> that it "ignores locale and only accepts decimal points".
>
> However, in difference to the original strtod() function, it can't deal
> with negative numbers in strings and will always return "0" for them. Not
> good!
> This is particularly relevant when dealing with variation fonts, as the
> axis parameters need to be given as a string and many of them have a
> negative range, which leads to faulty display of these fonts.
>
> I made a hotfix/verification in my own Cairo sources, and it seems to work
> fine, but I can't make a pull request at the moment, so I post it below,
> though there might be an easier way to fix this for sure:
>
> double
> _cairo_strtod (const char *nptr, char **endptr)
> {
>     const char *decimal_point;
>     int decimal_point_len;
>     const char *p;
>     char buf[100];
>     char *bufptr;
>     char *bufend = buf + sizeof(buf) - 1;
>     double value;
>     char *end;
>     int delta;
>     cairo_bool_t have_dp;
>     int inv; //[TF]
>
>     decimal_point = _cairo_get_locale_decimal_point ();
>     decimal_point_len = strlen (decimal_point);
>     assert (decimal_point_len != 0);
>
>     p = nptr;
>     bufptr = buf;
>     delta = 0;
>     have_dp = FALSE;
>     while (*p && _cairo_isspace (*p)) {
> 	p++;
> 	delta++;
>     }
>
>     inv = 1; //[TF]
>     while (*p && (bufptr + decimal_point_len < bufend)) {
> 	if (_cairo_isdigit (*p)) {
> 	    *bufptr++ = *p;
> 	} else if (*p == '-') { //[TF]
> 	    inv = -1; //[TF]
> 	    delta++; //[TF]
> 	} else if (*p == '.') {
> 	    if (have_dp)
> 		break;
> 	    strncpy (bufptr, decimal_point, decimal_point_len);
> 	    bufptr += decimal_point_len;
> 	    delta -= decimal_point_len - 1;
> 	    have_dp = TRUE;
> 	} else {
> 	    break;
> 	}
> 	p++;
>     }
>     *bufptr = 0;
>
>     value = strtod (buf, &end) * inv; //[TF]
>     if (endptr) {
> 	if (end == buf)
> 	    *endptr = (char*)(nptr);
> 	else
> 	    *endptr = (char*)(nptr + (end - buf) + delta);
>     }
>
>     return value;
> }
>
> --
> cairo mailing list
> cairo at cairographics.org
> https://lists.cairographics.org/mailman/listinfo/cairo
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.cairographics.org/archives/cairo/attachments/20200715/15150265/attachment.htm>


More information about the cairo mailing list