From bb9ff53ebe18e6759025106c25f9f1da614b7f6d Mon Sep 17 00:00:00 2001 From: Kevin Backhouse Date: Mon, 13 Sep 2021 21:43:59 +0100 Subject: [PATCH] Throw an exception on integer overflow. --- src/convert.cpp | 124 +++++++++++------------ tests/bugfixes/github/test_issue_1901.py | 110 ++------------------ xmpsdk/src/XMPUtils.cpp | 5 +- 3 files changed, 71 insertions(+), 168 deletions(-) diff --git a/src/convert.cpp b/src/convert.cpp index 9abe62e0fd..c4529b6060 100644 --- a/src/convert.cpp +++ b/src/convert.cpp @@ -859,6 +859,68 @@ namespace Exiv2 { XMP_DateTime datetime; try { SXMPUtils::ConvertToDate(value, &datetime); + char buf[30]; + if (std::string(to) != "Exif.GPSInfo.GPSTimeStamp") { + + SXMPUtils::ConvertToLocalTime(&datetime); + + snprintf(buf, sizeof(buf), "%4d:%02d:%02d %02d:%02d:%02d", + static_cast(datetime.year), + static_cast(datetime.month), + static_cast(datetime.day), + static_cast(datetime.hour), + static_cast(datetime.minute), + static_cast(datetime.second)); + buf[sizeof(buf) - 1] = 0; + (*exifData_)[to] = buf; + + if (datetime.nanoSecond) { + const char* subsecTag = nullptr; + if (std::string(to) == "Exif.Image.DateTime") { + subsecTag = "Exif.Photo.SubSecTime"; + } + else if (std::string(to) == "Exif.Photo.DateTimeOriginal") { + subsecTag = "Exif.Photo.SubSecTimeOriginal"; + } + else if (std::string(to) == "Exif.Photo.DateTimeDigitized") { + subsecTag = "Exif.Photo.SubSecTimeDigitized"; + } + if (subsecTag) { + prepareExifTarget(subsecTag, true); + (*exifData_)[subsecTag] = toString(datetime.nanoSecond); + } + } + } + else { // "Exif.GPSInfo.GPSTimeStamp" + + // Ignore the time zone, assuming the time is in UTC as it should be + + URational rhour(datetime.hour, 1); + URational rmin(datetime.minute, 1); + URational rsec(datetime.second, 1); + if (datetime.nanoSecond != 0) { + if (datetime.second != 0) { + // Add the seconds to rmin so that the ns fit into rsec + rmin.second = 60; + rmin.first *= 60; + rmin.first += datetime.second; + } + rsec.second = 1000000000; + rsec.first = datetime.nanoSecond; + } + + std::ostringstream array; + array << rhour << " " << rmin << " " << rsec; + (*exifData_)[to] = array.str(); + + prepareExifTarget("Exif.GPSInfo.GPSDateStamp", true); + snprintf(buf, sizeof(buf), "%4d:%02d:%02d", + static_cast(datetime.year), + static_cast(datetime.month), + static_cast(datetime.day)); + buf[sizeof(buf) - 1] = 0; + (*exifData_)["Exif.GPSInfo.GPSDateStamp"] = buf; + } } #ifndef SUPPRESS_WARNINGS catch (const XMP_Error& e) { @@ -870,68 +932,6 @@ namespace Exiv2 { return; } #endif // SUPPRESS_WARNINGS - char buf[30]; - if (std::string(to) != "Exif.GPSInfo.GPSTimeStamp") { - - SXMPUtils::ConvertToLocalTime(&datetime); - - snprintf(buf, sizeof(buf), "%4d:%02d:%02d %02d:%02d:%02d", - static_cast(datetime.year), - static_cast(datetime.month), - static_cast(datetime.day), - static_cast(datetime.hour), - static_cast(datetime.minute), - static_cast(datetime.second)); - buf[sizeof(buf) - 1] = 0; - (*exifData_)[to] = buf; - - if (datetime.nanoSecond) { - const char* subsecTag = nullptr; - if (std::string(to) == "Exif.Image.DateTime") { - subsecTag = "Exif.Photo.SubSecTime"; - } - else if (std::string(to) == "Exif.Photo.DateTimeOriginal") { - subsecTag = "Exif.Photo.SubSecTimeOriginal"; - } - else if (std::string(to) == "Exif.Photo.DateTimeDigitized") { - subsecTag = "Exif.Photo.SubSecTimeDigitized"; - } - if (subsecTag) { - prepareExifTarget(subsecTag, true); - (*exifData_)[subsecTag] = toString(datetime.nanoSecond); - } - } - } - else { // "Exif.GPSInfo.GPSTimeStamp" - - // Ignore the time zone, assuming the time is in UTC as it should be - - URational rhour(datetime.hour, 1); - URational rmin(datetime.minute, 1); - URational rsec(datetime.second, 1); - if (datetime.nanoSecond != 0) { - if (datetime.second != 0) { - // Add the seconds to rmin so that the ns fit into rsec - rmin.second = 60; - rmin.first *= 60; - rmin.first += datetime.second; - } - rsec.second = 1000000000; - rsec.first = datetime.nanoSecond; - } - - std::ostringstream array; - array << rhour << " " << rmin << " " << rsec; - (*exifData_)[to] = array.str(); - - prepareExifTarget("Exif.GPSInfo.GPSDateStamp", true); - snprintf(buf, sizeof(buf), "%4d:%02d:%02d", - static_cast(datetime.year), - static_cast(datetime.month), - static_cast(datetime.day)); - buf[sizeof(buf) - 1] = 0; - (*exifData_)["Exif.GPSInfo.GPSDateStamp"] = buf; - } if (erase_) xmpData_->erase(pos); #else diff --git a/tests/bugfixes/github/test_issue_1901.py b/tests/bugfixes/github/test_issue_1901.py index 4c98e95074..bc7867f49f 100644 --- a/tests/bugfixes/github/test_issue_1901.py +++ b/tests/bugfixes/github/test_issue_1901.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -from system_tests import CaseMeta, path +from system_tests import CaseMeta, path, check_no_ASAN_UBSAN_errors class XMPUtilsSetTimeZoneIntegerOverflow(metaclass=CaseMeta): """ @@ -17,109 +17,13 @@ class XMPUtilsSetTimeZoneIntegerOverflow(metaclass=CaseMeta): "$exiv2 -q $filename2", "$exiv2 -q $filename3", "$exiv2 -q $filename4"] - stderr = ["", "", "", ""] - stdout = ["""File name : $filename1 -File size : 170 Bytes -MIME type : application/rdf+xml -Image size : 0 x 0 -Thumbnail : None -Camera make : -Camera model : -Image timestamp : -File number : -Exposure time : -Aperture : -Exposure bias : -Flash : -Flash bias : -Focal length : -Subject distance: -ISO speed : -Exposure mode : -Metering mode : -Macro mode : -Image quality : -White balance : -Copyright : -Exif comment : - + stderr = ["""$filename1: No Exif data found in the file """, - """File name : $filename2 -File size : 170 Bytes -MIME type : application/rdf+xml -Image size : 0 x 0 -Thumbnail : None -Camera make : -Camera model : -Image timestamp : -File number : -Exposure time : -Aperture : -Exposure bias : -Flash : -Flash bias : -Focal length : -Subject distance: -ISO speed : -Exposure mode : -Metering mode : -Macro mode : -Image quality : -White balance : -Copyright : -Exif comment : - + """$filename2: No Exif data found in the file """, - """File name : $filename3 -File size : 160 Bytes -MIME type : application/rdf+xml -Image size : 0 x 0 -Thumbnail : None -Camera make : -Camera model : -Image timestamp : -File number : -Exposure time : -Aperture : -Exposure bias : -Flash : -Flash bias : -Focal length : -Subject distance: -ISO speed : -Exposure mode : -Metering mode : -Macro mode : -Image quality : -White balance : -Copyright : -Exif comment : - + """$filename3: No Exif data found in the file """, - """File name : $filename4 -File size : 154 Bytes -MIME type : application/rdf+xml -Image size : 0 x 0 -Thumbnail : None -Camera make : -Camera model : -Image timestamp : -File number : -Exposure time : -Aperture : -Exposure bias : -Flash : -Flash bias : -Focal length : -Subject distance: -ISO speed : -Exposure mode : -Metering mode : -Macro mode : -Image quality : -White balance : -Copyright : -Exif comment : + ""] + retval = [253, 253, 253, 0] -"""] - retval = [0, 0, 0, 0] + compare_stdout = check_no_ASAN_UBSAN_errors diff --git a/xmpsdk/src/XMPUtils.cpp b/xmpsdk/src/XMPUtils.cpp index 0084946790..af41c18791 100644 --- a/xmpsdk/src/XMPUtils.cpp +++ b/xmpsdk/src/XMPUtils.cpp @@ -1960,11 +1960,10 @@ XMPUtils::SetTimeZone ( XMP_DateTime * xmpTime ) if ( now == -1 ) XMP_Throw ( "Failure from ANSI C time function", kXMPErr_ExternalFailure ); ansi_localtime ( &now, &tmLocal ); } else { - // Fix for https://github.com/Exiv2/exiv2/issues/1901 if (xmpTime->year < std::numeric_limits::min() + 1900) { - tmLocal.tm_year = std::numeric_limits::min(); + XMP_Throw ( "Invalid year", kXMPErr_BadParam); } else if (xmpTime->year > std::numeric_limits::max()) { - tmLocal.tm_year = std::numeric_limits::max(); + XMP_Throw ( "Invalid year", kXMPErr_BadParam); } else { tmLocal.tm_year = xmpTime->year - 1900; }