Skip to content

Commit

Permalink
Merge pull request Exiv2#380 from D4N/misc_issues_fix
Browse files Browse the repository at this point in the history
Fix various memory issues and enable ASAN for the test suite
  • Loading branch information
D4N authored Jul 29, 2018
2 parents 505e241 + 664e93c commit 24ef91f
Show file tree
Hide file tree
Showing 8 changed files with 97 additions and 44 deletions.
6 changes: 5 additions & 1 deletion ci/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@ fi

mkdir build && cd build
conan install .. --build missing --profile release
cmake ${CMAKE_OPTIONS} -DCMAKE_INSTALL_PREFIX=install ..
cmake ${CMAKE_OPTIONS} -DCMAKE_INSTALL_PREFIX=install \
-DCMAKE_CXX_FLAGS="-fsanitize=address" \
-DCMAKE_C_FLAGS="-fsanitize=address" \
-DCMAKE_EXE_LINKER_FLAGS="-fsanitize=address" \
-DCMAKE_MODULE_LINKER_FLAGS="-fsanitize=address" ..
make -j2 VERBOSE=1
make tests
make install
Expand Down
16 changes: 15 additions & 1 deletion include/exiv2/types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,14 @@
//! Simple common max macro
#define EXV_MAX(a,b) ((a) > (b) ? (a) : (b))

#if defined(__GNUC__) && (__GNUC__ >= 4) || defined(__clang__)
#define EXV_WARN_UNUSED_RESULT __attribute__ ((warn_unused_result))
#elif defined(_MSC_VER) && (_MSC_VER >= 1700)
#define EXV_WARN_UNUSED_RESULT _Check_return_
#else
#define EXV_WARN_UNUSED_RESULT
#endif

