IMG_pnm.c
author Sam Lantinga <slouken@libsdl.org>
Thu, 25 Apr 2013 00:22:51 -0700
changeset 367 b2aa197f6774
parent 347 ad5034cad524
child 368 8a61842d00ce
permissions -rw-r--r--
Fixed bug 1821 - IMG_LoadLBM/PNM/XCF_RW() crash with a heap corruption on loading LBM, PNM or XCF images

Marcus von Appen

Trying to load a LBM image via any of the IMG_* functions will lead to a heap corruption on Windows 7, causing the application to crash.

The problem is caused by the usage of SDL_malloc on Win32, which by default uses dlmalloc, which in turn redefines malloc and free within the SDL address space.

The CRT heap manager hence is unaware of the pointer being allocated and will try to free an unmanaged memory segment by calling free() on the temporary buffer in IMG_LoadLBM_RW().
slouken@25
     1
/*
slouken@280
     2
  SDL_image:  An example image loading library for use with SDL
slouken@347
     3
  Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
slouken@25
     4
slouken@280
     5
  This software is provided 'as-is', without any express or implied
slouken@280
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@280
     7
  arising from the use of this software.
slouken@25
     8
slouken@280
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@280
    10
  including commercial applications, and to alter it and redistribute it
slouken@280
    11
  freely, subject to the following restrictions:
slouken@25
    12
slouken@280
    13
  1. The origin of this software must not be misrepresented; you must not
slouken@280
    14
     claim that you wrote the original software. If you use this software
slouken@280
    15
     in a product, an acknowledgment in the product documentation would be
slouken@280
    16
     appreciated but is not required.
slouken@280
    17
  2. Altered source versions must be plainly marked as such, and must not be
slouken@280
    18
     misrepresented as being the original software.
slouken@280
    19
  3. This notice may not be removed or altered from any source distribution.
slouken@25
    20
*/
slouken@25
    21
slouken@25
    22
/*
slouken@25
    23
 * PNM (portable anymap) image loader:
slouken@25
    24
 *
slouken@25
    25
 * Supports: PBM, PGM and PPM, ASCII and binary formats
slouken@25
    26
 * (PBM and PGM are loaded as 8bpp surfaces)
slouken@25
    27
 * Does not support: maximum component value > 255
slouken@25
    28
 */
slouken@25
    29
slouken@25
    30
#include <stdio.h>
slouken@25
    31
#include <stdlib.h>
slouken@25
    32
#include <ctype.h>
slouken@25
    33
#include <string.h>
slouken@25
    34
slouken@25
    35
#include "SDL_image.h"
slouken@25
    36
slouken@25
    37
#ifdef LOAD_PNM
slouken@25
    38
slouken@25
    39
/* See if an image is contained in a data source */
slouken@25
    40
int IMG_isPNM(SDL_RWops *src)
slouken@25
    41
{
aschiffler@343
    42
	Sint64 start;
slouken@117
    43
	int is_PNM;
slouken@25
    44
	char magic[2];
slouken@25
    45
icculus@154
    46
	if ( !src )
icculus@154
    47
		return 0;
slouken@117
    48
	start = SDL_RWtell(src);
slouken@117
    49
	is_PNM = 0;
slouken@117
    50
	if ( SDL_RWread(src, magic, sizeof(magic), 1) ) {
slouken@117
    51
		/*
slouken@117
    52
		 * PNM magic signatures:
slouken@117
    53
		 * P1	PBM, ascii format
slouken@117
    54
		 * P2	PGM, ascii format
slouken@117
    55
		 * P3	PPM, ascii format
slouken@117
    56
		 * P4	PBM, binary format
slouken@117
    57
		 * P5	PGM, binary format
slouken@117
    58
		 * P6	PPM, binary format
slouken@119
    59
		 * P7	PAM, a general wrapper for PNM data
slouken@117
    60
		 */
slouken@117
    61
		if ( magic[0] == 'P' && magic[1] >= '1' && magic[1] <= '6' ) {
slouken@117
    62
			is_PNM = 1;
slouken@117
    63
		}
slouken@117
    64
	}
slouken@236
    65
	SDL_RWseek(src, start, RW_SEEK_SET);
slouken@117
    66
	return(is_PNM);
slouken@25
    67
}
slouken@25
    68
slouken@25
    69
/* read a non-negative integer from the source. return -1 upon error */
slouken@25
    70
