Commit d504d82a authored by Matthias Clasen's avatar Matthias Clasen

Add ico and wbmp tests. Fail with a suitable error if buffer allocation

* test-images.h, test-loaders.c: Add ico and wbmp tests.
* io-jpeg.c (gdk_pixbuf__jpeg_image_save): Fail with a suitable
error if buffer allocation fails.
* io-ico.c: Make .ICO loader more robust.
All of these are due to sandmann@daimi.au.dk (#50187)
parent 9b14c046
......@@ -41,6 +41,7 @@ Known bugs:
#include <string.h>
#include "gdk-pixbuf-private.h"
#include "gdk-pixbuf-io.h"
#include <errno.h>
......@@ -115,8 +116,8 @@ static void DumpBIH(unsigned char *BIH)
/* Progressive loading */
struct headerpair {
guint width;
guint height;
gint width;
gint height;
guint depth;
guint Negative; /* Negative = 1 -> top down BMP,
Negative = 0 -> bottom up BMP */
......@@ -163,14 +164,27 @@ static gboolean gdk_pixbuf__ico_image_load_increment(gpointer data,
const guchar * buf, guint size,
GError **error);
static void
context_free (struct ico_progressive_state *context)
{
if (context->LineBuf != NULL)
g_free (context->LineBuf);
context->LineBuf = NULL;
if (context->HeaderBuf != NULL)
g_free (context->HeaderBuf);
if (context->pixbuf)
gdk_pixbuf_unref (context->pixbuf);
g_free (context);
}
/* Shared library entry point --> Can go when generic_image_load
enters gdk-pixbuf-io */
static GdkPixbuf *
gdk_pixbuf__ico_image_load(FILE * f, GError **error)
{
guchar *membuf;
guchar membuf [4096];
size_t length;
struct ico_progressive_state *State;
......@@ -179,24 +193,35 @@ gdk_pixbuf__ico_image_load(FILE * f, GError **error)
State = gdk_pixbuf__ico_image_begin_load(NULL, NULL, NULL, error);
if (State == NULL)
return NULL;
return NULL;
membuf = g_malloc(4096);
g_assert(membuf != NULL);
while (feof(f) == 0) {
while (!feof(f)) {
length = fread(membuf, 1, 4096, f);
if (ferror (f)) {
g_set_error (error,
G_FILE_ERROR,
g_file_error_from_errno (errno),
_("Failure reading ICO: %s"), g_strerror (errno));
context_free (State);
return NULL;
}
if (length > 0)
if (!gdk_pixbuf__ico_image_load_increment(State, membuf, length,
error)) {
gdk_pixbuf__ico_image_stop_load (State, NULL);
context_free (State);
return NULL;
}
}
}
g_free(membuf);
if (State->pixbuf != NULL)
gdk_pixbuf_ref(State->pixbuf);
gdk_pixbuf_ref (State->pixbuf);
else {
g_set_error (error,
GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
_("ICO file was missing some data (perhaps it was truncated somehow?)"));
context_free (State);
return NULL;
}
pb = State->pixbuf;
......@@ -205,7 +230,8 @@ gdk_pixbuf__ico_image_load(FILE * f, GError **error)
}
static void DecodeHeader(guchar *Data, gint Bytes,
struct ico_progressive_state *State)
struct ico_progressive_state *State,
GError **error)
{
/* For ICO's we have to be very clever. There are multiple images possible
in an .ICO. For now, we select (in order of priority):
......@@ -225,7 +251,14 @@ static void DecodeHeader(guchar *Data, gint Bytes,
State->HeaderSize = 6 + IconCount*16;
if (State->HeaderSize>State->BytesInHeaderBuf) {
State->HeaderBuf=g_realloc(State->HeaderBuf,State->HeaderSize);
State->HeaderBuf=g_try_realloc(State->HeaderBuf,State->HeaderSize);
if (!State->HeaderBuf) {
g_set_error (error,
GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
_("Not enough memory to load icon"));
return;
}
State->BytesInHeaderBuf = State->HeaderSize;
}
if (Bytes < State->HeaderSize)
......@@ -266,7 +299,14 @@ static void DecodeHeader(guchar *Data, gint Bytes,
State->HeaderSize = State->DIBoffset + 40; /* 40 = sizeof(InfoHeader) */
if (State->HeaderSize>State->BytesInHeaderBuf) {
State->HeaderBuf=g_realloc(State->HeaderBuf,State->HeaderSize);
State->HeaderBuf=g_try_realloc(State->HeaderBuf,State->HeaderSize);
if (!State->HeaderBuf) {
g_set_error (error,
GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
_("Not enough memory to load icon"));
return;
}
State->BytesInHeaderBuf = State->HeaderSize;
}
if (Bytes<State->HeaderSize)
......@@ -282,9 +322,23 @@ static void DecodeHeader(guchar *Data, gint Bytes,
State->Header.width =
(int)(BIH[7] << 24) + (BIH[6] << 16) + (BIH[5] << 8) + (BIH[4]);
if (State->Header.width == 0) {
g_set_error (error,
GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
_("Icon has zero width"));
return;
}
State->Header.height =
(int)(BIH[11] << 24) + (BIH[10] << 16) + (BIH[9] << 8) + (BIH[8])/2;
/* /2 because the BIH height includes the transparency mask */
if (State->Header.height == 0) {
g_set_error (error,
GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
_("Icon has zero height"));
return;
}
State->Header.depth = (BIH[15] << 8) + (BIH[14]);;
State->Type = State->Header.depth;
......@@ -308,7 +362,14 @@ static void DecodeHeader(guchar *Data, gint Bytes,
State->HeaderSize+=I;
if (State->HeaderSize>State->BytesInHeaderBuf) {
State->HeaderBuf=g_realloc(State->HeaderBuf,State->HeaderSize);
State->HeaderBuf=g_try_realloc(State->HeaderBuf,State->HeaderSize);
if (!State->HeaderBuf) {
g_set_error (error,
GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
_("Not enough memory to load icon"));
return;
}
State->BytesInHeaderBuf = State->HeaderSize;
}
if (Bytes < State->HeaderSize)
......@@ -316,7 +377,12 @@ static void DecodeHeader(guchar *Data, gint Bytes,
if ((BIH[16] != 0) || (BIH[17] != 0) || (BIH[18] != 0)
|| (BIH[19] != 0)) {
g_assert(0); /* Compressed icons aren't allowed */
/* FIXME: is this the correct message? */
g_set_error (error,
GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
_("Compressed icons are not supported"));
return;
}
/* Negative heights mean top-down pixel-order */
......@@ -327,6 +393,8 @@ static void DecodeHeader(guchar *Data, gint Bytes,
if (State->Header.width < 0) {
State->Header.width = -State->Header.width;
}
g_assert (State->Header.width > 0);
g_assert (State->Header.height > 0);
if (State->Type == 24)
State->LineWidth = State->Header.width * 3;
......@@ -346,8 +414,16 @@ static void DecodeHeader(guchar *Data, gint Bytes,
State->LineWidth = (State->LineWidth / 4) * 4 + 4;
if (State->LineBuf == NULL)
State->LineBuf = g_malloc(State->LineWidth);
if (State->LineBuf == NULL) {
State->LineBuf = g_try_malloc(State->LineWidth);
if (!State->LineBuf) {
g_set_error (error,
GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
_("Not enough memory to load icon"));
}
return;
}
g_assert(State->LineBuf != NULL);
......@@ -355,8 +431,8 @@ static void DecodeHeader(guchar *Data, gint Bytes,
if (State->pixbuf == NULL) {
State->pixbuf =
gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8,
(gint) State->Header.width,
(gint) State->Header.height);
State->Header.width,
State->Header.height);
if (State->prepared_func != NULL)
/* Notify the client that we are ready to go */
......@@ -388,7 +464,14 @@ gdk_pixbuf__ico_image_begin_load(ModulePreparedNotifyFunc prepared_func,
context->user_data = user_data;
context->HeaderSize = 54;
context->HeaderBuf = g_malloc(14 + 40 + 4*256 + 512);
context->HeaderBuf = g_try_malloc(14 + 40 + 4*256 + 512);
if (!context->HeaderBuf) {
g_set_error (error,
GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
_("Not enough memory to load ICO file"));
return NULL;
}
/* 4*256 for the colormap */
context->BytesInHeaderBuf = 14 + 40 + 4*256 + 512 ;
context->HeaderDone = 0;
......@@ -425,18 +508,8 @@ gboolean gdk_pixbuf__ico_image_stop_load(gpointer data,
*/
g_return_val_if_fail(context != NULL, TRUE);
if (context->LineBuf != NULL)
g_free(context->LineBuf);
context->LineBuf = NULL;
if (context->HeaderBuf != NULL)
g_free(context->HeaderBuf);
if (context->pixbuf)
gdk_pixbuf_unref(context->pixbuf);
g_free(context);
context_free (context);
return TRUE;
}
......@@ -672,9 +745,8 @@ gdk_pixbuf__ico_image_load_increment(gpointer data,
size -= BytesToCopy;
buf += BytesToCopy;
context->HeaderDone += BytesToCopy;
} else
{
}
else {
BytesToCopy =
context->LineWidth - context->LineDone;
if (BytesToCopy > size)
......@@ -696,11 +768,15 @@ gdk_pixbuf__ico_image_load_increment(gpointer data,
}
if (context->HeaderDone >= 6)
if (context->HeaderDone >= 6) {
GError *decode_err = NULL;
DecodeHeader(context->HeaderBuf,
context->HeaderDone, context);
context->HeaderDone, context, &decode_err);
if (decode_err) {
g_propagate_error (error, decode_err);
return FALSE;
}
}
}
return TRUE;
......
......@@ -693,7 +693,14 @@ gdk_pixbuf__jpeg_image_save (FILE *f,
g_return_val_if_fail (pixels != NULL, FALSE);
/* allocate a small buffer to convert image data */
buf = g_malloc (w * 3 * sizeof (guchar));
buf = g_try_malloc (w * 3 * sizeof (guchar));
if (!buf) {
g_set_error (error,
GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
_("Couldn't allocate memory for loading JPEG file"));
return FALSE;
}
/* set up error handling */
jerr.pub.error_exit = fatal_error_handler;
......
......@@ -825,6 +825,91 @@ static unsigned char const tiff1_test_1[] = {
0
};
static unsigned char const valid_ico_test[] = {
0, 0, 1, 0, 1, 0, 16, 16, 16, 0, 0, 0, 0, 0, 40, 1, 0, 0, 22, 0, 0,
0, 40, 0, 0, 0, 16, 0, 0, 0, 32, 0, 0, 0, 1, 0, 4, 0, 0, 0, 0, 0,
128, 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, 128, 0, 0, 128, 0, 0, 0, 128, 128, 0, 128, 0, 0, 0, 128,
0, 128, 0, 128, 128, 0, 0, 192, 192, 192, 0, 128, 128, 128, 0, 0, 0,
255, 0, 0, 255, 0, 0, 0, 255, 255, 0, 255, 0, 0, 0, 255, 0, 255, 0,
255, 255, 0, 0, 255, 255, 255, 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,
153, 153, 153, 9, 144, 0, 0, 0, 0, 153, 0, 0, 0, 0, 0, 0, 0, 153, 0,
0, 153, 0, 0, 0, 9, 153, 144, 0, 153, 144, 0, 0, 153, 144, 153, 0,
9, 144, 0, 9, 153, 0, 9, 144, 9, 153, 0, 153, 144, 0, 153, 153, 153,
153, 153, 153, 153, 144, 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,
255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 240, 55, 0, 0, 240,
39, 0, 0, 252, 123, 0, 0, 252, 113, 0, 0, 248, 48, 0, 0, 241, 24, 0,
0, 227, 136, 0, 0, 129, 0, 0, 0, 1, 255, 0, 0, 255, 255, 0, 0, 255,
255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0
};
static unsigned char const ico_test_1[] = {
0, 0, 1, 0, 1, 0, 16, 16, 16, 0, 0, 0, 0, 0, 40, 1, 0, 0, 22, 0,
0, 0, 40, 0, 0, 0, 16, 0, 0, 0, 32, 0, 0, 0, 1, 0, 4, 0, 0, 222,
0, 0, 128, 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, 128, 0, 0, 128, 0, 0, 0, 128, 128, 0, 128, 0,
0, 0, 128, 0, 128, 0, 128, 128, 0, 0, 192, 192, 192, 0, 128, 128,
128, 0, 0, 0, 255, 0, 0, 255, 0, 0, 0, 255, 255, 0, 255, 0, 0, 0,
255, 0 , 255, 0, 255, 255, 0, 0, 255, 255, 255, 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, 153, 153, 153, 9, 144, 0, 0, 0, 0, 153, 0, 0,
0, 0, 0, 0, 0, 153, 0, 0, 153, 0, 0, 0, 9, 153, 144, 0, 153, 144,
0, 0, 153, 144, 153, 251, 9, 144, 0, 9, 153, 0, 9, 144, 9, 153 ,
0, 153, 144, 0, 153, 153, 153, 153, 153, 153, 153, 144, 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, 255, 255, 0, 0, 255, 255, 0, 0,
255, 255, 0, 0, 240, 55, 0, 0, 240, 39, 0, 0, 252, 123, 0, 0, 252,
113, 0, 0, 248, 48, 0, 0, 241, 24, 0, 0, 227, 136, 0, 0 , 129, 0,
0, 0, 1, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0,
0, 255, 255, 0, 0
};
static unsigned char const wbmp_test_1[] = {
0, 0, 189, 179, 1, 0, 16, 180, 16, 0, 0, 230, 0, 0, 40, 1, 0, 0,
22, 0, 0, 115, 40, 0, 0, 0, 16, 0, 0, 0, 32, 56, 0, 0, 1, 70, 4,
92, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 23, 0, 0, 0, 0, 128, 0, 0, 128, 0, 0, 135, 128,
128, 0, 128, 0, 0, 0, 248, 0, 128, 0, 128, 128, 0, 154, 84, 192,
176, 0, 128, 128, 128, 0, 0, 0, 255, 0, 0, 255, 151, 0, 0, 161,
255, 0, 255, 0, 0, 0, 255, 0, 255, 0, 255, 255, 0, 0, 255, 250,
255, 0, 0, 159, 0, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 216, 0, 0, 148,
0, 0, 0, 24, 0, 187, 0, 229, 0, 0, 0, 0, 0, 67, 0, 90, 0, 65, 153,
153, 9, 144, 205, 236, 0, 0, 153, 0, 0, 0, 0, 0, 0, 251, 249, 0,
0, 194, 0, 97, 0, 9, 153, 144, 0, 153, 144, 0, 255, 153, 144, 153,
150, 9, 144, 0, 9, 153, 141, 9, 198, 9, 153, 0, 153, 153, 208,
153, 153, 233, 239, 153, 153, 153, 144, 0, 0, 71, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 61, 0, 0, 0, 0, 17, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 171, 235, 0, 0, 103, 255, 0, 60, 255, 255, 0,
0, 240, 55, 0, 41, 240, 39, 220, 0, 252, 123, 0, 0, 58, 113, 0,
178, 248, 48, 233, 0, 241, 183, 42, 0, 130, 136, 0, 0, 129, 88, 0,
0, 1, 255, 0, 0, 175, 93, 26, 0, 255, 255, 0, 149, 255, 255, 0,
198, 212, 255, 0, 0,
};
static unsigned char const wbmp_test_2[] = {
0, 0, 1, 111, 172, 0, 16, 16, 227, 0, 162, 150, 0, 24, 40, 208, 0,
0, 22, 0, 0, 0, 40, 9, 0, 0, 16, 0, 221, 55, 32, 0, 0, 49, 1, 0,
4, 0, 0, 0, 171, 0, 128, 0, 0, 24, 0, 0, 88, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 38, 0, 0, 0, 0, 128, 0, 0, 128, 0, 0, 0, 128,
128, 0, 128, 0, 0, 0, 128, 107, 128, 0, 128, 128, 0, 0, 192, 248,
192, 234, 128, 128, 128, 209, 0, 28, 255, 0, 0, 255, 0, 0, 0, 255,
255, 0, 255, 0, 0, 0, 102, 0, 255, 0, 130, 255, 0, 0, 255, 255,
255, 202, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
232, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 81, 0, 153, 153, 153,
99, 144, 0, 0, 0, 0, 153, 0, 0, 0, 0, 0, 0, 0, 153, 0, 0, 153,
255, 0, 0, 10, 153, 144, 0, 153, 144, 0, 0, 153, 144, 153, 96, 9,
144, 0, 9, 153, 0, 9, 144, 9, 153, 0, 153, 144, 0, 153, 254, 153,
153, 153, 153, 153, 144, 0, 0, 0, 168, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 5, 0, 47, 17, 0, 0, 0, 0, 0, 0, 250, 93, 47, 0,
133, 28, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 240,
55, 211, 0, 240, 39, 0, 169, 252, 123, 0, 0, 252, 118, 0, 0, 248,
48, 26, 0, 122, 24, 0, 0, 227, 108, 0, 0, 129, 0, 0, 133, 1, 255,
0, 0, 142, 255, 0, 0, 255, 255, 88, 40, 120, 64, 0, 178, 168, 255,
151, 147
};
static unsigned char const valid_jpeg_test[] = {
JPEG_HEADER,
255, 224, 0, 16, 74, 70, 73, 70, 0, 1, 1, 1, 0, 72, 0, 72, 0, 0,
......
......@@ -265,18 +265,19 @@ randomly_modify (const guchar *image, guint size, gboolean verbose)
{
int j;
guint index = rand () % size;
guchar byte = rand () % 256;
guint index = g_random_int_range (0, size);
guchar byte = g_random_int_range (0, 256);
img_copy[index] = byte;
if (verbose)
g_print ("%d\n", i);
if (verbose)
for (j = 0; j < size; j++)
g_print ("%u, ", img_copy[j]);
{
g_print ("img no %d\n", i);
for (j = 0; j < size; j++)
g_print ("%u, ", img_copy[j]);
g_print ("\n\n");
}
test_loader (img_copy, size, FALSE);
}
g_free (img_copy);
......@@ -383,7 +384,16 @@ main (int argc, char **argv)
TEST (valid_png_test, TRUE);
TEST (png_test_1, FALSE);
TEST (valid_ico_test, TRUE);
TEST (ico_test_1, FALSE);
#if 0
TEST (wbmp_test_1, FALSE);
TEST (wbmp_test_2, FALSE);
#endif
#if 0
TEST (png_test_2, FALSE);
#endif
......@@ -399,6 +409,13 @@ main (int argc, char **argv)
TEST_RANDOMLY_MODIFIED (valid_tiff1_test, FALSE);
#endif
#if 0
TEST_RANDOMLY_MODIFIED (valid_ico_test, TRUE); /* The ico loader does not seem to
* break, but the image tend to
* mutate into a wbmp image, and
* the wbmp loader is broken
*/
#endif
TEST_RANDOMLY_MODIFIED (valid_jpeg_test, FALSE); // The jpeg loader does not break
#if 0
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment