DO NOT MERGE
Update GIFLIB to 5.1.4 DO NOT MERGE

Bug:34697653

Remove files that are unused by Android.

Also include <limits.h> in openbsd-reallocarray.c, which is where
Android defines SIZE_MAX.

Preserve Android modification in egif_lib.c, which changed
"S_IREAD | S_IWRITE" to "S_IRUSR | S_IWUSR"

Change-Id: I75c0de5c0a8ad4790f43afe400a611d3ba5ccf57
(cherry picked from commit 7bdef2629b585e4f49aa0f8301f2ee5ab3558607)
diff --git a/Android.mk b/Android.mk
index 427c1ee..79b52e9 100644
--- a/Android.mk
+++ b/Android.mk
@@ -9,6 +9,7 @@
 	gifalloc.c \
 	gif_err.c \
 	gif_hash.c \
+	openbsd-reallocarray.c \
 	quantize.c
 
 LOCAL_CFLAGS += -Wno-format -Wno-sign-compare -Wno-unused-parameter -DHAVE_CONFIG_H
diff --git a/dgif_lib.c b/dgif_lib.c
index 744a2f9..66a1d6a 100644
--- a/dgif_lib.c
+++ b/dgif_lib.c
@@ -59,7 +59,6 @@
     }
 
     GifFile = DGifOpenFileHandle(FileHandle, Error);
-    // cppcheck-suppress resourceLeak
     return GifFile;
 }
 
@@ -90,7 +89,7 @@
     GifFile->SavedImages = NULL;
     GifFile->SColorMap = NULL;
 
-    Private = (GifFilePrivateType *)malloc(sizeof(GifFilePrivateType));
+    Private = (GifFilePrivateType *)calloc(1, sizeof(GifFilePrivateType));
     if (Private == NULL) {
         if (Error != NULL)
 	    *Error = D_GIF_ERR_NOT_ENOUGH_MEM;
@@ -98,6 +97,9 @@
         free((char *)GifFile);
         return NULL;
     }
+
+    /*@i1@*/memset(Private, '\0', sizeof(GifFilePrivateType));
+
 #ifdef _WIN32
     _setmode(FileHandle, O_BINARY);    /* Make sure it is in binary mode. */
 #endif /* _WIN32 */
@@ -114,6 +116,7 @@
     /*@=mustfreeonly@*/
 
     /* Let's see if this is a GIF file: */
