fix: use vector::at() rather than operator[] (backport #1735) (#1741)

* fix: use vector::at() rather than operator[] (#1735)

* Regression test for https://github.com/Exiv2/exiv2/issues/1706

* Use vector::at() rather than operator[].

* Print to stderr when exception is caught and EXIV2_DEBUG_MESSAGES is enabled.

* Check that it prints "Bad value" for the date.

(cherry picked from commit f4d3adbf91e6dc4e34aee5bac7b7fd9e127a5c00)

# Conflicts:
#	src/value.cpp

* fix merge conflicts from mergify backport

Co-authored-by: Kevin Backhouse <kevinbackhouse@github.com>
Co-authored-by: Christoph Hasse <hassec@users.noreply.github.com>
main
mergify[bot] 4 years ago committed by GitHub
parent 2b84f4bd64
commit 1d64f482ff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1616,7 +1616,7 @@ namespace Exiv2 {
std::string ValueType<T>::toString(long n) const std::string ValueType<T>::toString(long n) const
{ {
ok_ = true; ok_ = true;
return Exiv2::toString<T>(value_[n]); return Exiv2::toString<T>(value_.at(n));
} }
// Default implementation // Default implementation
@ -1624,69 +1624,69 @@ namespace Exiv2 {
long ValueType<T>::toLong(long n) const long ValueType<T>::toLong(long n) const
{ {
ok_ = true; ok_ = true;
return static_cast<long>(value_[n]); return static_cast<long>(value_.at(n));
} }
// #55 crash when value_[n].first == LONG_MIN // #55 crash when value_.at(n).first == LONG_MIN
#define LARGE_INT 1000000 #define LARGE_INT 1000000
// Specialization for rational // Specialization for rational
template<> template<>
inline long ValueType<Rational>::toLong(long n) const inline long ValueType<Rational>::toLong(long n) const
{ {
ok_ = (value_[n].second != 0 && INT_MIN < value_[n].first && value_[n].first < INT_MAX ); ok_ = (value_.at(n).second != 0 && INT_MIN < value_.at(n).first && value_.at(n).first < INT_MAX );
if (!ok_) return 0; if (!ok_) return 0;
return value_[n].first / value_[n].second; return value_.at(n).first / value_.at(n).second;
} }
// Specialization for unsigned rational // Specialization for unsigned rational
template<> template<>
inline long ValueType<URational>::toLong(long n) const inline long ValueType<URational>::toLong(long n) const
{ {
ok_ = (value_[n].second != 0 && value_[n].first < LARGE_INT); ok_ = (value_.at(n).second != 0 && value_.at(n).first < LARGE_INT);
if (!ok_) return 0; if (!ok_) return 0;
return value_[n].first / value_[n].second; return value_.at(n).first / value_.at(n).second;
} }
// Default implementation // Default implementation
template<typename T> template<typename T>
float ValueType<T>::toFloat(long n) const float ValueType<T>::toFloat(long n) const
{ {
ok_ = true; ok_ = true;
return static_cast<float>(value_[n]); return static_cast<float>(value_.at(n));
} }
// Specialization for rational // Specialization for rational
template<> template<>
inline float ValueType<Rational>::toFloat(long n) const inline float ValueType<Rational>::toFloat(long n) const
{ {
ok_ = (value_[n].second != 0); ok_ = (value_.at(n).second != 0);
if (!ok_) return 0.0f; if (!ok_) return 0.0f;
return static_cast<float>(value_[n].first) / value_[n].second; return static_cast<float>(value_.at(n).first) / value_.at(n).second;
} }
// Specialization for unsigned rational // Specialization for unsigned rational
template<> template<>
inline float ValueType<URational>::toFloat(long n) const inline float ValueType<URational>::toFloat(long n) const
{ {
ok_ = (value_[n].second != 0); ok_ = (value_.at(n).second != 0);
if (!ok_) return 0.0f; if (!ok_) return 0.0f;
return static_cast<float>(value_[n].first) / value_[n].second; return static_cast<float>(value_.at(n).first) / value_.at(n).second;
} }
// Default implementation // Default implementation
template<typename T> template<typename T>
Rational ValueType<T>::toRational(long n) const Rational ValueType<T>::toRational(long n) const
{ {
ok_ = true; ok_ = true;
return Rational(value_[n], 1); return Rational(value_.at(n), 1);
} }
// Specialization for rational // Specialization for rational
template<> template<>
inline Rational ValueType<Rational>::toRational(long n) const inline Rational ValueType<Rational>::toRational(long n) const
{ {
ok_ = true; ok_ = true;
return Rational(value_[n].first, value_[n].second); return Rational(value_.at(n).first, value_.at(n).second);
} }
// Specialization for unsigned rational // Specialization for unsigned rational
template<> template<>
inline Rational ValueType<URational>::toRational(long n) const inline Rational ValueType<URational>::toRational(long n) const
{ {
ok_ = true; ok_ = true;
return Rational(value_[n].first, value_[n].second); return Rational(value_.at(n).first, value_.at(n).second);
} }
// Specialization for float. // Specialization for float.
template<> template<>
@ -1694,7 +1694,7 @@ namespace Exiv2 {
{ {
ok_ = true; ok_ = true;
// Warning: This is a very simple conversion, see floatToRationalCast() // Warning: This is a very simple conversion, see floatToRationalCast()
return floatToRationalCast(value_[n]); return floatToRationalCast(value_.at(n));
} }
// Specialization for double. // Specialization for double.
template<> template<>
@ -1702,7 +1702,7 @@ namespace Exiv2 {
{ {
ok_ = true; ok_ = true;
// Warning: This is a very simple conversion, see floatToRationalCast() // Warning: This is a very simple conversion, see floatToRationalCast()
return floatToRationalCast(static_cast<float>(value_[n])); return floatToRationalCast(static_cast<float>(value_.at(n)));
} }
template<typename T> template<typename T>

@ -908,7 +908,7 @@ namespace Exiv2 {
assert(pCrwMapping != 0); assert(pCrwMapping != 0);
ULongValue v; ULongValue v;
v.read(ciffComponent.pData(), 8, byteOrder); v.read(ciffComponent.pData(), 8, byteOrder);
time_t t = v.value_[0]; time_t t = v.value_.at(0);
struct tm* tm = std::localtime(&t); struct tm* tm = std::localtime(&t);
if (tm) { if (tm) {
const size_t m = 20; const size_t m = 20;

@ -229,7 +229,22 @@ namespace Exiv2 {
fct = nullptr; fct = nullptr;
} }
} }
if ( fct ) fct(os, value(), pMetadata); if ( fct ) {
// https://github.com/Exiv2/exiv2/issues/1706
// Sometimes the type of the value doesn't match what the
// print function expects. (The expected types are stored
// in the TagInfo tables, but they are not enforced when the
// metadata is parsed.) These type mismatches can sometimes
// cause a std::out_of_range exception to be thrown.
try {
fct(os, value(), pMetadata);
} catch (std::out_of_range&) {
os << "Bad value";
#ifdef EXIV2_DEBUG_MESSAGES
std::cerr << "Caught std::out_of_range exception in Exifdatum::write().\n";
#endif
}
}
return os; return os;
} }

@ -203,7 +203,7 @@ namespace Exiv2 {
{ {
std::vector<byte>::size_type end = value_.size(); std::vector<byte>::size_type end = value_.size();
for (std::vector<byte>::size_type i = 0; i != end; ++i) { for (std::vector<byte>::size_type i = 0; i != end; ++i) {
os << static_cast<int>(value_[i]); os << static_cast<int>(value_.at(i));
if (i < end - 1) os << " "; if (i < end - 1) os << " ";
} }
return os; return os;
@ -212,7 +212,7 @@ namespace Exiv2 {
std::string DataValue::toString(long n) const std::string DataValue::toString(long n) const
{ {
std::ostringstream os; std::ostringstream os;
os << static_cast<int>(value_[n]); os << static_cast<int>(value_.at(n));
ok_ = !os.fail(); ok_ = !os.fail();
return os.str(); return os.str();
} }
@ -220,19 +220,19 @@ namespace Exiv2 {
long DataValue::toLong(long n) const long DataValue::toLong(long n) const
{ {
ok_ = true; ok_ = true;
return value_[n]; return value_.at(n);
} }
float DataValue::toFloat(long n) const float DataValue::toFloat(long n) const
{ {
ok_ = true; ok_ = true;
return value_[n]; return value_.at(n);
} }
Rational DataValue::toRational(long n) const Rational DataValue::toRational(long n) const
{ {
ok_ = true; ok_ = true;
return {value_[n], 1}; return {value_.at(n), 1};
} }
StringValueBase::StringValueBase(TypeId typeId) StringValueBase::StringValueBase(TypeId typeId)
@ -296,19 +296,19 @@ namespace Exiv2 {
long StringValueBase::toLong(long n) const long StringValueBase::toLong(long n) const
{ {
ok_ = true; ok_ = true;
return value_[n]; return value_.at(n);
} }
float StringValueBase::toFloat(long n) const float StringValueBase::toFloat(long n) const
{ {
ok_ = true; ok_ = true;
return value_[n]; return value_.at(n);
} }
Rational StringValueBase::toRational(long n) const Rational StringValueBase::toRational(long n) const
{ {
ok_ = true; ok_ = true;
return {value_[n], 1}; return {value_.at(n), 1};
} }
StringValue::StringValue() StringValue::StringValue()
@ -340,8 +340,9 @@ namespace Exiv2 {
{ {
value_ = buf; value_ = buf;
// ensure count>0 and nul terminated # https://github.com/Exiv2/exiv2/issues/1484 // ensure count>0 and nul terminated # https://github.com/Exiv2/exiv2/issues/1484
if (value_.empty() || value_[value_.size() - 1] != '\0') if (value_.empty() || value_.at(value_.size() - 1) != '\0') {
value_ += '\0'; value_ += '\0';
}
return 0; return 0;
} }
@ -740,22 +741,22 @@ namespace Exiv2 {
std::string XmpArrayValue::toString(long n) const std::string XmpArrayValue::toString(long n) const
{ {
ok_ = true; ok_ = true;
return value_[n]; return value_.at(n);
} }
long XmpArrayValue::toLong(long n) const long XmpArrayValue::toLong(long n) const
{ {
return parseLong(value_[n], ok_); return parseLong(value_.at(n), ok_);
} }
float XmpArrayValue::toFloat(long n) const float XmpArrayValue::toFloat(long n) const
{ {
return parseFloat(value_[n], ok_); return parseFloat(value_.at(n), ok_);
} }
Rational XmpArrayValue::toRational(long n) const Rational XmpArrayValue::toRational(long n) const
{ {
return parseRational(value_[n], ok_); return parseRational(value_.at(n), ok_);
} }
XmpArrayValue* XmpArrayValue::clone_() const XmpArrayValue* XmpArrayValue::clone_() const

Binary file not shown.

@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
from system_tests import CaseMeta, path
class InvalidDateXMP(metaclass=CaseMeta):
"""
Regression test for the bug described in:
https://github.com/Exiv2/exiv2/issues/1706
"""
url = "https://github.com/Exiv2/exiv2/issues/1706"
filename = path("$data_path/issue_1706_poc.exv")
commands = ["$exiv2 -PE $filename"]
stderr = [
"""Error: Directory Photo with 65280 entries considered invalid; not read.
"""
]
retval = [0]
def compare_stdout(self, i, command, got_stdout, expected_stdout):
# Check that it printed "Bad value" for the date.
self.assertRegex(got_stdout, "Exif.PentaxDng.Date\\s+Long\\s+1\\s+Bad value")
Loading…
Cancel
Save