static int ReadNumber(SDL_RWops *src)
slouken@25
    71
{
slouken@25
    72
	int number;
slouken@25
    73
	unsigned char ch;
slouken@25
    74
slouken@25
    75
	/* Initialize return value */
slouken@25
    76
	number = 0;
slouken@25
    77
slouken@25
    78
	/* Skip leading whitespace */
slouken@25
    79
	do {
slouken@25
    80
		if ( ! SDL_RWread(src, &ch, 1, 1) ) {
slouken@25
    81
			return(0);
slouken@25
    82
		}
slouken@25
    83
		/* Eat comments as whitespace */
slouken@25
    84
		if ( ch == '#' ) {  /* Comment is '#' to end of line */
slouken@25
    85
			do {
slouken@25
    86
				if ( ! SDL_RWread(src, &ch, 1, 1) ) {
slouken@25
    87
					return -1;
slouken@25
    88
				}
slouken@25
    89
			} while ( (ch != '\r') && (ch != '\n') );
slouken@25
    90
		}
slouken@25
    91
	} while ( isspace(ch) );
slouken@25
    92
slouken@25
    93
	/* Add up the number */
slouken@25
    94
	do {
slouken@25
    95
		number *= 10;
slouken@25
    96
		number += ch-'0';
slouken@25
    97
slouken@25
    98
		if ( !SDL_RWread(src, &ch, 1, 1) ) {
slouken@25
    99
			return -1;
slouken@25
   100
		}
slouken@25
   101
	} while ( isdigit(ch) );
slouken@25
   102
slouken@25
   103
	return(number);
slouken@25
   104
}
slouken@25
   105
slouken@25
   106
SDL_Surface *IMG_LoadPNM_RW(SDL_RWops *src)
slouken@25
   107
{
aschiffler@343
   108
	Sint64 start;
slouken@25
   109
	SDL_Surface *surface = NULL;
slouken@25
   110
	int width, height;
slouken@25
   111
	int maxval, y, bpl;
slouken@25
   112
	Uint8 *row;
slouken@25
   113
	Uint8 *buf = NULL;
slouken@25
   114
	char *error = NULL;
slouken@25
   115
	Uint8 magic[2];
slouken@25
   116
	int ascii;
slouken@119
   117
	enum { PBM, PGM, PPM, PAM } kind;
slouken@25
   118
slouken@25
   119
#define ERROR(s) do { error = (s); goto done; } while(0)
slouken@25
   120
slouken@98
   121
	if ( !src ) {
slouken@98
   122
		/* The error message has been set in SDL_RWFromFile */
slouken@98
   123
		return NULL;
slouken@98
   124
	}
slouken@118
   125
	start = SDL_RWtell(src);
slouken@98
   126
slouken@25
   127
	SDL_RWread(src, magic, 2, 1);
slouken@25
   128
	kind = magic[1] - '1';
slouken@25
   129
	ascii = 1;
slouken@25
   130
	if(kind >= 3) {
slouken@25
   131
		ascii = 0;
slouken@25
   132
		kind -= 3;
slouken@25
   133
	}
slouken@25
   134
slouken@25
   135
	width = ReadNumber(src);
slouken@25
   136
	height = ReadNumber(src);
slouken@25
   137
	if(width <= 0 || height <= 0)
slouken@25
   138
		ERROR("Unable to read image width and height");
slouken@25
   139
slouken@25
   140
	if(kind != PBM) {
slouken@25
   141
		maxval = ReadNumber(src);
slouken@25
   142
		if(maxval <= 0 || maxval > 255)
slouken@25
   143
			ERROR("unsupported PNM format");
slouken@25
   144
	} else
slouken@25
   145
		maxval = 255;	/* never scale PBMs */
slouken@25
   146
slouken@25
   147
	/* binary PNM allows just a single character of whitespace after
slouken@25
   148
	   the last parameter, and we've already consumed it */
slouken@25
   149
slouken@25
   150
	if(kind == PPM) {
slouken@25
   151
		/* 24-bit surface in R,G,B byte order */
slouken@320
   152
		surface = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 24,
slouken@25
   153
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
slouken@25
   154
					   0x000000ff, 0x0000ff00, 0x00ff0000,
slouken@25
   155
#else
slouken@25
   156
					   0x00ff0000, 0x0000ff00, 0x000000ff,
slouken@25
   157
#endif
slouken@25
   158
					   0);
slouken@25
   159
	} else {
slouken@25
   160
		/* load PBM/PGM as 8-bit indexed images */
slouken@320
   161
		surface = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 8,
slouken@25
   162
					   0, 0, 0, 0);
slouken@25
   163
	}
slouken@25
   164
	if ( surface == NULL )
slouken@25
   165
		ERROR("Out of memory");
slouken@25
   166
	bpl = width * surface->format->BytesPerPixel;
