summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeon Scroggins III <scroggo@google.com>2017-03-14 19:20:37 +0000
committerandroid-build-merger <android-build-merger@google.com>2017-03-14 19:20:37 +0000
commit34ed1449181d5377c0ba943f42fb964fc1afe011 (patch)
tree871c599d19653398d83d63d16e86b7e5ca20e15c
parent621696a283c0ce34956417f760f1005fadcd12ae (diff)
parent398d93604167f7499f895bcde8fb4048afaba8b0 (diff)
downloadgiflib-34ed1449181d5377c0ba943f42fb964fc1afe011.tar.gz
Update GIFLIB to 5.1.4 DO NOT MERGE am: b95e3f654a
am: 398d936041 Change-Id: I80be8771d2b6a12eecb9f4204e7eeebc53ab106a
-rw-r--r--Android.mk3
-rw-r--r--dgif_lib.c104
-rw-r--r--gif_err.c4
-rw-r--r--gif_lib.h41
-rw-r--r--gifalloc.c46
-rw-r--r--openbsd-reallocarray.c38
6 files changed, 171 insertions, 65 deletions
diff --git a/Android.mk b/Android.mk
index cea7cf1..ac0e341 100644
--- a/Android.mk
+++ b/Android.mk
@@ -4,7 +4,8 @@ include $(CLEAR_VARS)
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 c7ff504..66a1d6a 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) {
@@ -1134,11 +1152,13 @@ DGifSlurp(GifFileType *GifFile)
if (DGifGetExtension(GifFile,&ExtFunction,&ExtData) == GIF_ERROR)
return (GIF_ERROR);
/* Create an extension block with our data */
- if (GifAddExtensionBlock(&GifFile->ExtensionBlockCount,
- &GifFile->ExtensionBlocks,
- ExtFunction, ExtData[0], &ExtData[1])
- == GIF_ERROR)
- return (GIF_ERROR);
+ if (ExtData != NULL) {
+ 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);
@@ -1160,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 8de72a0..3ec2a56 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 23df861..078930c 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 <stddef.h>
#include <stdbool.h>
#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 4cb8cde..3b51868 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 0000000..aa70686
--- /dev/null
+++ b/openbsd-reallocarray.c
@@ -0,0 +1,38 @@
+/* $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>
+
+/*
+ * 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);
+}