diff --git a/Android.mk b/Android.mk index f9ff34b2..99a6e96d 100644 --- a/Android.mk +++ b/Android.mk @@ -6,7 +6,8 @@ LOCAL_SDK_VERSION := 9 LOCAL_SRC_FILES := \ dgif_lib.c \ gifalloc.c \ - gif_err.c + gif_err.c \ + openbsd-reallocarray.c LOCAL_CFLAGS += -Wno-format -DHAVE_CONFIG_H LOCAL_SDK_VERSION := 8 diff --git a/dgif_lib.c b/dgif_lib.c index 744a2f90..66a1d6a4 100644 --- a/dgif_lib.c +++ b/dgif_lib.c @@ -59,7 +59,6 @@ DGifOpenFileName(const char *FileName, int *Error) } GifFile = DGifOpenFileHandle(FileHandle, Error); - // cppcheck-suppress resourceLeak return GifFile; } @@ -90,7 +89,7 @@ DGifOpenFileHandle(int FileHandle, int *Error) 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 @@ DGifOpenFileHandle(int FileHandle, int *Error) 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 @@ DGifOpenFileHandle(int FileHandle, int *Error) /*@=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 @@ DGifOpen(void *userData, InputFunc readFunc, int *Error) 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 @@ DGifOpen(void *userData, InputFunc readFunc, int *Error) 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 @@ DGifOpen(void *userData, InputFunc readFunc, int *Error) 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 @@ DGifGetScreenDesc(GifFileType *GifFile) /* 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 @@ DGifGetRecordType(GifFileType *GifFile, GifRecordType* Type) 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 @@ DGifGetImageDesc(GifFileType *GifFile) /* 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 @@ DGifGetImageDesc(GifFileType *GifFile) } 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 @@ DGifGetImageDesc(GifFileType *GifFile) (long)GifFile->Image.Height; /* Reset decompress algorithm parameters. */ - (void)DGifSetupDecompress(GifFile); - - return GIF_OK; + return DGifSetupDecompress(GifFile); } /****************************************************************************** @@ -521,6 +531,7 @@ DGifGetExtension(GifFileType *GifFile, int *ExtCode, GifByteType **Extension) 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 @@ DGifGetExtensionNext(GifFileType *GifFile, GifByteType ** Extension) 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 @@ int DGifSavedExtensionToGCB(GifFileType *GifFile, 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 @@ DGifCloseFile(GifFileType *GifFile) 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 @@ DGifGetWord(GifFileType *GifFile, GifWord *Word) { 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 @@ DGifGetCodeNext(GifFileType *GifFile, GifByteType **CodeBlock) 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 @@ DGifSetupDecompress(GifFileType *GifFile) 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 @@ DGifDecompressLine(GifFileType *GifFile, GifPixelType *Line, int LineLen) * 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 @@ DGifBufferedInput(GifFileType *GifFile, GifByteType *Buf, GifByteType *NextByte) { 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 @@ DGifBufferedInput(GifFileType *GifFile, GifByteType *Buf, GifByteType *NextByte) 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 @@ DGifSlurp(GifFileType *GifFile) 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 @@ DGifSlurp(GifFileType *GifFile) 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 @@ DGifSlurp(GifFileType *GifFile) } } 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/gif_err.c b/gif_err.c index 8de72a00..3ec2a56f 100644 --- a/gif_err.c +++ b/gif_err.c @@ -12,10 +12,10 @@ gif_err.c - handle error reporting for the GIF library. /***************************************************************************** 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 23df8613..078930c6 100644 --- a/gif_lib.h +++ b/gif_lib.h @@ -12,12 +12,13 @@ extern "C" { #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 #include #define GIF_STAMP "GIFVER" /* First chars in file - GIF stamp. */ @@ -127,9 +128,10 @@ GifFileType *EGifOpenFileName(const char *GifFileName, 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 *DGifOpenFileName(const char *GifFileName, int *Error); 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 @@ int GifQuantizeBuffer(unsigned int Width, unsigned int Height, /****************************************************************************** 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 @@ extern ColorMapObject *GifUnionColorMap(const ColorMapObject *ColorIn1, 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 @@ int EGifGCBToSavedExtension(const GraphicsControlBlock *GCB, 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 4cb8cde1..3b518680 100644 --- a/gifalloc.c +++ b/gifalloc.c @@ -60,6 +60,7 @@ GifMakeMapObject(int ColorCount, const GifColorType *ColorMap) Object->ColorCount = ColorCount; Object->BitsPerPixel = GifBitSize(ColorCount); + Object->SortFlag = false; if (ColorMap != NULL) { memcpy((char *)Object->Colors, @@ -186,9 +187,15 @@ GifUnionColorMap(const ColorMapObject *ColorIn1, 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 @@ GifAddExtensionBlock(int *ExtensionBlockCount, 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 @@ FreeLastSavedImage(GifFileType *GifFile) 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 @@ GifMakeSavedImage(GifFileType *GifFile, const SavedImage *CopyFrom) } /* 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 @@ GifMakeSavedImage(GifFileType *GifFile, const SavedImage *CopyFrom) /* 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 00000000..41a33262 --- /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 + * + * 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 +#include +#include +#include +#include + +/* + * 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); +}