diff --git a/CHANGELOG.md b/CHANGELOG.md index d646e11..9f118ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.26.6 + +* Be more careful about checking for overflow when parsing numbers + ## 1.26.5 * Support UTF-16 surrogate pairs in JSON strings diff --git a/mvt.cpp b/mvt.cpp index 9559dd4..27ee21a 100644 --- a/mvt.cpp +++ b/mvt.cpp @@ -517,14 +517,28 @@ mvt_value stringified_to_mvt_value(int type, const char *s) { tv.numeric_value.sint_value = v; } } else { - double d = atof(s); + errno = 0; + char *endptr; - if (d == (float) d) { - tv.type = mvt_float; - tv.numeric_value.float_value = d; - } else { + float f = strtof(s, &endptr); + + if (endptr == s || ((f == HUGE_VAL || f == HUGE_VALF || f == HUGE_VALL) && errno == ERANGE)) { + double d = strtod(s, &endptr); + if (endptr == s || ((d == HUGE_VAL || d == HUGE_VALF || d == HUGE_VALL) && errno == ERANGE)) { + fprintf(stderr, "Warning: numeric value %s could not be represented\n", s); + } tv.type = mvt_double; tv.numeric_value.double_value = d; + } else { + double d = atof(s); + if (f == d) { + tv.type = mvt_float; + tv.numeric_value.float_value = f; + } else { + // Conversion succeeded, but lost precision, so use double + tv.type = mvt_double; + tv.numeric_value.double_value = d; + } } } } else if (type == mvt_bool) { diff --git a/tests/overflow/in.json b/tests/overflow/in.json new file mode 100644 index 0000000..cbf7d63 --- /dev/null +++ b/tests/overflow/in.json @@ -0,0 +1,3 @@ +{ "type": "Feature", "properties": { "excess": 2222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222 }, "geometry": { "type": "Point", "coordinates": [ 0,0 ] } } +{ "type": "Feature", "properties": { "excess": 22e291 }, "geometry": { "type": "Point", "coordinates": [ 0,0 ] } } +{ "type": "Feature", "properties": { "excess": 2.5 }, "geometry": { "type": "Point", "coordinates": [ 0,0 ] } } diff --git a/tests/overflow/out/-z0.json b/tests/overflow/out/-z0.json new file mode 100644 index 0000000..94df132 --- /dev/null +++ b/tests/overflow/out/-z0.json @@ -0,0 +1,22 @@ +{ "type": "FeatureCollection", "properties": { +"bounds": "0.000000,0.000000,0.000000,0.000000", +"center": "0.000000,0.000000,0", +"description": "tests/overflow/out/-z0.json.check.mbtiles", +"format": "pbf", +"json": "{\"vector_layers\": [ { \"id\": \"in\", \"description\": \"\", \"minzoom\": 0, \"maxzoom\": 0, \"fields\": {\"excess\": \"Number\"} } ],\"tilestats\": {\"layerCount\": 1,\"layers\": [{\"layer\": \"in\",\"count\": 3,\"geometry\": \"Point\",\"attributeCount\": 1,\"attributes\": [{\"attribute\": \"excess\",\"count\": 3,\"type\": \"number\",\"values\": [2.2222222222222223e+291,2.2e+292,2.5],\"min\": 2.5,\"max\": 2.2e+292}]}]}}", +"maxzoom": "0", +"minzoom": "0", +"name": "tests/overflow/out/-z0.json.check.mbtiles", +"type": "overlay", +"version": "2" +}, "features": [ +{ "type": "FeatureCollection", "properties": { "zoom": 0, "x": 0, "y": 0 }, "features": [ +{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [ +{ "type": "Feature", "properties": { "excess": 2.2222222222222223e+291 }, "geometry": { "type": "Point", "coordinates": [ 0.000000, 0.000000 ] } } +, +{ "type": "Feature", "properties": { "excess": 2.2e+292 }, "geometry": { "type": "Point", "coordinates": [ 0.000000, 0.000000 ] } } +, +{ "type": "Feature", "properties": { "excess": 2.5 }, "geometry": { "type": "Point", "coordinates": [ 0.000000, 0.000000 ] } } +] } +] } +] } diff --git a/version.hpp b/version.hpp index 0df13f6..096f6e0 100644 --- a/version.hpp +++ b/version.hpp @@ -1,6 +1,6 @@ #ifndef VERSION_HPP #define VERSION_HPP -#define VERSION "tippecanoe v1.26.5\n" +#define VERSION "tippecanoe v1.26.6\n" #endif