slouken@25
   167
	if(kind == PGM) {
slouken@25
   168
		SDL_Color *c = surface->format->palette->colors;
slouken@25
   169
		int i;
slouken@25
   170
		for(i = 0; i < 256; i++)
slouken@25
   171
			c[i].r = c[i].g = c[i].b = i;
slouken@25
   172
		surface->format->palette->ncolors = 256;
slouken@25
   173
	} else if(kind == PBM) {
slouken@25
   174
		/* for some reason PBM has 1=black, 0=white */
slouken@25
   175
		SDL_Color *c = surface->format->palette->colors;
slouken@25
   176
		c[0].r = c[0].g = c[0].b = 255;
slouken@25
   177
		c[1].r = c[1].g = c[1].b = 0;
slouken@25
   178
		surface->format->palette->ncolors = 2;
slouken@25
   179
		bpl = (width + 7) >> 3;
aschiffler@343
   180
		buf = (Uint8 *)SDL_malloc(bpl);
slouken@25
   181
		if(buf == NULL)
slouken@25
   182
			ERROR("Out of memory");
slouken@25
   183
	}
slouken@25
   184
slouken@25
   185
	/* Read the image into the surface */
aschiffler@343
   186
	row = (Uint8 *)surface->pixels;
slouken@25
   187
	for(y = 0; y < height; y++) {
slouken@25
   188
		if(ascii) {
slouken@25
   189
			int i;
slouken@25
   190
			if(kind == PBM) {
slouken@25
   191
				for(i = 0; i < width; i++) {
slouken@25
   192
					Uint8 ch;
slouken@25
   193
					do {
slouken@25
   194
						if(!SDL_RWread(src, &ch,
slouken@25
   195
							       1, 1))
slouken@25
   196
						       ERROR("file truncated");
slouken@25
   197
						ch -= '0';
slouken@25
   198
					} while(ch > 1);
slouken@25
   199
					row[i] = ch;
slouken@25
   200
				}
slouken@25
   201
			} else {
slouken@25
   202
				for(i = 0; i < bpl; i++) {
slouken@25
   203
					int c;
slouken@25
   204
					c = ReadNumber(src);
slouken@25
   205
					if(c < 0)
slouken@25
   206
						ERROR("file truncated");
slouken@25
   207
					row[i] = c;
slouken@25
   208
				}
slouken@25
   209
			}
slouken@25
   210
		} else {
slouken@25
   211
			Uint8 *dst = (kind == PBM) ? buf : row;
slouken@25
   212
			if(!SDL_RWread(src, dst, bpl, 1))
slouken@25
   213
				ERROR("file truncated");
slouken@25
   214
			if(kind == PBM) {
slouken@25
   215
				/* expand bitmap to 8bpp */
slouken@25
   216
				int i;
slouken@25
   217
				for(i = 0; i < width; i++) {
slouken@25
   218
					int bit = 7 - (i & 7);
slouken@25
   219
					row[i] = (buf[i >> 3] >> bit) & 1;
slouken@25
   220
				}
slouken@25
   221
			}
slouken@25
   222
		}
slouken@25
   223
		if(maxval < 255) {
slouken@25
   224
			/* scale up to full dynamic range (slow) */
slouken@25
   225
			int i;
slouken@25
   226
			for(i = 0; i < bpl; i++)
slouken@25
   227
				row[i] = row[i] * 255 / maxval;
slouken@25
   228
		}
slouken@25
   229
		row += surface->pitch;
slouken@25
   230
	}
slouken@25
   231
done:
slouken@367
   232
	SDL_free(buf);
slouken@25
   233
	if(error) {
slouken@236
   234
		SDL_RWseek(src, start, RW_SEEK_SET);
slouken@118
   235
		if ( surface ) {
slouken@118
   236
			SDL_FreeSurface(surface);
slouken@118
   237
			surface = NULL;
slouken@118
   238
		}
slouken@25
   239
		IMG_SetError(error);
slouken@25
   240
	}
slouken@25
   241
	return(surface);
slouken@25
   242
}
slouken@25
   243
slouken@25
   244
#else
slouken@25
   245
slouken@25
   246
/* See if an image is contained in a data source */
slouken@25
   247
int IMG_isPNM(SDL_RWops *src)
slouken@25
   248
{
slouken@25
   249
	return(0);
slouken@25
   250
}
slouken@25
   251
slouken@25
   252
/* Load a PNM type image from an SDL datasource */
slouken@25
   253
SDL_Surface *IMG_LoadPNM_RW(SDL_RWops *src)
slouken@25
   254
{
slouken@25
   255
	return(NULL);
slouken@25
   256
}
slouken@25
   257
slouken@25
   258
#endif /* LOAD_PNM */