+    /* coverity[check_return] */
     if (READ(GifFile, (unsigned char *)Buf, GIF_STAMP_LEN) != GIF_STAMP_LEN) {
         if (Error != NULL)
 	    *Error = D_GIF_ERR_READ_FAILED;
@@ -172,13 +175,14 @@
     GifFile->SavedImages = NULL;
     GifFile->SColorMap = NULL;
 
-    Private = (GifFilePrivateType *)malloc(sizeof(GifFilePrivateType));
+    Private = (GifFilePrivateType *)calloc(1, sizeof(GifFilePrivateType));
     if (!Private) {
         if (Error != NULL)
 	    *Error = D_GIF_ERR_NOT_ENOUGH_MEM;
         free((char *)GifFile);
         return NULL;
     }
+    /*@i1@*/memset(Private, '\0', sizeof(GifFilePrivateType));
 
     GifFile->Private = (void *)Private;
     Private->FileHandle = 0;
@@ -189,6 +193,7 @@
     GifFile->UserData = userData;    /* TVT */
 
     /* Lets see if this is a GIF file: */
+    /* coverity[check_return] */
     if (READ(GifFile, (unsigned char *)Buf, GIF_STAMP_LEN) != GIF_STAMP_LEN) {
         if (Error != NULL)
 	    *Error = D_GIF_ERR_READ_FAILED;
@@ -210,6 +215,8 @@
     if (DGifGetScreenDesc(GifFile) == GIF_ERROR) {
         free((char *)Private);
         free((char *)GifFile);
+        if (Error != NULL)
+	    *Error = D_GIF_ERR_NO_SCRN_DSCR;
         return NULL;
     }
 
@@ -267,6 +274,7 @@
         /* Get the global color map: */
 	GifFile->SColorMap->SortFlag = SortFlag;
         for (i = 0; i < GifFile->SColorMap->ColorCount; i++) {
+	    /* coverity[check_return] */
             if (READ(GifFile, Buf, 3) != 3) {
                 GifFreeMapObject(GifFile->SColorMap);
                 GifFile->SColorMap = NULL;
@@ -299,6 +307,7 @@
         return GIF_ERROR;
     }
 
+    /* coverity[check_return] */
     if (READ(GifFile, &Buf, 1) != 1) {
         GifFile->Error = D_GIF_ERR_READ_FAILED;
         return GIF_ERROR;
@@ -372,6 +381,7 @@
 
         /* Get the image local color map: */
         for (i = 0; i < GifFile->Image.ColorMap->ColorCount; i++) {
+	    /* coverity[check_return] */
             if (READ(GifFile, Buf, 3) != 3) {
                 GifFreeMapObject(GifFile->Image.ColorMap);
                 GifFile->Error = D_GIF_ERR_READ_FAILED;
@@ -385,12 +395,14 @@
     }
 
     if (GifFile->SavedImages) {
-        if ((GifFile->SavedImages = (SavedImage *)realloc(GifFile->SavedImages,
-                                      sizeof(SavedImage) *
-                                      (GifFile->ImageCount + 1))) == NULL) {
+        SavedImage* new_saved_images =
+            (SavedImage *)reallocarray(GifFile->SavedImages,
+                            (GifFile->ImageCount + 1), sizeof(SavedImage));
+        if (new_saved_images == NULL) {
             GifFile->Error = D_GIF_ERR_NOT_ENOUGH_MEM;
             return GIF_ERROR;
         }
+        GifFile->SavedImages = new_saved_images;
     } else {
         if ((GifFile->SavedImages =
              (SavedImage *) malloc(sizeof(SavedImage))) == NULL) {
@@ -420,9 +432,7 @@
        (long)GifFile->Image.Height;
 
     /* Reset decompress algorithm parameters. */
-    (void)DGifSetupDecompress(GifFile);
-
-    return GIF_OK;
+    return DGifSetupDecompress(GifFile);
 }
 
 /******************************************************************************
@@ -521,6 +531,7 @@
         return GIF_ERROR;
     }
 
+    /* coverity[check_return] */
     if (READ(GifFile, &Buf, 1) != 1) {
         GifFile->Error = D_GIF_ERR_READ_FAILED;
         return GIF_ERROR;
@@ -548,7 +559,7 @@
     if (Buf > 0) {
         *Extension = Private->Buf;    /* Use private unused buffer. */
         (*Extension)[0] = Buf;  /* Pascal strings notation (pos. 0 is len.). */
-	/* coverity[tainted_data] */
+	/* coverity[tainted_data,check_return] */
         if (READ(GifFile, &((*Extension)[1]), Buf) != Buf) {
             GifFile->Error = D_GIF_ERR_READ_FAILED;
             return GIF_ERROR;
@@ -612,7 +623,7 @@
  This routine should be called last, to close the GIF file.
 ******************************************************************************/
 int
-DGifCloseFile(GifFileType *GifFile)
+DGifCloseFile(GifFileType *GifFile, int *ErrorCode)
 {
     GifFilePrivateType *Private;
 
@@ -640,25 +651,25 @@
 
     if (!IS_READABLE(Private)) {
         /* This file was NOT open for reading: */
-        GifFile->Error = D_GIF_ERR_NOT_READABLE;
+	if (ErrorCode != NULL)
+	    *ErrorCode = D_GIF_ERR_NOT_READABLE;
+	free((char *)GifFile->Private);
+	free(GifFile);
         return GIF_ERROR;
     }
 
     if (Private->File && (fclose(Private->File) != 0)) {
-        GifFile->Error = D_GIF_ERR_CLOSE_FAILED;
+	if (ErrorCode != NULL)
+	    *ErrorCode = D_GIF_ERR_CLOSE_FAILED;
+	free((char *)GifFile->Private);
+	free(GifFile);
         return GIF_ERROR;
     }
 
     free((char *)GifFile->Private);
-
-    /* 
-     * Without the #ifndef, we get spurious warnings because Coverity mistakenly
-     * thinks the GIF structure is freed on an error return. 
-     */
-#ifndef __COVERITY__
     free(GifFile);
-#endif /* __COVERITY__ */
-
+    if (ErrorCode != NULL)
+	*ErrorCode = D_GIF_SUCCEEDED;
     return GIF_OK;
 }
 
@@ -670,6 +681,7 @@
 {
     unsigned char c[2];
 
+    /* coverity[check_return] */
     if (READ(GifFile, c, 2) != 2) {
         GifFile->Error = D_GIF_ERR_READ_FAILED;
         return GIF_ERROR;
@@ -714,6 +726,7 @@
     GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
 
     /* coverity[tainted_data_argument] */
+    /* coverity[check_return] */
     if (READ(GifFile, &Buf, 1) != 1) {
         GifFile->Error = D_GIF_ERR_READ_FAILED;
         return GIF_ERROR;
@@ -748,9 +761,18 @@
     GifPrefixType *Prefix;
     GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
 
-    READ(GifFile, &CodeSize, 1);    /* Read Code size from file. */
+    /* coverity[check_return] */
+    if (READ(GifFile, &CodeSize, 1) < 1) {    /* Read Code size from file. */
+	return GIF_ERROR;    /* Failed to read Code size. */
+    }
     BitsPerPixel = CodeSize;
 
+    /* this can only happen on a severely malformed GIF */
+    if (BitsPerPixel > 8) {
+	GifFile->Error = D_GIF_ERR_READ_FAILED;	/* somewhat bogus error code */
+	return GIF_ERROR;    /* Failed to read Code size. */
+    }
+
     Private->Buf[0] = 0;    /* Input Buffer empty. */
     Private->BitsPerPixel = BitsPerPixel;
     Private->ClearCode = (1 << BitsPerPixel);
@@ -834,19 +856,22 @@
                  * pixels on our stack. If we done, pop the stack in reverse
                  * (thats what stack is good for!) order to output.  */
                 if (Prefix[CrntCode] == NO_SUCH_CODE) {
+                    CrntPrefix = LastCode;
+
                     /* Only allowed if CrntCode is exactly the running code:
                      * In that case CrntCode = XXXCode, CrntCode or the
                      * prefix code is last code and the suffix char is
                      * exactly the prefix of last code! */
                     if (CrntCode == Private->RunningCode - 2) {
-                        CrntPrefix = LastCode;
                         Suffix[Private->RunningCode - 2] =
                            Stack[StackPtr++] = DGifGetPrefixChar(Prefix,
                                                                  LastCode,
                                                                  ClearCode);
                     } else {
-                        GifFile->Error = D_GIF_ERR_IMAGE_DEFECT;
-                        return GIF_ERROR;
+                        Suffix[Private->RunningCode - 2] =
+                           Stack[StackPtr++] = DGifGetPrefixChar(Prefix,
+                                                                 CrntCode,
+                                                                 ClearCode);
                     }
                 } else
                     CrntPrefix = CrntCode;
@@ -1018,6 +1043,7 @@
 {
     if (Buf[0] == 0) {
         /* Needs to read the next buffer - this one is empty: */
+	/* coverity[check_return] */
         if (READ(GifFile, Buf, 1) != 1) {
             GifFile->Error = D_GIF_ERR_READ_FAILED;
             return GIF_ERROR;
@@ -1030,14 +1056,6 @@
             GifFile->Error = D_GIF_ERR_IMAGE_DEFECT;
             return GIF_ERROR;
         }
-        /* There shouldn't be any empty data blocks here as the LZW spec
-         * says the LZW termination code should come first.  Therefore we
-         * shouldn't be inside this routine at that point.
-         */
-        if (Buf[0] == 0) {
-            GifFile->Error = D_GIF_ERR_IMAGE_DEFECT;
-            return GIF_ERROR;
-        }
         if (READ(GifFile, &Buf[1], Buf[0]) != Buf[0]) {
             GifFile->Error = D_GIF_ERR_READ_FAILED;
             return GIF_ERROR;
@@ -1090,7 +1108,7 @@
               if (ImageSize > (SIZE_MAX / sizeof(GifPixelType))) {
                   return GIF_ERROR;
               }
-              sp->RasterBits = (unsigned char *)malloc(ImageSize *
+              sp->RasterBits = (unsigned char *)reallocarray(NULL, ImageSize,
                       sizeof(GifPixelType));
 
               if (sp->RasterBits == NULL) {
@@ -1135,12 +1153,12 @@
                   return (GIF_ERROR);
 	      /* Create an extension block with our data */
               if (ExtData != NULL) {
-	          if (GifAddExtensionBlock(&GifFile->ExtensionBlockCount,
-				       &GifFile->ExtensionBlocks, 
-				       ExtFunction, ExtData[0], &ExtData[1])
-		  == GIF_ERROR)
-		  return (GIF_ERROR);
-              }
+		  if (GifAddExtensionBlock(&GifFile->ExtensionBlockCount,
+					   &GifFile->ExtensionBlocks, 
+					   ExtFunction, ExtData[0], &ExtData[1])
+		      == GIF_ERROR)
+		      return (GIF_ERROR);
+	      }
               while (ExtData != NULL) {
                   if (DGifGetExtensionNext(GifFile, &ExtData) == GIF_ERROR)
                       return (GIF_ERROR);
@@ -1162,6 +1180,12 @@
         }
     } while (RecordType != TERMINATE_RECORD_TYPE);
 
+    /* Sanity check for corrupted file */
+    if (GifFile->ImageCount == 0) {
+	GifFile->Error = D_GIF_ERR_NO_IMAG_DSCR;
+	return(GIF_ERROR);
+    }
+
     return (GIF_OK);
 }
 
diff --git a/egif_lib.c b/egif_lib.c
index 4e353ba..3917ec6 100644
--- a/egif_lib.c
+++ b/egif_lib.c
@@ -105,6 +105,7 @@
 	    *Error = E_GIF_ERR_NOT_ENOUGH_MEM;
         return NULL;
     }
+    /*@i1@*/memset(Private, '\0', sizeof(GifFilePrivateType));
     if ((Private->HashTable = _InitHashTable()) == NULL) {
         free(GifFile);
         free(Private);
@@ -123,6 +124,7 @@
     Private->FileHandle = FileHandle;
     Private->File = f;
     Private->FileState = FILE_STATE_WRITE;
+    Private->gif89 = false;
 
     Private->Write = (OutputFunc) 0;    /* No user write routine (MRB) */
     GifFile->UserData = (void *)NULL;    /* No user write handle (MRB) */
@@ -159,6 +161,8 @@
         return NULL;
     }
 
+    memset(Private, '\0', sizeof(GifFilePrivateType));
+
     Private->HashTable = _InitHashTable();
     if (Private->HashTable == NULL) {
         free (GifFile);
@@ -186,7 +190,7 @@
 /******************************************************************************
  Routine to compute the GIF version that will be written on output.
 ******************************************************************************/
-char *
+const char *
 EGifGetGifVersion(GifFileType *GifFile)
 {
     GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
@@ -267,7 +271,7 @@
 {
     GifByteType Buf[3];
     GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
-    char *write_version;
+    const char *write_version;
 
     if (Private->FileState & FILE_STATE_SCREEN) {
         /* If already has screen descriptor - something is wrong! */
@@ -379,6 +383,10 @@
     GifFile->Image.Height = Height;
     GifFile->Image.Interlace = Interlace;
     if (ColorMap) {
+	if (GifFile->Image.ColorMap != NULL) {
+	    GifFreeMapObject(GifFile->Image.ColorMap);
+	    GifFile->Image.ColorMap = NULL;
+	}
         GifFile->Image.ColorMap = GifMakeMapObject(ColorMap->ColorCount,
                                                 ColorMap->Colors);
         if (GifFile->Image.ColorMap == NULL) {
@@ -496,7 +504,7 @@
 int
 EGifPutComment(GifFileType *GifFile, const char *Comment)
 {
-    unsigned int length = strlen(Comment);
+    unsigned int length;
     char *buf;
 
     length = strlen(Comment);
@@ -750,7 +758,7 @@
  This routine should be called last, to close the GIF file.
 ******************************************************************************/
 int
-EGifCloseFile(GifFileType *GifFile)
+EGifCloseFile(GifFileType *GifFile, int *ErrorCode)
 {
     GifByteType Buf;
     GifFilePrivateType *Private;
@@ -764,7 +772,9 @@
 	return GIF_ERROR;
     if (!IS_WRITEABLE(Private)) {
         /* This file was NOT open for writing: */
-        GifFile->Error = E_GIF_ERR_NOT_WRITEABLE;
+	if (ErrorCode != NULL)
+	    *ErrorCode = E_GIF_ERR_NOT_WRITEABLE;
+	free(GifFile);
         return GIF_ERROR;
     }
 
@@ -785,22 +795,19 @@
         if (Private->HashTable) {
             free((char *) Private->HashTable);
         }
-	    free((char *) Private);
+	free((char *) Private);
     }
 
     if (File && fclose(File) != 0) {
-        GifFile->Error = E_GIF_ERR_CLOSE_FAILED;
+	if (ErrorCode != NULL)
+	    *ErrorCode = E_GIF_ERR_CLOSE_FAILED;
+	free(GifFile);
         return GIF_ERROR;
     }
 
-    /* 
-     * Without the #ifndef, we get spurious warnings because Coverity mistakenly
-     * thinks the GIF structure is freed on an error return. 
-     */
-#ifndef __COVERITY__
     free(GifFile);
-#endif /* __COVERITY__ */
-
+    if (ErrorCode != NULL)
+	*ErrorCode = E_GIF_SUCCEEDED;
     return GIF_OK;
 }
 
@@ -1140,7 +1147,7 @@
 			    GifFileOut->ExtensionBlockCount) == GIF_ERROR)
 	return (GIF_ERROR);
 
-    if (EGifCloseFile(GifFileOut) == GIF_ERROR)
+    if (EGifCloseFile(GifFileOut, NULL) == GIF_ERROR)
         return (GIF_ERROR);
 
     return (GIF_OK);
diff --git a/gif_err.c b/gif_err.c
index 8de72a0..3ec2a56 100644
--- a/gif_err.c
+++ b/gif_err.c
@@ -12,10 +12,10 @@
 /*****************************************************************************
  Return a string description of  the last GIF error
 *****************************************************************************/
-char *
+const char *
 GifErrorString(int ErrorCode)
 {
-    char *Err;
+    const char *Err;
 
     switch (ErrorCode) {
       case E_GIF_ERR_OPEN_FAILED:
diff --git a/gif_lib.h b/gif_lib.h
index 23df861..078930c 100644
--- a/gif_lib.h
+++ b/gif_lib.h
@@ -12,12 +12,13 @@
 #endif /* __cplusplus */
 
 #define GIFLIB_MAJOR 5
-#define GIFLIB_MINOR 0
+#define GIFLIB_MINOR 1
 #define GIFLIB_RELEASE 4
 
 #define GIF_ERROR   0
 #define GIF_OK      1
 
+#include <stddef.h>
 #include <stdbool.h>
 
 #define GIF_STAMP "GIFVER"          /* First chars in file - GIF stamp.  */
@@ -127,9 +128,10 @@
 GifFileType *EGifOpenFileHandle(const int GifFileHandle, int *Error);
 GifFileType *EGifOpen(void *userPtr, OutputFunc writeFunc, int *Error);
 int EGifSpew(GifFileType * GifFile);
-char *EGifGetGifVersion(GifFileType *GifFile); /* new in 5.x */
-int EGifCloseFile(GifFileType * GifFile);
+const char *EGifGetGifVersion(GifFileType *GifFile); /* new in 5.x */
+int EGifCloseFile(GifFileType *GifFile, int *ErrorCode);
 
+#define E_GIF_SUCCEEDED          0
 #define E_GIF_ERR_OPEN_FAILED    1    /* And EGif possible errors. */
 #define E_GIF_ERR_WRITE_FAILED   2
 #define E_GIF_ERR_HAS_SCRN_DSCR  3
@@ -178,8 +180,9 @@
 GifFileType *DGifOpenFileHandle(int GifFileHandle, int *Error);
 int DGifSlurp(GifFileType * GifFile);
 GifFileType *DGifOpen(void *userPtr, InputFunc readFunc, int *Error);    /* new one (TVT) */
-int DGifCloseFile(GifFileType * GifFile);
+    int DGifCloseFile(GifFileType * GifFile, int *ErrorCode);
 
+#define D_GIF_SUCCEEDED          0
 #define D_GIF_ERR_OPEN_FAILED    101    /* And DGif possible errors. */
 #define D_GIF_ERR_READ_FAILED    102
 #define D_GIF_ERR_NOT_GIF_FILE   103
@@ -222,7 +225,7 @@
 /******************************************************************************
  Error handling and reporting.
 ******************************************************************************/
-extern char *GifErrorString(int ErrorCode);     /* new in 2012 - ESR */
+extern const char *GifErrorString(int ErrorCode);     /* new in 2012 - ESR */
 
 /*****************************************************************************
  Everything below this point is new after version 1.2, supporting `slurp
@@ -241,6 +244,9 @@
                                      GifPixelType ColorTransIn2[]);
 extern int GifBitSize(int n);
 
+extern void *
+reallocarray(void *optr, size_t nmemb, size_t size);
+
 /******************************************************************************
  Support for the in-core structures allocation (slurp mode).              
 ******************************************************************************/
@@ -273,6 +279,31 @@
 			    GifFileType *GifFile, 
 			    int ImageIndex);
 
+/******************************************************************************
+ The library's internal utility font                          
+******************************************************************************/
+
+#define GIF_FONT_WIDTH  8
+#define GIF_FONT_HEIGHT 8
+extern const unsigned char GifAsciiTable8x8[][GIF_FONT_WIDTH];
+
+extern void GifDrawText8x8(SavedImage *Image,
+                     const int x, const int y,
+                     const char *legend, const int color);
+
+extern void GifDrawBox(SavedImage *Image,
+                    const int x, const int y,
+                    const int w, const int d, const int color);
+
+extern void GifDrawRectangle(SavedImage *Image,
+                   const int x, const int y,
+                   const int w, const int d, const int color);
+
+extern void GifDrawBoxedText8x8(SavedImage *Image,
+                          const int x, const int y,
+                          const char *legend,
+                          const int border, const int bg, const int fg);
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
diff --git a/gifalloc.c b/gifalloc.c
index 4cb8cde..3b51868 100644
--- a/gifalloc.c
+++ b/gifalloc.c
@@ -60,6 +60,7 @@
 
     Object->ColorCount = ColorCount;
     Object->BitsPerPixel = GifBitSize(ColorCount);
+    Object->SortFlag = false;
 
     if (ColorMap != NULL) {
         memcpy((char *)Object->Colors,
@@ -186,9 +187,15 @@
             Map[j].Red = Map[j].Green = Map[j].Blue = 0;
 
         /* perhaps we can shrink the map? */
-        if (RoundUpTo < ColorUnion->ColorCount)
-            ColorUnion->Colors = (GifColorType *)realloc(Map,
-                                 sizeof(GifColorType) * RoundUpTo);
+        if (RoundUpTo < ColorUnion->ColorCount) {
+            GifColorType *new_map = (GifColorType *)reallocarray(Map,
+                                 RoundUpTo, sizeof(GifColorType));
+            if( new_map == NULL ) {
+                GifFreeMapObject(ColorUnion);
+                return ((ColorMapObject *) NULL);
+            }
+            ColorUnion->Colors = new_map;
+        }
     }
 
     ColorUnion->ColorCount = RoundUpTo;
@@ -224,10 +231,14 @@
 
     if (*ExtensionBlocks == NULL)
         *ExtensionBlocks=(ExtensionBlock *)malloc(sizeof(ExtensionBlock));
-    else
-        *ExtensionBlocks = (ExtensionBlock *)realloc(*ExtensionBlocks,
-                                      sizeof(ExtensionBlock) *
-                                      (*ExtensionBlockCount + 1));
+    else {
+        ExtensionBlock* ep_new = (ExtensionBlock *)reallocarray
+				 (*ExtensionBlocks, (*ExtensionBlockCount + 1),
+                                      sizeof(ExtensionBlock));
+        if( ep_new == NULL )
+            return (GIF_ERROR);
+        *ExtensionBlocks = ep_new;
+    }
 
     if (*ExtensionBlocks == NULL)
         return (GIF_ERROR);
@@ -311,18 +322,16 @@
 SavedImage *
 GifMakeSavedImage(GifFileType *GifFile, const SavedImage *CopyFrom)
 {
-    SavedImage *sp;
-
     if (GifFile->SavedImages == NULL)
         GifFile->SavedImages = (SavedImage *)malloc(sizeof(SavedImage));
     else
-        GifFile->SavedImages = (SavedImage *)realloc(GifFile->SavedImages,
-                               sizeof(SavedImage) * (GifFile->ImageCount + 1));
+        GifFile->SavedImages = (SavedImage *)reallocarray(GifFile->SavedImages,
+                               (GifFile->ImageCount + 1), sizeof(SavedImage));
 
     if (GifFile->SavedImages == NULL)
         return ((SavedImage *)NULL);
     else {
-        sp = &GifFile->SavedImages[GifFile->ImageCount++];
+        SavedImage *sp = &GifFile->SavedImages[GifFile->ImageCount++];
         memset((char *)sp, '\0', sizeof(SavedImage));
 
         if (CopyFrom != NULL) {
@@ -346,9 +355,10 @@
             }
 
             /* next, the raster */
-            sp->RasterBits = (unsigned char *)malloc(sizeof(GifPixelType) *
-                                                   CopyFrom->ImageDesc.Height *
-                                                   CopyFrom->ImageDesc.Width);
+            sp->RasterBits = (unsigned char *)reallocarray(NULL,
+                                                  (CopyFrom->ImageDesc.Height *
+                                                  CopyFrom->ImageDesc.Width),
+						  sizeof(GifPixelType));
             if (sp->RasterBits == NULL) {
                 FreeLastSavedImage(GifFile);
                 return (SavedImage *)(NULL);
@@ -359,9 +369,9 @@
 
             /* finally, the extension blocks */
             if (sp->ExtensionBlocks != NULL) {
-                sp->ExtensionBlocks = (ExtensionBlock *)malloc(
-                                      sizeof(ExtensionBlock) *
-                                      CopyFrom->ExtensionBlockCount);
+                sp->ExtensionBlocks = (ExtensionBlock *)reallocarray(NULL,
+                                      CopyFrom->ExtensionBlockCount,
+				      sizeof(ExtensionBlock));
                 if (sp->ExtensionBlocks == NULL) {
                     FreeLastSavedImage(GifFile);
                     return (SavedImage *)(NULL);
diff --git a/openbsd-reallocarray.c b/openbsd-reallocarray.c
new file mode 100644
index 0000000..41a3326
--- /dev/null
+++ b/openbsd-reallocarray.c
@@ -0,0 +1,39 @@
+/*	$OpenBSD: reallocarray.c,v 1.1 2014/05/08 21:43:49 deraadt Exp $	*/
+/*
+ * Copyright (c) 2008 Otto Moerbeek <otto@drijf.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <limits.h>
+
+/*
+ * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX
+ * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW
+ */
+#define MUL_NO_OVERFLOW	((size_t)1 << (sizeof(size_t) * 4))
+
+void *
+reallocarray(void *optr, size_t nmemb, size_t size)
+{
+	if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
+	    nmemb > 0 && SIZE_MAX / nmemb < size) {
+		errno = ENOMEM;
+		return NULL;
+	}
+	return realloc(optr, size * nmemb);
+}
diff --git a/quantize.c b/quantize.c
index fc31f36..e5d4a59 100644
--- a/quantize.c
+++ b/quantize.c
@@ -234,6 +234,17 @@
              j++, QuantizedColor = QuantizedColor->Pnext)
             SortArray[j] = QuantizedColor;
 
+	/*
+	 * Because qsort isn't stable, this can produce differing 
+	 * results for the order of tuples depending on platform
+	 * details of how qsort() is implemented.
+	 *
+	 * We mitigate this problem by sorting on all three axes rather
+	 * than only the one specied by SortRGBAxis; that way the instability
+	 * can only become an issue if there are multiple color indices
+	 * referring to identical RGB tuples.  Older versions of this 
+	 * sorted on only the one axis.
+	 */
         qsort(SortArray, NewColorSubdiv[Index].NumEntries,
               sizeof(QuantizedColorType *), SortCmpRtn);
 
@@ -298,12 +309,22 @@
 /****************************************************************************
  Routine called by qsort to compare two entries.
 *****************************************************************************/
+
 static int
 SortCmpRtn(const void *Entry1,
            const void *Entry2) {
+	   QuantizedColorType *entry1 = (*((QuantizedColorType **) Entry1));
+	   QuantizedColorType *entry2 = (*((QuantizedColorType **) Entry2));
 
-    return (*((QuantizedColorType **) Entry1))->RGB[SortRGBAxis] -
-       (*((QuantizedColorType **) Entry2))->RGB[SortRGBAxis];
+	   /* sort on all axes of the color space! */
+	   int hash1 = entry1->RGB[SortRGBAxis] * 256 * 256
+	   			+ entry1->RGB[(SortRGBAxis+1) % 3] * 256
+				+ entry1->RGB[(SortRGBAxis+2) % 3];
+	   int hash2 = entry2->RGB[SortRGBAxis] * 256 * 256
+	   			+ entry2->RGB[(SortRGBAxis+1) % 3] * 256
+				+ entry2->RGB[(SortRGBAxis+2) % 3];
+
+    return hash1 - hash2;
 }
 
 /* end */