diff options
author | Florian Kriener <floriank@google.com> | 2016-02-29 15:38:08 +0100 |
---|---|---|
committer | Florian Kriener <floriank@google.com> | 2016-03-01 12:40:19 +0100 |
commit | a9912faa4ebc5100cfb7f03718304a315edf32fb (patch) | |
tree | b686396ed7f251badccf2ceabdfb8a7269cf5233 /source | |
parent | 0b098b759cf9a2a8659babaf8c3b74e1b48ca604 (diff) | |
download | dng_sdk-a9912faa4ebc5100cfb7f03718304a315edf32fb.tar.gz |
Integrate integer overflow changes from security branch
Bug: 26535130
Change-Id: Idafa0626ce5bea6c265d64175702ac85ed738b41
Diffstat (limited to 'source')
37 files changed, 397 insertions, 303 deletions
diff --git a/source/RawEnvironment.h b/source/RawEnvironment.h index 3613cd4..688ee0e 100644 --- a/source/RawEnvironment.h +++ b/source/RawEnvironment.h @@ -1,3 +1,6 @@ +#ifndef __dng_RawEnvironment__ +#define __dng_RawEnvironment__ + // Define preprocessor constants that control platform-specific conditional // compilation. The constants qMacOS and qWinOS must be defined on all // platforms. Other constants, such as qLinux, only need to be defined if we're @@ -14,3 +17,4 @@ #define qWinOS 1 #endif +#endif // __dng_RawEnvironment__ diff --git a/source/dng_auto_ptr.h b/source/dng_auto_ptr.h index 6d70fe6..ed88bba 100644 --- a/source/dng_auto_ptr.h +++ b/source/dng_auto_ptr.h @@ -193,7 +193,7 @@ class AutoArray /// Construct an AutoArray that refers to a null pointer. AutoArray () { } - + /// Construct an AutoArray containing 'count' elements, which are /// default-constructed. If an out-of-memory condition occurs, a /// dng_exception with error code dng_error_memory is thrown. diff --git a/source/dng_camera_profile.cpp b/source/dng_camera_profile.cpp index 06f423b..34a3105 100644 --- a/source/dng_camera_profile.cpp +++ b/source/dng_camera_profile.cpp @@ -21,6 +21,7 @@ #include "dng_image_writer.h" #include "dng_info.h" #include "dng_parse_utils.h" +#include "dng_safe_arithmetic.h" #include "dng_tag_codes.h" #include "dng_tag_types.h" #include "dng_temperature.h" @@ -898,11 +899,6 @@ void dng_camera_profile::ReadHueSatMap (dng_stream &stream, /*****************************************************************************/ -#if defined(__clang__) && defined(__has_attribute) -#if __has_attribute(no_sanitize) -__attribute__((no_sanitize("unsigned-integer-overflow"))) -#endif -#endif void dng_camera_profile::Parse (dng_stream &stream, dng_camera_profile_info &profileInfo) { @@ -971,9 +967,10 @@ void dng_camera_profile::Parse (dng_stream &stream, stream.SetReadPosition (profileInfo.fHueSatDeltas1Offset); - bool skipSat0 = (profileInfo.fHueSatDeltas1Count == profileInfo.fProfileHues * - (profileInfo.fProfileSats - 1) * - profileInfo.fProfileVals * 3); + bool skipSat0 = (profileInfo.fHueSatDeltas1Count == SafeUint32Mult( + profileInfo.fProfileHues, + SafeUint32Sub(profileInfo.fProfileSats, 1), + profileInfo.fProfileVals, 3)); ReadHueSatMap (stream, fHueSatDeltas1, @@ -992,9 +989,10 @@ void dng_camera_profile::Parse (dng_stream &stream, stream.SetReadPosition (profileInfo.fHueSatDeltas2Offset); - bool skipSat0 = (profileInfo.fHueSatDeltas2Count == profileInfo.fProfileHues * - (profileInfo.fProfileSats - 1) * - profileInfo.fProfileVals * 3); + bool skipSat0 = (profileInfo.fHueSatDeltas2Count == SafeUint32Mult( + profileInfo.fProfileHues, + SafeUint32Sub(profileInfo.fProfileSats, 1), + profileInfo.fProfileVals, 3)); ReadHueSatMap (stream, fHueSatDeltas2, @@ -1013,9 +1011,10 @@ void dng_camera_profile::Parse (dng_stream &stream, stream.SetReadPosition (profileInfo.fLookTableOffset); - bool skipSat0 = (profileInfo.fLookTableCount == profileInfo.fLookTableHues * - (profileInfo.fLookTableSats - 1) * - profileInfo.fLookTableVals * 3); + bool skipSat0 = (profileInfo.fLookTableCount == SafeUint32Mult( + profileInfo.fLookTableHues, + SafeUint32Sub(profileInfo.fLookTableSats, 1), + profileInfo.fLookTableVals, 3)); ReadHueSatMap (stream, fLookTable, diff --git a/source/dng_color_spec.cpp b/source/dng_color_spec.cpp index b376410..57c8b25 100644 --- a/source/dng_color_spec.cpp +++ b/source/dng_color_spec.cpp @@ -409,6 +409,7 @@ void dng_color_spec::SetWhiteXY (const dng_xy_coord &white) // Find the camera white values. fCameraWhite = colorMatrix * XYtoXYZ (fWhiteXY); + real64 cameraWhiteMaxEntry = MaxEntry (fCameraWhite); if (cameraWhiteMaxEntry == 0) { @@ -433,7 +434,7 @@ void dng_color_spec::SetWhiteXY (const dng_xy_coord &white) fPCStoCamera = colorMatrix * MapWhiteMatrix (PCStoXY (), fWhiteXY); real64 scale = MaxEntry (fPCStoCamera * PCStoXYZ ()); - + if (scale == 0) { ThrowBadFormat (); diff --git a/source/dng_date_time.cpp b/source/dng_date_time.cpp index e7175b8..bede131 100644 --- a/source/dng_date_time.cpp +++ b/source/dng_date_time.cpp @@ -103,11 +103,6 @@ void dng_date_time::Clear () /*****************************************************************************/ -#if defined(__clang__) && defined(__has_attribute) -#if __has_attribute(no_sanitize) -__attribute__((no_sanitize("unsigned-integer-overflow"))) -#endif -#endif static uint32 DateTimeParseU32 (const char *&s) { @@ -118,7 +113,8 @@ static uint32 DateTimeParseU32 (const char *&s) while (*s >= '0' && *s <= '9') { - x = x * 10 + (uint32) (*(s++) - '0'); + x = SafeUint32Mult(x, 10); + x = SafeUint32Add(x, (uint32) (*(s++) - '0')); } return x; diff --git a/source/dng_date_time.h b/source/dng_date_time.h index 846c5c9..8cb5433 100644 --- a/source/dng_date_time.h +++ b/source/dng_date_time.h @@ -149,7 +149,7 @@ class dng_time_zone void SetOffsetHours (int32 offset) { - fOffsetMinutes = (int32) ((int64) offset * 60); + fOffsetMinutes = SafeInt32Mult(offset, 60); } void SetOffsetMinutes (int32 offset) diff --git a/source/dng_filter_task.cpp b/source/dng_filter_task.cpp index 3676b6e..7823102 100644 --- a/source/dng_filter_task.cpp +++ b/source/dng_filter_task.cpp @@ -62,12 +62,12 @@ void dng_filter_task::Start (uint32 threadCount, { fSrcTileSize = SrcTileSize (tileSize); - + uint32 srcBufferSize = ComputeBufferSize(fSrcPixelType, fSrcTileSize, fSrcPlanes, pad16Bytes); uint32 dstBufferSize = ComputeBufferSize(fDstPixelType, tileSize, fDstPlanes, pad16Bytes); - + for (uint32 threadIndex = 0; threadIndex < threadCount; threadIndex++) { @@ -95,20 +95,20 @@ void dng_filter_task::Process (uint32 threadIndex, { // Find source area for this destination area. - + dng_rect srcArea = SrcArea (area); - + int32 src_area_w; int32 src_area_h; if (!ConvertUint32ToInt32 (srcArea.W (), &src_area_w) || !ConvertUint32ToInt32 (srcArea.H (), &src_area_h) || src_area_w > fSrcTileSize.h || src_area_h > fSrcTileSize.v) { - + ThrowMemoryFull("Area exceeds tile size."); - + } - + // Setup srcBuffer. - + dng_pixel_buffer srcBuffer(srcArea, fSrcPlane, fSrcPlanes, fSrcPixelType, pcRowInterleavedAlign16, fSrcBuffer [threadIndex]->Buffer ()); diff --git a/source/dng_fingerprint.h b/source/dng_fingerprint.h index 74830e9..fe5c6d3 100644 --- a/source/dng_fingerprint.h +++ b/source/dng_fingerprint.h @@ -225,8 +225,8 @@ class dng_md5_printer } // FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. - -#if defined(__clang__) && defined(__has_attribute) + +#if defined(__clang__) && defined(__has_attribute) #if __has_attribute(no_sanitize) __attribute__((no_sanitize("unsigned-integer-overflow"))) #endif diff --git a/source/dng_flags.h b/source/dng_flags.h index 8b6c2f9..036914a 100644 --- a/source/dng_flags.h +++ b/source/dng_flags.h @@ -158,7 +158,7 @@ #ifndef qDNG64Bit -#if qMacOS +#if qMacOS || qLinux #ifdef __LP64__ #if __LP64__ diff --git a/source/dng_gain_map.cpp b/source/dng_gain_map.cpp index 489fca0..87d7e6f 100644 --- a/source/dng_gain_map.cpp +++ b/source/dng_gain_map.cpp @@ -19,6 +19,7 @@ #include "dng_globals.h" #include "dng_host.h" #include "dng_pixel_buffer.h" +#include "dng_safe_arithmetic.h" #include "dng_stream.h" #include "dng_tag_values.h" @@ -248,11 +249,6 @@ void dng_gain_map_interpolator::ResetColumn () /*****************************************************************************/ -#if defined(__clang__) && defined(__has_attribute) -#if __has_attribute(no_sanitize) -__attribute__((no_sanitize("unsigned-integer-overflow"))) -#endif -#endif dng_gain_map::dng_gain_map (dng_memory_allocator &allocator, const dng_point &points, const dng_point_real64 &spacing, @@ -264,7 +260,7 @@ dng_gain_map::dng_gain_map (dng_memory_allocator &allocator, , fOrigin (origin) , fPlanes (planes) - , fRowStep (planes * points.h) + , fRowStep (SafeUint32Mult(planes, points.h)) , fBuffer () diff --git a/source/dng_host.cpp b/source/dng_host.cpp index d36572c..28f1930 100644 --- a/source/dng_host.cpp +++ b/source/dng_host.cpp @@ -275,7 +275,7 @@ dng_exif * dng_host::Make_dng_exif () dng_xmp * dng_host::Make_dng_xmp () { - + dng_xmp *result = new dng_xmp (Allocator ()); if (!result) diff --git a/source/dng_hue_sat_map.cpp b/source/dng_hue_sat_map.cpp index 4740e82..c86446f 100644 --- a/source/dng_hue_sat_map.cpp +++ b/source/dng_hue_sat_map.cpp @@ -97,11 +97,6 @@ dng_hue_sat_map::~dng_hue_sat_map () /*****************************************************************************/ -#if defined(__clang__) && defined(__has_attribute) -#if __has_attribute(no_sanitize) -__attribute__((no_sanitize("unsigned-integer-overflow"))) -#endif -#endif void dng_hue_sat_map::SetDivisions (uint32 hueDivisions, uint32 satDivisions, uint32 valDivisions) @@ -125,9 +120,9 @@ void dng_hue_sat_map::SetDivisions (uint32 hueDivisions, fValDivisions = valDivisions; fHueStep = satDivisions; - fValStep = hueDivisions * fHueStep; + fValStep = SafeUint32Mult(hueDivisions, fHueStep); - uint32 size = DeltasCount () * (uint32) sizeof (HSBModify); + uint32 size = SafeUint32Mult(DeltasCount (), (uint32) sizeof (HSBModify)); fDeltas.Allocate (size); diff --git a/source/dng_ifd.cpp b/source/dng_ifd.cpp index b0ff06b..570477d 100644 --- a/source/dng_ifd.cpp +++ b/source/dng_ifd.cpp @@ -256,11 +256,6 @@ dng_ifd::~dng_ifd () /*****************************************************************************/ -#if defined(__clang__) && defined(__has_attribute) -#if __has_attribute(no_sanitize) -__attribute__((no_sanitize("unsigned-integer-overflow"))) -#endif -#endif // Parses tags that should only appear in IFDs that contain images. bool dng_ifd::ParseTag (dng_stream &stream, @@ -1541,9 +1536,9 @@ bool dng_ifd::ParseTag (dng_stream &stream, CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong, ttRational); - if (!CheckTagCount (parentCode, tagCode, tagCount, fBlackLevelRepeatRows * - fBlackLevelRepeatCols * - fSamplesPerPixel)) + if (!CheckTagCount (parentCode, tagCode, tagCount, SafeUint32Mult(fBlackLevelRepeatRows, + fBlackLevelRepeatCols, + fSamplesPerPixel))) { return false; } @@ -2722,11 +2717,6 @@ bool dng_ifd::IsValidCFA (dng_shared &shared, /*****************************************************************************/ -#if defined(__clang__) && defined(__has_attribute) -#if __has_attribute(no_sanitize) -__attribute__((no_sanitize("unsigned-integer-overflow"))) -#endif -#endif bool dng_ifd::IsValidDNG (dng_shared &shared, uint32 parentCode) { @@ -3446,8 +3436,8 @@ bool dng_ifd::IsValidDNG (dng_shared &shared, // Check tile info. - uint32 tilesWide = (fImageWidth + fTileWidth - 1) / fTileWidth; - uint32 tilesHigh = (fImageLength + fTileLength - 1) / fTileLength; + uint32 tilesWide = SafeUint32DivideUp(fImageWidth, fTileWidth); + uint32 tilesHigh = SafeUint32DivideUp(fImageLength, fTileLength); uint32 tileCount = tilesWide * tilesHigh; @@ -4061,37 +4051,31 @@ dng_rect dng_ifd::TileArea (uint32 rowIndex, /*****************************************************************************/ -#if defined(__clang__) && defined(__has_attribute) -#if __has_attribute(no_sanitize) -__attribute__((no_sanitize("unsigned-integer-overflow"))) -#endif -#endif uint32 dng_ifd::TileByteCount (const dng_rect &tile) const { if (fCompression == ccUncompressed) { - uint32 bitsPerRow = tile.W () * - fBitsPerSample [0]; + uint32 bitsPerRow = SafeUint32Mult(tile.W (), fBitsPerSample [0]); if (fPlanarConfiguration == pcInterleaved) { - bitsPerRow *= fSamplesPerPixel; + bitsPerRow = SafeUint32Mult(bitsPerRow, fSamplesPerPixel); } - uint32 bytesPerRow = (bitsPerRow + 7) >> 3; + uint32 bytesPerRow = SafeUint32DivideUp(bitsPerRow, 8); if (fPlanarConfiguration == pcRowInterleaved) { - bytesPerRow *= fSamplesPerPixel; + bytesPerRow = SafeUint32Mult(bytesPerRow, fSamplesPerPixel); } - return bytesPerRow * tile.H (); + return SafeUint32Mult(bytesPerRow, tile.H ()); } diff --git a/source/dng_image_writer.cpp b/source/dng_image_writer.cpp index 049d7c3..5c81042 100644 --- a/source/dng_image_writer.cpp +++ b/source/dng_image_writer.cpp @@ -50,7 +50,7 @@ #if qDNGUseLibJPEG #include "dng_jpeglib.h" #endif - + /*****************************************************************************/ // Defines for testing DNG 1.2 features. @@ -4901,9 +4901,9 @@ static void CopyBoolean (const dng_xmp &oldXMP, } } - #endif + /*****************************************************************************/ void dng_image_writer::CleanUpMetadata (dng_host &host, @@ -6506,7 +6506,7 @@ void dng_image_writer::WriteDNG (dng_host &host, } // XMP metadata. - + #if qDNGUseXMP tag_xmp tagXMP (metadata->GetXMP ()); diff --git a/source/dng_info.cpp b/source/dng_info.cpp index 65f3a4b..ed87692 100644 --- a/source/dng_info.cpp +++ b/source/dng_info.cpp @@ -21,6 +21,7 @@ #include "dng_host.h" #include "dng_tag_codes.h" #include "dng_parse_utils.h" +#include "dng_safe_arithmetic.h" #include "dng_tag_types.h" #include "dng_tag_values.h" #include "dng_utils.h" @@ -334,11 +335,6 @@ void dng_info::ParseTag (dng_host &host, /*****************************************************************************/ -#if defined(__clang__) && defined(__has_attribute) -#if __has_attribute(no_sanitize) -__attribute__((no_sanitize("unsigned-integer-overflow"))) -#endif -#endif bool dng_info::ValidateIFD (dng_stream &stream, uint64 ifdOffset, int64 offsetDelta) @@ -388,7 +384,7 @@ bool dng_info::ValidateIFD (dng_stream &stream, return false; } - uint32 tag_data_size = tagCount * tag_type_size; + uint32 tag_data_size = SafeUint32Mult(tagCount, tag_type_size); if (tag_data_size > 4) { @@ -397,7 +393,7 @@ bool dng_info::ValidateIFD (dng_stream &stream, tagOffset += offsetDelta; - if (tagOffset + tag_data_size > stream.Length ()) + if (SafeUint64Add(tagOffset, tag_data_size) > stream.Length()) { return false; } @@ -412,11 +408,6 @@ bool dng_info::ValidateIFD (dng_stream &stream, /*****************************************************************************/ -#if defined(__clang__) && defined(__has_attribute) -#if __has_attribute(no_sanitize) -__attribute__((no_sanitize("unsigned-integer-overflow"))) -#endif -#endif void dng_info::ParseIFD (dng_host &host, dng_stream &stream, dng_exif *exif, @@ -558,7 +549,7 @@ void dng_info::ParseIFD (dng_host &host, uint64 tagOffset = ifdOffset + 2 + tag_index * 12 + 8; - if (tagCount * tag_type_size > 4) + if (SafeUint32Mult(tagCount, tag_type_size) > 4) { tagOffset = stream.Get_uint32 (); @@ -662,11 +653,6 @@ void dng_info::ParseIFD (dng_host &host, /*****************************************************************************/ -#if defined(__clang__) && defined(__has_attribute) -#if __has_attribute(no_sanitize) -__attribute__((no_sanitize("unsigned-integer-overflow"))) -#endif -#endif bool dng_info::ParseMakerNoteIFD (dng_host &host, dng_stream &stream, uint64 ifdSize, @@ -760,7 +746,7 @@ bool dng_info::ParseMakerNoteIFD (dng_host &host, continue; } - uint32 tagSize = tagCount * TagTypeSize (tagType); + uint32 tagSize = SafeUint32Mult(tagCount, TagTypeSize (tagType)); uint64 tagOffset = ifdOffset + 2 + tagIndex * 12 + 8; @@ -770,7 +756,7 @@ bool dng_info::ParseMakerNoteIFD (dng_host &host, tagOffset = stream.Get_uint32 () + offsetDelta; if (tagOffset < minOffset || - tagOffset + tagSize > maxOffset) + SafeUint64Add(tagOffset, tagSize) > maxOffset) { // Tag data is outside the valid offset range, @@ -1427,11 +1413,6 @@ void dng_info::ParseSonyPrivateData (dng_host & /* host */, /*****************************************************************************/ -#if defined(__clang__) && defined(__has_attribute) -#if __has_attribute(no_sanitize) -__attribute__((no_sanitize("unsigned-integer-overflow"))) -#endif -#endif void dng_info::ParseDNGPrivateData (dng_host &host, dng_stream &stream) { @@ -1543,7 +1524,7 @@ void dng_info::ParseDNGPrivateData (dng_host &host, uint16 order_mark = stream.Get_uint16 (); int64 old_offset = stream.Get_uint32 (); - uint32 tempSize = section_count - 6; + uint32 tempSize = SafeUint32Sub(section_count, 6); AutoPtr<dng_memory_block> tempBlock (host.Allocate (tempSize)); @@ -1629,7 +1610,7 @@ void dng_info::ParseDNGPrivateData (dng_host &host, tagOffset, 0); - stream.SetReadPosition (tagOffset + tagCount); + stream.SetReadPosition (SafeUint64Add(tagOffset, tagCount)); } @@ -1654,7 +1635,7 @@ void dng_info::ParseDNGPrivateData (dng_host &host, tagOffset, 0); - stream.SetReadPosition (tagOffset + tagCount); + stream.SetReadPosition (SafeUint64Add(tagOffset, tagCount)); } @@ -1679,7 +1660,7 @@ void dng_info::ParseDNGPrivateData (dng_host &host, tagOffset, 0); - stream.SetReadPosition (tagOffset + tagCount); + stream.SetReadPosition (SafeUint64Add(tagOffset, tagCount)); } @@ -1860,7 +1841,7 @@ void dng_info::ParseDNGPrivateData (dng_host &host, uint32 tagCount = stream.Get_uint32 (); - uint32 tagSize = tagCount * TagTypeSize (tagType); + uint32 tagSize = SafeUint32Mult(tagCount, TagTypeSize (tagType)); uint64 tagOffset = stream.Position (); @@ -1878,7 +1859,7 @@ void dng_info::ParseDNGPrivateData (dng_host &host, tagOffset, 0); - stream.SetReadPosition (tagOffset + tagSize); + stream.SetReadPosition (SafeUint64Add(tagOffset, tagSize)); } diff --git a/source/dng_lens_correction.cpp b/source/dng_lens_correction.cpp index 5afda9f..67c09ac 100644 --- a/source/dng_lens_correction.cpp +++ b/source/dng_lens_correction.cpp @@ -29,6 +29,7 @@ #include "dng_safe_arithmetic.h" #include "dng_sdk_limits.h" #include "dng_tag_values.h" +#include "dng_utils.h" /*****************************************************************************/ @@ -1111,11 +1112,6 @@ void dng_filter_warp::Initialize (dng_host &host) /*****************************************************************************/ -#if defined(__clang__) && defined(__has_attribute) -#if __has_attribute(no_sanitize) -__attribute__((no_sanitize("float-cast-overflow"))) -#endif -#endif dng_rect dng_filter_warp::SrcArea (const dng_rect &dstArea) { @@ -1143,7 +1139,7 @@ dng_rect dng_filter_warp::SrcArea (const dng_rect &dstArea) const dng_point_real64 src = GetSrcPixelPosition (dst, plane); - const int32 y = (int32) floor (src.v); + const int32 y = ConvertDoubleToInt32 (floor (src.v)); yMin = Min_int32 (yMin, y); @@ -1157,7 +1153,7 @@ dng_rect dng_filter_warp::SrcArea (const dng_rect &dstArea) const dng_point_real64 src = GetSrcPixelPosition (dst, plane); - const int32 y = (int32) ceil (src.v); + const int32 y = ConvertDoubleToInt32 (ceil (src.v)); yMax = Max_int32 (yMax, y); @@ -1178,7 +1174,7 @@ dng_rect dng_filter_warp::SrcArea (const dng_rect &dstArea) const dng_point_real64 src = GetSrcPixelPosition (dst, plane); - const int32 x = (int32) floor (src.h); + const int32 x = ConvertDoubleToInt32 (floor (src.h)); xMin = Min_int32 (xMin, x); @@ -1192,7 +1188,7 @@ dng_rect dng_filter_warp::SrcArea (const dng_rect &dstArea) const dng_point_real64 src = GetSrcPixelPosition (dst, plane); - const int32 x = (int32) ceil (src.h); + const int32 x = ConvertDoubleToInt32 (ceil (src.h)); xMax = Max_int32 (xMax, x); @@ -1204,15 +1200,15 @@ dng_rect dng_filter_warp::SrcArea (const dng_rect &dstArea) // Pad each side by filter radius. - const int32 pad = (int32) fWeights.Radius (); + const int32 pad = ConvertUint32ToInt32(fWeights.Radius()); - xMin = (int32) ((int64) xMin - (int64)pad); - yMin = (int32) ((int64) yMin - (int64)pad); - xMax = (int32) ((int64) xMax + (int64)pad); - yMax = (int32) ((int64) yMax + (int64)pad); + xMin = SafeInt32Sub(xMin, pad); + yMin = SafeInt32Sub(yMin, pad); + xMax = SafeInt32Add(xMax, pad); + yMax = SafeInt32Add(yMax, pad); - xMax = (int32) ((int64) xMax + 1); - yMax = (int32) ((int64) yMax + 1); + xMax = SafeInt32Add(xMax, 1); + yMax = SafeInt32Add(yMax, 1); const dng_rect srcArea (yMin, xMin, @@ -1225,11 +1221,6 @@ dng_rect dng_filter_warp::SrcArea (const dng_rect &dstArea) /*****************************************************************************/ -#if defined(__clang__) && defined(__has_attribute) -#if __has_attribute(no_sanitize) -__attribute__((no_sanitize("float-cast-overflow"))) -#endif -#endif dng_point dng_filter_warp::SrcTileSize (const dng_point &dstTileSize) { @@ -1266,14 +1257,14 @@ dng_point dng_filter_warp::SrcTileSize (const dng_point &dstTileSize) const real64 maxSrcGap = fParams->MaxSrcRadiusGap (maxDstGap); - const int32 dim = (int32) ceil (maxSrcGap * fNormRadius); + const int32 dim = ConvertDoubleToInt32 (ceil (maxSrcGap * fNormRadius)); srcTileSize = dng_point (dim, dim); } - srcTileSize.h += (int32) (fWeights.Width ()); - srcTileSize.v += (int32) (fWeights.Width ()); + srcTileSize.h += ConvertUint32ToInt32(fWeights.Width()); + srcTileSize.v += ConvertUint32ToInt32(fWeights.Width()); // Get upper bound on src tile size from tangential warp. @@ -1290,8 +1281,8 @@ dng_point dng_filter_warp::SrcTileSize (const dng_point &dstTileSize) // Add the two bounds together. - srcTileSize.v = (int32) ((real64) srcTileSize.v + (real64) ceil (srcTanGap.v * fNormRadius)); - srcTileSize.h = (int32) ((real64) srcTileSize.h + (real64) ceil (srcTanGap.h * fNormRadius)); + srcTileSize.v += ConvertDoubleToInt32 (ceil (srcTanGap.v * fNormRadius)); + srcTileSize.h += ConvertDoubleToInt32 (ceil (srcTanGap.h * fNormRadius)); return srcTileSize; @@ -1299,11 +1290,6 @@ dng_point dng_filter_warp::SrcTileSize (const dng_point &dstTileSize) /*****************************************************************************/ -#if defined(__clang__) && defined(__has_attribute) -#if __has_attribute(no_sanitize) -__attribute__((no_sanitize("float-cast-overflow"))) -#endif -#endif void dng_filter_warp::ProcessArea (uint32 /* threadIndex */, dng_pixel_buffer &srcBuffer, dng_pixel_buffer &dstBuffer) @@ -1367,11 +1353,11 @@ void dng_filter_warp::ProcessArea (uint32 /* threadIndex */, // Decompose into integer and fractional parts. - dng_point sInt ((int32) floor (sPos.v), - (int32) floor (sPos.h)); + dng_point sInt (ConvertDoubleToInt32 (floor (sPos.v)), + ConvertDoubleToInt32 (floor (sPos.h))); - dng_point sFct ((int32) ((sPos.v - (real64) sInt.v) * numSubsamples), - (int32) ((sPos.h - (real64) sInt.h) * numSubsamples)); + dng_point sFct (ConvertDoubleToInt32 ((sPos.v - (real64) sInt.v) * numSubsamples), + ConvertDoubleToInt32 ((sPos.h - (real64) sInt.h) * numSubsamples)); // Add resample offset. diff --git a/source/dng_linearization_info.cpp b/source/dng_linearization_info.cpp index 27bc457..95fa493 100644 --- a/source/dng_linearization_info.cpp +++ b/source/dng_linearization_info.cpp @@ -687,7 +687,7 @@ void dng_linearize_plane::Process (const dng_rect &srcTile) uint16 *dstPtr = (uint16 *) dPtr; - b1 = (int32) ((int64) b1 - (int64) 128); // Rounding for 8 bit shift + b1 -= 128; // Rounding for 8 bit shift if (fSrcPixelType == ttByte) { @@ -735,7 +735,7 @@ void dng_linearize_plane::Process (const dng_rect &srcTile) if (b2_count) { - x = (int32) ((int64)x - b2 [b2_phase]); + x -= b2 [b2_phase]; if (++b2_phase == b2_count) { diff --git a/source/dng_lossless_jpeg.cpp b/source/dng_lossless_jpeg.cpp index 9257f88..e3b0576 100644 --- a/source/dng_lossless_jpeg.cpp +++ b/source/dng_lossless_jpeg.cpp @@ -254,7 +254,7 @@ static void FixHuffTbl (HuffmanTable *htbl) { ThrowBadFormat (); } - + for (i = ll; i <= ul; i++) { htbl->numbits [i] = size; @@ -1680,7 +1680,7 @@ inline int32 dng_lossless_decoder::HuffDecode (HuffmanTable *htbl) inline void dng_lossless_decoder::HuffExtend (int32 &x, int32 s) { - + if (x < (0x08000 >> (16 - s))) { x += -(1 << s) + 1; diff --git a/source/dng_memory_stream.cpp b/source/dng_memory_stream.cpp index c5821f3..b6e903e 100644 --- a/source/dng_memory_stream.cpp +++ b/source/dng_memory_stream.cpp @@ -121,7 +121,7 @@ void dng_memory_stream::DoSetLength (uint64 length) if (fPageCount == fPagesAllocated) { - + uint32 newSizeTemp1 = 0, newSizeTemp2 = 0; if (!SafeUint32Add (fPagesAllocated, 32u, &newSizeTemp1) || !SafeUint32Mult (fPagesAllocated, 2u, &newSizeTemp2)) @@ -135,10 +135,10 @@ void dng_memory_stream::DoSetLength (uint64 length) { ThrowMemoryFull ("Arithmetic overflow in DoSetLength()"); } - + dng_memory_block **list = (dng_memory_block **) malloc (numBytes); - - if (!list) + + if (!list) { ThrowMemoryFull (); diff --git a/source/dng_misc_opcodes.cpp b/source/dng_misc_opcodes.cpp index ca7ba8f..5a6fa82 100644 --- a/source/dng_misc_opcodes.cpp +++ b/source/dng_misc_opcodes.cpp @@ -201,11 +201,6 @@ void dng_area_spec::PutData (dng_stream &stream) const /*****************************************************************************/ -#if defined(__clang__) && defined(__has_attribute) -#if __has_attribute(no_sanitize) -__attribute__((no_sanitize("unsigned-integer-overflow"))) -#endif -#endif dng_rect dng_area_spec::Overlap (const dng_rect &tile) const { @@ -222,8 +217,12 @@ dng_rect dng_area_spec::Overlap (const dng_rect &tile) const if (overlap.NotEmpty ()) { - overlap.t = fArea.t + ((overlap.t - fArea.t + fRowPitch - 1) / fRowPitch) * fRowPitch; - overlap.l = fArea.l + ((overlap.l - fArea.l + fColPitch - 1) / fColPitch) * fColPitch; + overlap.t = fArea.t + ConvertUint32ToInt32( + RoundUpUint32ToMultiple(static_cast<uint32>(overlap.t - fArea.t), + fRowPitch)); + overlap.l = fArea.l + ConvertUint32ToInt32( + RoundUpUint32ToMultiple(static_cast<uint32>(overlap.l - fArea.l), + fColPitch)); if (overlap.NotEmpty ()) { @@ -468,11 +467,6 @@ dng_opcode_MapPolynomial::dng_opcode_MapPolynomial (const dng_area_spec &areaSpe /*****************************************************************************/ -#if defined(__clang__) && defined(__has_attribute) -#if __has_attribute(no_sanitize) -__attribute__((no_sanitize("unsigned-integer-overflow"))) -#endif -#endif dng_opcode_MapPolynomial::dng_opcode_MapPolynomial (dng_stream &stream) : dng_inplace_opcode (dngOpcode_MapPolynomial, @@ -490,16 +484,16 @@ dng_opcode_MapPolynomial::dng_opcode_MapPolynomial (dng_stream &stream) fDegree = stream.Get_uint32 (); - if (dataSize != dng_area_spec::kDataSize + 4 + (fDegree + 1) * 8) + if (fDegree > kMaxDegree) { ThrowBadFormat (); } - - if (fDegree > kMaxDegree) + + if (dataSize != dng_area_spec::kDataSize + 4 + (fDegree + 1) * 8) { ThrowBadFormat (); } - + for (uint32 j = 0; j <= kMaxDegree; j++) { diff --git a/source/dng_mosaic_info.cpp b/source/dng_mosaic_info.cpp index 0fb50e6..0a51d9b 100644 --- a/source/dng_mosaic_info.cpp +++ b/source/dng_mosaic_info.cpp @@ -293,17 +293,21 @@ __attribute__((no_sanitize("unsigned-integer-overflow"))) #endif uint32 DeltaRow (uint32 row, int32 delta) { - return (row + fPatRows + (uint32) delta) % fPatRows; + // Potential overflow in the conversion from delta to a uint32 as + // well as in the subsequent addition is intentional. + return (SafeUint32Add(row, fPatRows) + (uint32) delta) % fPatRows; } - + #if defined(__clang__) && defined(__has_attribute) #if __has_attribute(no_sanitize) __attribute__((no_sanitize("unsigned-integer-overflow"))) -#endif +#endif #endif uint32 DeltaCol (uint32 col, int32 delta) { - return (col + fPatCols + (uint32) delta) % fPatCols; + // Potential overflow in the conversion from delta to a uint32 as + // well as in the subsequent addition is intentional. + return (SafeUint32Add(col, fPatCols) + (uint32) delta) % fPatCols; } real32 LinearWeight1 (int32 d1, int32 d2) diff --git a/source/dng_negative.cpp b/source/dng_negative.cpp index ab63e5d..1f7d6ad 100644 --- a/source/dng_negative.cpp +++ b/source/dng_negative.cpp @@ -43,6 +43,7 @@ #include "dng_tag_values.h" #include "dng_tile_iterator.h" #include "dng_utils.h" + #if qDNGUseXMP #include "dng_xmp.h" #endif @@ -237,9 +238,9 @@ void dng_metadata::ApplyOrientation (const dng_orientation &orientation) { fBaseOrientation += orientation; - #if qDNGUseXMP + fXMP->SetOrientation (fBaseOrientation); #endif @@ -545,7 +546,7 @@ void dng_metadata::ResetXMP (dng_xmp * newXMP) { fXMP.Reset (newXMP); - + } /*****************************************************************************/ @@ -720,9 +721,9 @@ void dng_metadata::UpdateMetadataDateTimeToNow () CurrentDateTimeAndZone (dt); - #if qDNGUseXMP +#if qDNGUseXMP fXMP->UpdateMetadataDate (dt); - #endif +#endif } @@ -1679,7 +1680,7 @@ class dng_find_new_raw_image_digest_task : public dng_area_task const uint32 bufferSize = ComputeBufferSize(fPixelType, tileSize, fImage.Planes(), padNone); - + for (uint32 index = 0; index < threadCount; index++) { @@ -4158,11 +4159,6 @@ void dng_negative::DoBuildStage3 (dng_host &host, /*****************************************************************************/ -#if defined(__clang__) && defined(__has_attribute) -#if __has_attribute(no_sanitize) -__attribute__((no_sanitize("unsigned-integer-overflow"))) -#endif -#endif void dng_negative::BuildStage3Image (dng_host &host, int32 srcPlane) { @@ -4201,9 +4197,11 @@ void dng_negative::BuildStage3Image (dng_host &host, uint32 adjust = Round_uint32 (fRawToFullScaleH); - fDefaultCropSizeH .n *= adjust; - fDefaultCropOriginH.n *= adjust; - fDefaultScaleH .d *= adjust; + fDefaultCropSizeH .n = + SafeUint32Mult (fDefaultCropSizeH.n, adjust); + fDefaultCropOriginH.n = + SafeUint32Mult (fDefaultCropOriginH.n, adjust); + fDefaultScaleH .d = SafeUint32Mult (fDefaultScaleH.d, adjust); fRawToFullScaleH /= (real64) adjust; @@ -4214,9 +4212,12 @@ void dng_negative::BuildStage3Image (dng_host &host, uint32 adjust = Round_uint32 (fRawToFullScaleV); - fDefaultCropSizeV .n *= adjust; - fDefaultCropOriginV.n *= adjust; - fDefaultScaleV .d *= adjust; + fDefaultCropSizeV .n = + SafeUint32Mult (fDefaultCropSizeV.n, adjust); + fDefaultCropOriginV.n = + SafeUint32Mult (fDefaultCropOriginV.n, adjust); + fDefaultScaleV .d = + SafeUint32Mult (fDefaultScaleV.d, adjust); fRawToFullScaleV /= (real64) adjust; diff --git a/source/dng_pixel_buffer.cpp b/source/dng_pixel_buffer.cpp index 28385d9..c1380eb 100644 --- a/source/dng_pixel_buffer.cpp +++ b/source/dng_pixel_buffer.cpp @@ -358,7 +358,7 @@ dng_pixel_buffer::dng_pixel_buffer () { } - + /*****************************************************************************/ dng_pixel_buffer::dng_pixel_buffer (const dng_rect &area, @@ -382,7 +382,7 @@ dng_pixel_buffer::dng_pixel_buffer (const dng_rect &area, { const char *overflowMessage = "Arithmetic overflow in pixel buffer setup"; - + // Initialize fRowStep, fColStep and fPlaneStep according to the desired // pixel layout. switch (planarConfiguration) diff --git a/source/dng_pixel_buffer.h b/source/dng_pixel_buffer.h index 104d3b7..e144408 100644 --- a/source/dng_pixel_buffer.h +++ b/source/dng_pixel_buffer.h @@ -126,7 +126,7 @@ class dng_pixel_buffer int32 col, uint32 plane = 0) const { - + // Ensure pixel to be accessed lies inside valid area. if (row < fArea.t || row >= fArea.b || col < fArea.l || col >= fArea.r || diff --git a/source/dng_point.h b/source/dng_point.h index c6070b9..4cad777 100644 --- a/source/dng_point.h +++ b/source/dng_point.h @@ -18,8 +18,8 @@ /*****************************************************************************/ -#include "dng_types.h" #include "dng_safe_arithmetic.h" +#include "dng_types.h" #include "dng_utils.h" /*****************************************************************************/ diff --git a/source/dng_read_image.cpp b/source/dng_read_image.cpp index b2f6dd4..08cb583 100644 --- a/source/dng_read_image.cpp +++ b/source/dng_read_image.cpp @@ -39,7 +39,7 @@ #include "dng_jpeg_memory_source.h" #include "dng_jpeglib.h" #endif - + #include <limits> /******************************************************************************/ @@ -1171,11 +1171,6 @@ dng_read_image::~dng_read_image () /*****************************************************************************/ -#if defined(__clang__) && defined(__has_attribute) -#if __has_attribute(no_sanitize) -__attribute__((no_sanitize("unsigned-integer-overflow"))) -#endif -#endif bool dng_read_image::ReadUncompressed (dng_host &host, const dng_ifd &ifd, dng_stream &stream, @@ -1192,15 +1187,15 @@ bool dng_read_image::ReadUncompressed (dng_host &host, if (ifd.fPlanarConfiguration == pcRowInterleaved) { - rows *= planes; + rows = SafeUint32Mult(rows, planes); } else { - samplesPerRow *= planes; + samplesPerRow = SafeUint32Mult(samplesPerRow, planes); } - uint32 samplesPerTile = samplesPerRow * rows; - + uint32 samplesPerTile = SafeUint32Mult(samplesPerRow, rows); + if (uncompressedBuffer.Get () == NULL) { @@ -1397,7 +1392,7 @@ bool dng_read_image::ReadUncompressed (dng_host &host, uint32 *p = (uint32 *) uncompressedBuffer->Buffer (); - uint32 bitMask = ((uint32)1 << bitDepth) - 1; + uint32 bitMask = ((uint32) 1 << bitDepth) - 1; for (uint32 row = 0; row < rows; row++) { @@ -1809,11 +1804,6 @@ bool dng_read_image::ReadBaselineJPEG (dng_host &host, /*****************************************************************************/ -#if defined(__clang__) && defined(__has_attribute) -#if __has_attribute(no_sanitize) -__attribute__((no_sanitize("unsigned-integer-overflow"))) -#endif -#endif bool dng_read_image::ReadLosslessJPEG (dng_host &host, const dng_ifd &ifd, dng_stream &stream, @@ -1868,9 +1858,9 @@ bool dng_read_image::ReadLosslessJPEG (dng_host &host, *uncompressedBuffer.Get (), subTileBlockBuffer); - uint32 decodedSize = tileArea.W () * - tileArea.H () * - planes * (uint32) sizeof (uint16); + uint32 decodedSize = SafeUint32Mult(tileArea.W (), + tileArea.H (), + planes, (uint32) sizeof (uint16)); bool bug16 = ifd.fLosslessJPEGBug16; @@ -2204,7 +2194,7 @@ void dng_read_image::ReadTile (dng_host &host, ThrowMemoryFull ("Arithmetic overflow computing sample count."); } - + // Setup pixel buffer to hold uncompressed data. uint32 pixelType = ttUndefined; diff --git a/source/dng_render.cpp b/source/dng_render.cpp index e3d9940..44ed445 100644 --- a/source/dng_render.cpp +++ b/source/dng_render.cpp @@ -45,7 +45,7 @@ dng_function_exposure_ramp::dng_function_exposure_ramp (real64 white, { ThrowBadFormat (); } - + const real64 kMaxCurveX = 0.5; // Fraction of minBlack. const real64 kMaxCurveY = 1.0 / 16.0; // Fraction of white. diff --git a/source/dng_resample.cpp b/source/dng_resample.cpp index 5bb05d9..66bd002 100644 --- a/source/dng_resample.cpp +++ b/source/dng_resample.cpp @@ -310,7 +310,7 @@ dng_resample_weights_2d::~dng_resample_weights_2d () void dng_resample_weights_2d::Initialize (const dng_resample_function &kernel, dng_memory_allocator &allocator) { - + // Find radius of this kernel. Unlike with 1d resample weights (see // dng_resample_weights), we never scale up the kernel size. @@ -326,12 +326,12 @@ void dng_resample_weights_2d::Initialize (const dng_resample_function &kernel, !SafeUint32Mult (width, width, &widthSqr) || !RoundUpUint32ToMultiple (widthSqr, 8, &step) || !SafeUint32Mult (step, kResampleSubsampleCount2D, &fRowStep)) - { - - ThrowMemoryFull ("Arithmetic overflow computing row step."); + { + + ThrowMemoryFull ("Arithmetic overflow computing row step."); + + } - } - fColStep = step; // Allocate and zero weight tables. @@ -354,13 +354,13 @@ void dng_resample_weights_2d::Initialize (const dng_resample_function &kernel, if (!SafeUint32Mult (step, kResampleSubsampleCount2D, &bufferSize) || - !SafeUint32Mult (bufferSize, kResampleSubsampleCount2D, &bufferSize) || - !SafeUint32Mult (bufferSize, (uint32) sizeof (int16), &bufferSize)) - { - - ThrowMemoryFull ("Arithmetic overflow computing buffer size."); - - } + !SafeUint32Mult (bufferSize, kResampleSubsampleCount2D, &bufferSize) || + !SafeUint32Mult (bufferSize, (uint32) sizeof (int16), &bufferSize)) + { + + ThrowMemoryFull ("Arithmetic overflow computing buffer size."); + + } fWeights16.Reset (allocator.Allocate (bufferSize)); @@ -557,7 +557,7 @@ dng_resample_task::dng_resample_task (const dng_image &srcImage, if (fRowScale == 0 || fColScale == 0) { ThrowBadFormat (); - } + } if (srcImage.PixelSize () <= 2 && dstImage.PixelSize () <= 2 && @@ -587,11 +587,6 @@ dng_resample_task::dng_resample_task (const dng_image &srcImage, /*****************************************************************************/ -#if defined(__clang__) && defined(__has_attribute) -#if __has_attribute(no_sanitize) -__attribute__((no_sanitize("unsigned-integer-overflow"))) -#endif -#endif dng_rect dng_resample_task::SrcArea (const dng_rect &dstArea) { @@ -603,11 +598,17 @@ dng_rect dng_resample_task::SrcArea (const dng_rect &dstArea) dng_rect srcArea; - srcArea.t = fRowCoords.Pixel (dstArea.t) + offsetV; - srcArea.l = fColCoords.Pixel (dstArea.l) + offsetH; + srcArea.t = SafeInt32Add (fRowCoords.Pixel (dstArea.t), offsetV); + srcArea.l = SafeInt32Add (fColCoords.Pixel (dstArea.l), offsetH); - srcArea.b = fRowCoords.Pixel (dstArea.b - 1) + offsetV + widthV; - srcArea.r = fColCoords.Pixel (dstArea.r - 1) + offsetH + widthH; + srcArea.b = SafeInt32Add (SafeInt32Add ( + fRowCoords.Pixel (SafeInt32Sub (dstArea.b, 1)), + offsetV), + ConvertUint32ToInt32 (widthV));; + srcArea.r = SafeInt32Add(SafeInt32Add( + fColCoords.Pixel (SafeInt32Sub (dstArea.r, 1)), + offsetH), + ConvertUint32ToInt32(widthH));; return srcArea; @@ -629,6 +630,7 @@ void dng_resample_task::Start (uint32 threadCount, dng_memory_allocator *allocator, dng_abort_sniffer *sniffer) { + // Compute sub-pixel resolution coordinates in the source image for // each row and column of the destination area. diff --git a/source/dng_resample.h b/source/dng_resample.h index 9116e6e..9ad13dd 100644 --- a/source/dng_resample.h +++ b/source/dng_resample.h @@ -250,7 +250,7 @@ class dng_resample_weights_2d } const uint32 offset = fract.v * fRowStep + fract.h * fColStep; - + return fWeights32->Buffer_real32 () + offset; } diff --git a/source/dng_safe_arithmetic.cpp b/source/dng_safe_arithmetic.cpp index 1a4f543..9d3d51d 100644 --- a/source/dng_safe_arithmetic.cpp +++ b/source/dng_safe_arithmetic.cpp @@ -33,9 +33,7 @@ T SafeAdd(T arg1, T arg2) { return arg1 + arg2; } else { ThrowProgramError("Arithmetic overflow"); - - // Dummy return statement. - return 0; + abort(); // Never reached. } } @@ -48,9 +46,7 @@ T SafeUnsignedMult(T arg1, T arg2) { return arg1 * arg2; } else { ThrowProgramError("Arithmetic overflow"); - - // Dummy return statement. - return 0; + abort(); // Never reached. } } @@ -87,6 +83,10 @@ std::uint32_t SafeUint32Add(std::uint32_t arg1, std::uint32_t arg2) { return SafeAdd<std::uint32_t>(arg1, arg2); } +std::uint64_t SafeUint64Add(std::uint64_t arg1, std::uint64_t arg2) { + return SafeAdd<std::uint64_t>(arg1, arg2); +} + bool SafeInt32Sub(std::int32_t arg1, std::int32_t arg2, std::int32_t *result) { if ((arg2 >= 0 && arg1 >= std::numeric_limits<int32_t>::min() + arg2) || (arg2 < 0 && arg1 <= std::numeric_limits<int32_t>::max() + arg2)) { @@ -107,6 +107,15 @@ std::int32_t SafeInt32Sub(std::int32_t arg1, std::int32_t arg2) { return result; } +std::uint32_t SafeUint32Sub(std::uint32_t arg1, std::uint32_t arg2) { + if (arg1 >= arg2) { + return arg1 - arg2; + } else { + ThrowProgramError("Arithmetic overflow"); + abort(); // Never reached. + } +} + bool SafeUint32Mult(std::uint32_t arg1, std::uint32_t arg2, std::uint32_t *result) { try { @@ -151,11 +160,24 @@ std::uint32_t SafeUint32Mult(std::uint32_t arg1, std::uint32_t arg2, return SafeUint32Mult(SafeUint32Mult(arg1, arg2, arg3), arg4); } +std::int32_t SafeInt32Mult(std::int32_t arg1, std::int32_t arg2) { + const std::int64_t tmp = + static_cast<std::int64_t>(arg1) * static_cast<std::int64_t>(arg2); + if (tmp >= INT32_MIN && tmp <= INT32_MAX) { + return static_cast<std::int32_t>(tmp); + } else { + ThrowProgramError("Arithmetic overflow"); + abort(); + } +} + std::size_t SafeSizetMult(std::size_t arg1, std::size_t arg2) { return SafeUnsignedMult<std::size_t>(arg1, arg2); } -std::int64_t SafeInt64Mult(std::int64_t arg1, std::int64_t arg2) { +namespace dng_internal { + +std::int64_t SafeInt64MultSlow(std::int64_t arg1, std::int64_t arg2) { bool overflow = true; if (arg1 > 0) { @@ -174,14 +196,14 @@ std::int64_t SafeInt64Mult(std::int64_t arg1, std::int64_t arg2) { if (overflow) { ThrowProgramError("Arithmetic overflow"); - - // Dummy return. - return 0; + abort(); // Never reached. } else { return arg1 * arg2; } } +} // namespace dng_internal + std::uint32_t SafeUint32DivideUp(std::uint32_t arg1, std::uint32_t arg2) { // It might seem more intuitive to implement this function simply as // @@ -191,9 +213,7 @@ std::uint32_t SafeUint32DivideUp(std::uint32_t arg1, std::uint32_t arg2) { if (arg2 == 0) { ThrowProgramError("Division by zero"); - - // Dummy return to avoid compiler error about missing return statement. - return 0; + abort(); // Never reached. } else if (arg1 == 0) { // If arg1 is zero, return zero to avoid wraparound in the expression // "arg1 - 1" below. @@ -205,27 +225,57 @@ std::uint32_t SafeUint32DivideUp(std::uint32_t arg1, std::uint32_t arg2) { bool RoundUpUint32ToMultiple(std::uint32_t val, std::uint32_t multiple_of, std::uint32_t *result) { - if (multiple_of == 0) { + try { + *result = RoundUpUint32ToMultiple(val, multiple_of); + return true; + } catch (const dng_exception &) { return false; } +} + +std::uint32_t RoundUpUint32ToMultiple(std::uint32_t val, + std::uint32_t multiple_of) { + if (multiple_of == 0) { + ThrowProgramError("multiple_of is zero in RoundUpUint32ToMultiple"); + } const std::uint32_t remainder = val % multiple_of; if (remainder == 0) { - *result = val; - return true; + return val; } else { - return SafeUint32Add(val, multiple_of - remainder, result); + return SafeUint32Add(val, multiple_of - remainder); } } bool ConvertUint32ToInt32(std::uint32_t val, std::int32_t *result) { + try { + *result = ConvertUint32ToInt32(val); + return true; + } catch (const dng_exception &) { + return false; + } +} + +std::int32_t ConvertUint32ToInt32(std::uint32_t val) { const std::uint32_t kInt32MaxAsUint32 = static_cast<std::uint32_t>(std::numeric_limits<std::int32_t>::max()); if (val <= kInt32MaxAsUint32) { - *result = static_cast<std::int32_t>(val); - return true; + return static_cast<std::int32_t>(val); } else { - return false; + ThrowProgramError("Arithmetic overflow"); + abort(); // Never reached. + } +} + +std::int32_t ConvertDoubleToInt32(double val) { + constexpr double kMin = static_cast<double>(INT32_MIN); + constexpr double kMax = static_cast<double>(INT32_MAX); + // NaNs will fail this test; they always compare false. + if (val > kMin - 1.0 && val < kMax + 1.0) { + return static_cast<std::int32_t>(val); + } else { + ThrowProgramError("Argument not in range in ConvertDoubleToInt32"); + abort(); // Never reached. } } diff --git a/source/dng_safe_arithmetic.h b/source/dng_safe_arithmetic.h index 31c2176..78d8ae0 100644 --- a/source/dng_safe_arithmetic.h +++ b/source/dng_safe_arithmetic.h @@ -26,6 +26,14 @@ #include "dng_exceptions.h" +#ifndef __has_builtin +#define __has_builtin(x) 0 // Compatibility with non-Clang compilers. +#endif + +#if !defined(DNG_HAS_INT128) && defined(__SIZEOF_INT128__) +#define DNG_HAS_INT128 +#endif + // If the result of adding arg1 and arg2 will fit in an int32_t (without // under-/overflow), stores this result in *result and returns true. Otherwise, // returns false and leaves *result unchanged. @@ -43,10 +51,11 @@ std::int64_t SafeInt64Add(std::int64_t arg1, std::int64_t arg2); bool SafeUint32Add(std::uint32_t arg1, std::uint32_t arg2, std::uint32_t *result); -// Returns the result of adding arg1 and arg2 if it will fit in a uint32_t +// Returns the result of adding arg1 and arg2 if it will fit in the result type // (without wraparound). Otherwise, throws a dng_exception with error code // dng_error_unknown. std::uint32_t SafeUint32Add(std::uint32_t arg1, std::uint32_t arg2); +std::uint64_t SafeUint64Add(std::uint64_t arg1, std::uint64_t arg2); // If the subtraction of arg2 from arg1 will not result in an int32_t under- or // overflow, stores this result in *result and returns true. Otherwise, @@ -58,6 +67,16 @@ bool SafeInt32Sub(std::int32_t arg1, std::int32_t arg2, std::int32_t *result); // with error code dng_error_unknown. std::int32_t SafeInt32Sub(std::int32_t arg1, std::int32_t arg2); +// Returns the result of subtracting arg2 from arg1 if this operation will not +// result in wraparound. Otherwise, throws a dng_exception with error code +// dng_error_unknown. +std::uint32_t SafeUint32Sub(std::uint32_t arg1, std::uint32_t arg2); + +// Returns the result of multiplying arg1 and arg2 if it will fit in a int32_t +// (without overflow). Otherwise, throws a dng_exception with error code +// dng_error_unknown. +std::int32_t SafeInt32Mult(std::int32_t arg1, std::int32_t arg2); + // If the result of multiplying arg1, ..., argn will fit in a uint32_t (without // wraparound), stores this result in *result and returns true. Otherwise, // returns false and leaves *result unchanged. @@ -82,10 +101,57 @@ std::uint32_t SafeUint32Mult(std::uint32_t arg1, std::uint32_t arg2, // dng_error_unknown. std::size_t SafeSizetMult(std::size_t arg1, std::size_t arg2); +namespace dng_internal { + +// Internal function used as fallback for SafeInt64Mult() if other optimized +// computation is not supported. Don't call this function directly. +std::int64_t SafeInt64MultSlow(std::int64_t arg1, std::int64_t arg2); + +// Internal function used as optimization for SafeInt64Mult() if Clang +// __builtin_smull_overflow is supported. Don't call this function directly. +#if __has_builtin(__builtin_smull_overflow) +inline std::int64_t SafeInt64MultByClang(std::int64_t arg1, std::int64_t arg2) { + std::int64_t result; +#if (__WORDSIZE == 64) && !defined(__APPLE__) + if (__builtin_smull_overflow(arg1, arg2, &result)) { +#else + if (__builtin_smulll_overflow(arg1, arg2, &result)) { +#endif + ThrowProgramError("Arithmetic overflow"); + abort(); // Never reached. + } + return result; +} +#endif + +// Internal function used as optimization for SafeInt64Mult() if __int128 type +// is supported. Don't call this function directly. +#ifdef DNG_HAS_INT128 +inline std::int64_t SafeInt64MultByInt128(std::int64_t arg1, + std::int64_t arg2) { + __int128 result = static_cast<__int128>(arg1) * static_cast<__int128>(arg2); + if (result > static_cast<__int128>(INT64_MAX) || + result < static_cast<__int128>(INT64_MIN)) { + ThrowProgramError("Arithmetic overflow"); + } + return static_cast<std::int64_t>(result); +} +#endif + +} // namespace dng_internal + // Returns the result of multiplying arg1 and arg2 if it will fit in an int64_t // (without overflow). Otherwise, throws a dng_exception with error code // dng_error_unknown. -std::int64_t SafeInt64Mult(std::int64_t arg1, std::int64_t arg2); +inline std::int64_t SafeInt64Mult(std::int64_t arg1, std::int64_t arg2) { +#if __has_builtin(__builtin_smull_overflow) + return dng_internal::SafeInt64MultByClang(arg1, arg2); +#elif defined(DNG_HAS_INT128) + return dng_internal::SafeInt64MultByInt128(arg1, arg2); +#else + return dng_internal::SafeInt64MultSlow(arg1, arg2); +#endif +} // Returns the result of dividing arg1 by arg2; if the result is not an integer, // rounds up to the next integer. If arg2 is zero, throws a dng_exception with @@ -101,10 +167,22 @@ std::uint32_t SafeUint32DivideUp(std::uint32_t arg1, std::uint32_t arg2); bool RoundUpUint32ToMultiple(std::uint32_t val, std::uint32_t multiple_of, std::uint32_t *result); +// Returns the smallest integer multiple of 'multiple_of' that is greater than +// or equal to 'val'. If the result will not fit in a std::uint32_t or if +// 'multiple_of' is zero, throws a dng_exception with error code +// dng_error_unknown. +std::uint32_t RoundUpUint32ToMultiple(std::uint32_t val, + std::uint32_t multiple_of); + // If the uint32_t value val will fit in a int32_t, converts it to a int32_t and // stores it in *result. Otherwise, returns false and leaves *result unchanged. bool ConvertUint32ToInt32(std::uint32_t val, std::int32_t *result); +// Returns the result of converting val to an int32_t if it can be converted +// without overflow. Otherwise, throws a dng_exception with error code +// dng_error_unknown. +std::int32_t ConvertUint32ToInt32(std::uint32_t val); + // Converts a value of the unsigned integer type TSrc to the unsigned integer // type TDest. If the value in 'src' cannot be converted to the type TDest // without truncation, throws a dng_exception with error code dng_error_unknown. @@ -135,4 +213,9 @@ static void ConvertUnsigned(TSrc src, TDest *dest) { *dest = converted; } +// Returns the result of converting val to an int32_t using truncation if val is +// in range of int32_t values. Otherwise, throws a dng_exception with error code +// dng_error_unknown. +std::int32_t ConvertDoubleToInt32(double val); + #endif // __dng_safe_arithmetic__ diff --git a/source/dng_shared.cpp b/source/dng_shared.cpp index 5384116..961ac1f 100644 --- a/source/dng_shared.cpp +++ b/source/dng_shared.cpp @@ -20,6 +20,7 @@ #include "dng_globals.h" #include "dng_memory.h" #include "dng_parse_utils.h" +#include "dng_safe_arithmetic.h" #include "dng_tag_codes.h" #include "dng_tag_types.h" #include "dng_tag_values.h" @@ -96,11 +97,6 @@ dng_camera_profile_info::~dng_camera_profile_info () /*****************************************************************************/ -#if defined(__clang__) && defined(__has_attribute) -#if __has_attribute(no_sanitize) -__attribute__((no_sanitize("unsigned-integer-overflow"))) -#endif -#endif bool dng_camera_profile_info::ParseTag (dng_stream &stream, uint32 parentCode, uint32 tagCode, @@ -588,9 +584,11 @@ bool dng_camera_profile_info::ParseTag (dng_stream &stream, if (!CheckTagType (parentCode, tagCode, tagType, ttFloat)) return false; - bool skipSat0 = (tagCount == fProfileHues * - (fProfileSats - 1) * - fProfileVals * 3); + bool skipSat0 = (tagCount == + SafeUint32Mult(fProfileHues, + SafeUint32Sub(fProfileSats, 1u), + fProfileVals, + 3u)); if (!skipSat0) { @@ -634,9 +632,11 @@ bool dng_camera_profile_info::ParseTag (dng_stream &stream, if (!CheckTagType (parentCode, tagCode, tagType, ttFloat)) return false; - bool skipSat0 = (tagCount == fProfileHues * - (fProfileSats - 1) * - fProfileVals * 3); + bool skipSat0 = (tagCount == + SafeUint32Mult(fProfileHues, + SafeUint32Sub(fProfileSats, 1u), + fProfileVals, + 3u)); if (!skipSat0) { @@ -755,9 +755,11 @@ bool dng_camera_profile_info::ParseTag (dng_stream &stream, if (!CheckTagType (parentCode, tagCode, tagType, ttFloat)) return false; - bool skipSat0 = (tagCount == fLookTableHues * - (fLookTableSats - 1) * - fLookTableVals * 3); + bool skipSat0 = (tagCount == + SafeUint32Mult(fLookTableHues, + SafeUint32Sub(fLookTableSats, 1u), + fLookTableVals, + 3u)); if (!skipSat0) { @@ -1028,11 +1030,6 @@ bool dng_camera_profile_info::ParseTag (dng_stream &stream, /*****************************************************************************/ -#if defined(__clang__) && defined(__has_attribute) -#if __has_attribute(no_sanitize) -__attribute__((no_sanitize("unsigned-integer-overflow"))) -#endif -#endif bool dng_camera_profile_info::ParseExtended (dng_stream &stream) { @@ -1069,7 +1066,7 @@ bool dng_camera_profile_info::ParseExtended (dng_stream &stream) uint32 offset = stream.Get_uint32 (); - stream.Skip (offset - 8); + stream.Skip (SafeUint32Sub(offset, 8u)); // Start on IFD entries. @@ -1091,7 +1088,7 @@ bool dng_camera_profile_info::ParseExtended (dng_stream &stream) uint64 tagOffset = stream.Position (); - if (TagTypeSize (tagType) * tagCount > 4) + if (SafeUint32Mult(TagTypeSize (tagType), tagCount) > 4) { tagOffset = startPosition + stream.Get_uint32 (); @@ -1353,7 +1350,8 @@ bool dng_shared::Parse_ifd0 (dng_stream &stream, CheckTagType (parentCode, tagCode, tagType, ttLong, ttAscii, ttUndefined); - fIPTC_NAA_Count = SafeUint32Mult(tagCount, TagTypeSize(tagType)); + fIPTC_NAA_Count = SafeUint32Mult(tagCount, + TagTypeSize(tagType)); fIPTC_NAA_Offset = fIPTC_NAA_Count ? tagOffset : 0; #if qDNGValidate diff --git a/source/dng_simple_image.cpp b/source/dng_simple_image.cpp index 46d0011..ac8e1dc 100644 --- a/source/dng_simple_image.cpp +++ b/source/dng_simple_image.cpp @@ -182,3 +182,4 @@ void dng_simple_image::AcquireTileBuffer (dng_tile_buffer &buffer, } /*****************************************************************************/ + diff --git a/source/dng_string.cpp b/source/dng_string.cpp index af8514d..60e7d74 100644 --- a/source/dng_string.cpp +++ b/source/dng_string.cpp @@ -86,6 +86,11 @@ static void CheckSpaceLeftInBuffer(const T *currentPos, // to the following Mac-OS- and Windows-specific functions. Calls to // ThrowNotHardened() have been added to these functions to alert callers of // this fact. +// +// If you're trying to use a function that calls ThrowNotHardened(), you need to +// fix the security issues noted in the comment next to the ThrowNotHardened() +// call. Once you have fixed these issues, obtain a security review for the +// fixes. This may require fuzzing of the modified code on the target platform. static void ThrowNotHardened() { ThrowProgramError ("This function has not been security-hardened"); @@ -97,6 +102,7 @@ static void ThrowNotHardened() static uint32 Extract_SystemEncoding (const dng_string &dngString, dng_memory_data &buffer) { + // TODO: Needs implementation. ThrowProgramError ("Extract_SystemEncoding() not implemented on iOS"); return 0; } @@ -104,6 +110,7 @@ static uint32 Extract_SystemEncoding (const dng_string &dngString, static void Assign_SystemEncoding (dng_string &dngString, const char *otherString) { + // TODO: Needs implementation. ThrowProgramError ("Assign_SystemEncoding() not implemented on iOS"); } @@ -111,6 +118,7 @@ static void Assign_SystemEncoding (dng_string &dngString, static void Assign_JIS_X208_1990 (dng_string &dngString, const char *otherString) { + // TODO: Needs implementation. ThrowProgramError ("Assign_JIS_X208_1990() not implemented on iOS"); } @@ -128,7 +136,7 @@ static void Assign_Multibyte (dng_string &dngString, // - The computation of aBufSize and the subsequent addition of 1 in the // call to the dng_memory_data constructor may wrap around. ThrowNotHardened(); - + uint32 aSize = (uint32) strlen (otherString); if (aSize > 0) @@ -901,11 +909,6 @@ void dng_string::Set_JIS_X208_1990 (const char *s) /*****************************************************************************/ -#if defined(__clang__) && defined(__has_attribute) -#if __has_attribute(no_sanitize) -__attribute__((no_sanitize("unsigned-integer-overflow"))) -#endif -#endif uint32 dng_string::DecodeUTF8 (const char *&s, uint32 maxBytes, bool *isValid) @@ -920,7 +923,7 @@ uint32 dng_string::DecodeUTF8 (const char *&s, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,6,6,6,6 + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,6,6,0,0 }; if (isValid) @@ -2182,6 +2185,7 @@ int32 dng_string::Compare (const dng_string &s) const #if qMacOS #if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR + // TODO: Needs implementation. ThrowProgramError ("Compare() not implemented on iOS"); return 0; @@ -2272,6 +2276,7 @@ int32 dng_string::Compare (const dng_string &s) const } #endif // TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR + #elif qWinOS { diff --git a/source/dng_types.h b/source/dng_types.h index f59771d..2baeb4e 100644 --- a/source/dng_types.h +++ b/source/dng_types.h @@ -32,7 +32,11 @@ /*****************************************************************************/ -#if qDNGUseStdInt || 1 +#if qDNGUseCustomIntegralTypes + +#include "dng_custom_integral_types.h" + +#elif qDNGUseStdInt || 1 typedef int8_t int8; typedef int16_t int16; diff --git a/source/dng_utils.cpp b/source/dng_utils.cpp index daf85f5..bf129c1 100644 --- a/source/dng_utils.cpp +++ b/source/dng_utils.cpp @@ -171,6 +171,7 @@ uint32 ComputeBufferSize(uint32 pixelType, const dng_point &tileSize, uint32 numPlanes, PaddingType paddingType) { + // Convert tile size to uint32. if (tileSize.h < 0 || tileSize.v < 0) { @@ -311,7 +312,7 @@ real64 TickCountInSeconds () // TODO: Needs implementation. ThrowProgramError ("TickCountInSeconds() not implemented on iOS"); return 0; - #else + #else return TickCount () * (1.0 / 60.0); #endif // TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR diff --git a/source/dng_utils.h b/source/dng_utils.h index 218831d..d945a6e 100644 --- a/source/dng_utils.h +++ b/source/dng_utils.h @@ -225,7 +225,7 @@ inline bool RoundUpForPixelSize (uint32 x, uint32 pixelSize, uint32 *result) default: multiple = 16; break; - + } return RoundUpUint32ToMultiple(x, multiple, result); @@ -467,11 +467,6 @@ inline real64 Lerp_real64 (real64 a, real64 b, real64 t) /*****************************************************************************/ -#if defined(__clang__) && defined(__has_attribute) -#if __has_attribute(no_sanitize) -__attribute__((no_sanitize("float-cast-overflow"))) -#endif -#endif inline int32 Round_int32 (real32 x) { @@ -482,7 +477,21 @@ inline int32 Round_int32 (real32 x) inline int32 Round_int32 (real64 x) { - return (int32) (x > 0.0 ? x + 0.5 : x - 0.5); + const real64 temp = x > 0.0 ? x + 0.5 : x - 0.5; + + // NaNs will fail this test (because NaNs compare false against + // everything) and will therefore also take the else branch. + if (temp > real64(INT32_MIN) - 1.0 && temp < real64(INT32_MAX) + 1.0) + { + return (int32) temp; + } + + else + { + ThrowProgramError("Overflow in Round_int32"); + // Dummy return. + return 0; + } } @@ -493,15 +502,24 @@ inline uint32 Floor_uint32 (real32 x) } -#if defined(__clang__) && defined(__has_attribute) -#if __has_attribute(no_sanitize) -__attribute__((no_sanitize("float-cast-overflow"))) -#endif -#endif inline uint32 Floor_uint32 (real64 x) { - return (uint32) Max_real64 (0.0, x); + const real64 temp = Max_real64 (0.0, x); + + // NaNs will fail this test (because NaNs compare false against + // everything) and will therefore also take the else branch. + if (temp < real64(UINT32_MAX) + 1.0) + { + return (uint32) temp; + } + + else + { + ThrowProgramError("Overflow in Floor_uint32"); + // Dummy return. + return 0; + } } @@ -1146,7 +1164,8 @@ inline int32 Mulsh86 (int32 x, int32 y) // This is the ACM standard 30 bit generator: // x' = (x * 16807) mod 2^31-1 - +// This function intentionally exploits the defined behavior of unsigned integer +// overflow. #if defined(__clang__) && defined(__has_attribute) #if __has_attribute(no_sanitize) __attribute__((no_sanitize("unsigned-integer-overflow"))) |