// *****************************************************************************
// forward declarations
struct tm;
Expand Down Expand Up @@ -235,7 +243,13 @@ namespace Exiv2 {
buffer as a data pointer and size pair, resets the internal
buffer.
*/
std::pair<byte*, long> release();
EXV_WARN_UNUSED_RESULT std::pair<byte*, long> release();

/*!
@brief Free the internal buffer and reset the size to 0.
*/
void free();

//! Reset value
void reset(std::pair<byte*, long> =std::make_pair((byte*)(0),long(0)));
//@}
Expand Down
11 changes: 6 additions & 5 deletions src/basicio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2460,11 +2460,12 @@ namespace Exiv2 {
if (protocol_ == pSftp) {
if (sftp_seek(fileHandler_, (uint32_t) (lowBlock * blockSize_)) < 0) throw Error(kerErrorMessage, "SFTP: unable to sftp_seek");
size_t buffSize = (highBlock - lowBlock + 1) * blockSize_;
char* buffer = new char[buffSize];
long nBytes = (long) sftp_read(fileHandler_, buffer, buffSize);
if (nBytes < 0) throw Error(kerErrorMessage, "SFTP: unable to sftp_read");
response.assign(buffer, buffSize);
delete[] buffer;
std::vector<char> buffer(buffSize);
long nBytes = static_cast<long>(sftp_read(fileHandler_, &buffer.at(0), buffSize));
if (nBytes < 0) {
throw Error(kerErrorMessage, "SFTP: unable to sftp_read");
}
response.assign(&buffer.at(0), buffSize);
} else {
std::stringstream ss;
if (lowBlock > -1 && highBlock > -1) {
Expand Down
2 changes: 1 addition & 1 deletion src/image.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -662,7 +662,7 @@ namespace Exiv2 {

void Image::clearIccProfile()
{
iccProfile_.release();
iccProfile_.free();
}

void Image::setByteOrder(ByteOrder byteOrder)
Expand Down
42 changes: 24 additions & 18 deletions src/iptc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -348,24 +348,30 @@ namespace Exiv2 {
return iptcMetadata_.erase(pos);
}

void IptcData::printStructure(std::ostream& out, const byte* bytes,const size_t size,uint32_t depth)
{
uint32_t i = 0 ;
while ( i < size-3 && bytes[i] != 0x1c ) i++;
depth++;
out << Internal::indent(depth) << "Record | DataSet | Name | Length | Data" << std::endl;
while ( bytes[i] == 0x1c && i < size-3 ) {
char buff[100];
uint16_t record = bytes[i+1];
uint16_t dataset = bytes[i+2];
uint16_t len = getUShort(bytes+i+3,bigEndian);
sprintf(buff," %6d | %7d | %-24s | %6d | ",record,dataset, Exiv2::IptcDataSets::dataSetName(dataset,record).c_str(), len);

out << buff << Internal::binaryToString(bytes,(len>40?40:len),i+5) << (len>40?"...":"") << std::endl;
i += 5 + len;
}
depth--;
}
void IptcData::printStructure(std::ostream& out, const byte* bytes, const size_t size, uint32_t depth)
{
uint32_t i = 0;
while (i < size - 3 && bytes[i] != 0x1c)
i++;
depth++;
out << Internal::indent(depth) << "Record | DataSet | Name | Length | Data" << std::endl;
while (i < size - 3) {
if (bytes[i] != 0x1c) {
break;
}
char buff[100];
uint16_t record = bytes[i + 1];
uint16_t dataset = bytes[i + 2];
uint16_t len = getUShort(bytes + i + 3, bigEndian);
sprintf(buff, " %6d | %7d | %-24s | %6d | ", record, dataset,
Exiv2::IptcDataSets::dataSetName(dataset, record).c_str(), len);

out << buff << Internal::binaryToString(bytes, (len > 40 ? 40 : len), i + 5) << (len > 40 ? "..." : "")
<< std::endl;
i += 5 + len;
}
depth--;
}

const char *IptcData::detectCharset() const
{
Expand Down
52 changes: 36 additions & 16 deletions src/pngimage.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// ***************************************************************** -*- C++ -*-
/*
* Copyright (C) 2004-2017 Andreas Huggel <ahuggel@gmx.net>
* Copyright (C) 2004-2018 Exiv2 authors
*
* This program is part of the Exiv2 distribution.
*
Expand Down Expand Up @@ -57,6 +57,16 @@ const unsigned char pngBlank[] = { 0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,
0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};

namespace
{
inline bool compare(const char* str, const Exiv2::DataBuf& buf, size_t length)
{
// str & length should compile time constants => only running this in DEBUG mode is ok
assert(strlen(str) <= length);
return memcmp(str, buf.pData_, std::min(static_cast<long>(length), buf.size_)) == 0;
}
} // namespace

// *****************************************************************************
// class member definitions
namespace Exiv2 {
Expand Down Expand Up @@ -99,13 +109,14 @@ namespace Exiv2 {
zlibResult = uncompress((Bytef*)result.pData_,&uncompressedLen,bytes,length);
// if result buffer is large than necessary, redo to fit perfectly.
if (zlibResult == Z_OK && (long) uncompressedLen < result.size_ ) {
result.release();
result.free();

result.alloc(uncompressedLen);
zlibResult = uncompress((Bytef*)result.pData_,&uncompressedLen,bytes,length);
}
if (zlibResult == Z_BUF_ERROR) {
// the uncompressed buffer needs to be larger
result.release();
result.free();

// Sanity - never bigger than 16mb
if (uncompressedLen > 16*1024*1024) zlibResult = Z_DATA_ERROR;
Expand All @@ -126,10 +137,10 @@ namespace Exiv2 {
zlibResult = compress((Bytef*)result.pData_,&compressedLen,bytes,length);
if (zlibResult == Z_BUF_ERROR) {
// the compressedArray needs to be larger
result.release();
result.free();
compressedLen *= 2;
} else {
result.release();
result.free();
result.alloc(compressedLen);
zlibResult = compress((Bytef*)result.pData_,&compressedLen,bytes,length);
}
Expand All @@ -154,12 +165,21 @@ namespace Exiv2 {
}

// calculate length and allocate result;
// count: number of \n in the header
long count=0;
// p points to the current position in the array bytes
const byte* p = bytes ;
// header is \nsomething\n number\n hex
while ( count < 3 )
if ( *p++ == '\n' )

// header is '\nsomething\n number\n hex'
// => increment p until it points to the byte after the last \n
// p must stay within bounds of the bytes array!
while ((count < 3) && (p - bytes < length)) {
// length is later used for range checks of p => decrement it for each increment of p
--length;
if ( *p++ == '\n' ) {
count++;
}
}
for ( long i = 0 ; i < length ; i++ )
if ( value[p[i]] )
++count;
Expand Down Expand Up @@ -678,14 +698,14 @@ namespace Exiv2 {
!memcmp(cheaderBuf.pData_ + 4, "iCCP", 4))
{
DataBuf key = PngChunk::keyTXTChunk(chunkBuf, true);
if (memcmp("Raw profile type exif", key.pData_, 21) == 0 ||
memcmp("Raw profile type APP1", key.pData_, 21) == 0 ||
memcmp("Raw profile type iptc", key.pData_, 21) == 0 ||
memcmp("Raw profile type xmp", key.pData_, 20) == 0 ||
memcmp("XML:com.adobe.xmp", key.pData_, 17) == 0 ||
memcmp("icc", key.pData_, 3) == 0 || // see test/data/imagemagick.png
memcmp("ICC", key.pData_, 3) == 0 ||
memcmp("Description", key.pData_, 11) == 0)
if (compare("Raw profile type exif", key, 21) ||
compare("Raw profile type APP1", key, 21) ||
compare("Raw profile type iptc", key, 21) ||
compare("Raw profile type xmp", key, 20) ||
compare("XML:com.adobe.xmp", key, 17) ||
compare("icc", key, 3) || // see test/data/imagemagick.png
compare("ICC", key, 3) ||
compare("Description", key, 11))
{
#ifdef DEBUG
std::cout << "Exiv2::PngImage::doWriteMetadata: strip " << szChunk
Expand Down
9 changes: 8 additions & 1 deletion src/types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,14 +155,21 @@ namespace Exiv2 {
}
}

std::pair<byte*, long> DataBuf::release()
EXV_WARN_UNUSED_RESULT std::pair<byte*, long> DataBuf::release()
{
std::pair<byte*, long> p = std::make_pair(pData_, size_);
pData_ = 0;
size_ = 0;
return p;
}

void DataBuf::free()
{
delete[] pData_;
pData_ = 0;
size_ = 0;
}

void DataBuf::reset(std::pair<byte*, long> p)
{
if (pData_ != p.first) {
Expand Down
3 changes: 2 additions & 1 deletion src/webpimage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -594,7 +594,8 @@ namespace Exiv2 {
io_->read(payload.pData_, payload.size_);

byte size_buff[2];
byte exifLongHeader[] = { 0xFF, 0x01, 0xFF, 0xE1 };
// 4 meaningful bytes + 2 padding bytes
byte exifLongHeader[] = { 0xFF, 0x01, 0xFF, 0xE1, 0x00, 0x00 };
byte exifShortHeader[] = { 0x45, 0x78, 0x69, 0x66, 0x00, 0x00 };
byte exifTiffLEHeader[] = { 0x49, 0x49, 0x2A }; // "MM*"
byte exifTiffBEHeader[] = { 0x4D, 0x4D, 0x00, 0x2A }; // "II\0*"
Expand Down

0 comments on commit 24ef91f

Please sign in to comment.