diff options
| author | Nikita Popov <nikita.ppv@gmail.com> | 2020-06-12 12:52:39 +0200 |
|---|---|---|
| committer | Nikita Popov <nikita.ppv@gmail.com> | 2020-06-12 12:54:41 +0200 |
| commit | 4f9a1122e11ebd0052ce7ae27222e0fa6af39713 (patch) | |
| tree | 3d77830bbb262020abb7be08677c48c3ebafbc65 /ext/exif | |
| parent | bf4f3ddb2f0df1dd33d4764ccba6566bc676ed4b (diff) | |
| download | php-git-4f9a1122e11ebd0052ce7ae27222e0fa6af39713.tar.gz | |
Avoid out of range float to int cast in exif
Use convert_any_int instead of convert_any_format to directly get
an integer.
Also adjust SRATIONAL handling to not go through a double division.
This was introduced to avoid SIGFPE for the INT_MIN / -1 case,
but we can just handle that explicitly.
Diffstat (limited to 'ext/exif')
| -rw-r--r-- | ext/exif/exif.c | 22 |
1 files changed, 12 insertions, 10 deletions
diff --git a/ext/exif/exif.c b/ext/exif/exif.c index 5b77e518d6..72ad308d18 100644 --- a/ext/exif/exif.c +++ b/ext/exif/exif.c @@ -1710,31 +1710,33 @@ static size_t double_to_size_t(double x) { * Evaluate number, be it int, rational, or float from directory. */ static size_t exif_convert_any_to_int(void *value, int format, int motorola_intel) { - int s_den; - unsigned u_den; - - switch(format) { + switch (format) { case TAG_FMT_SBYTE: return *(signed char *)value; case TAG_FMT_BYTE: return *(uchar *)value; case TAG_FMT_USHORT: return php_ifd_get16u(value, motorola_intel); case TAG_FMT_ULONG: return php_ifd_get32u(value, motorola_intel); - case TAG_FMT_URATIONAL: - u_den = php_ifd_get32u(4+(char *)value, motorola_intel); + case TAG_FMT_URATIONAL: { + unsigned u_den = php_ifd_get32u(4+(char *)value, motorola_intel); if (u_den == 0) { return 0; } else { return php_ifd_get32u(value, motorola_intel) / u_den; } + } - case TAG_FMT_SRATIONAL: - s_den = php_ifd_get32s(4+(char *)value, motorola_intel); + case TAG_FMT_SRATIONAL: { + int s_num = php_ifd_get32s(value, motorola_intel); + int s_den = php_ifd_get32s(4+(char *)value, motorola_intel); if (s_den == 0) { return 0; + } else if (s_num == INT_MIN && s_den == -1) { + return INT_MAX; } else { - return (size_t)((double)php_ifd_get32s(value, motorola_intel) / s_den); + return s_num / s_den; } + } case TAG_FMT_SSHORT: return php_ifd_get16u(value, motorola_intel); case TAG_FMT_SLONG: return php_ifd_get32s(value, motorola_intel); @@ -3473,7 +3475,7 @@ static int exif_process_IFD_TAG(image_info_type *ImageInfo, char *dir_entry, con case TAG_FOCALPLANE_RESOLUTION_UNIT: REQUIRE_NON_EMPTY(); - switch((int)exif_convert_any_format(value_ptr, format, ImageInfo->motorola_intel)) { + switch (exif_convert_any_to_int(value_ptr, format, ImageInfo->motorola_intel)) { case 1: ImageInfo->FocalplaneUnits = 25.4; break; /* inch */ case 2: /* According to the information I was using, 2 measn meters. |
