--- Begin Message ---
Subject: |
Re: [ft] Memory Stomp problem in FT_Bitmap_Embolden |
Date: |
Mon, 08 Jan 2007 14:26:47 -0500 |
User-agent: |
Thunderbird 1.5.0.9 (X11/20061206) |
Hi -
I just checked out the latest version from CVS and the problem is still
there.
The code assumes that the new embolden'ed bitmap will have a equal or
larger pitch
than the existing bitmap.
Since you are making a bold version of the bitmap this would seem to
always be the case
However if the original bitmap has excess padding on the right then the
new bitmap can
turn out to be narrower than the original bitmap. Bitmaps produced by
the monochrome
renderer are always padded to the next 16 bit boundary so they many
times have extra
padding on the right. The pitch of the new bitmap ignores the pitch of
the original bitmap, the
new pitch is computed only from the width in pixels of the original
bitmap. So the new
bitmap gets minimum padding and ends up being smaller than the original
bitmap with extra
padding.
The loop which copies the scan lines always copies the number of bytes
in the original bitmaps pitch.
If the new bitmap is narrower than the original bitmap when the last
scan line of the bitmap is
copied from the old to the new it writes 1 or more bytes past the end of
allocated memory.
The memcpy at line 174 in ftbitmap.c moves pitch bytes into a bitmap
which can be pitch-1 bytes wide.
My test code is attached along with my output. The output shows that the
bold bitmap has a pitch of 3 while
the original bitmap has a pitch of 4. I don't have any problem running
this code on Linux, different malloc,
but in our embedded OS the bitmap free hits an assert.
Thanks, Ted Packard
FTPATH := /home/tpackard/freetype/cvs
#FTPATH := /home/tpackard/freetype/freetype-2.2.1
embold: embold.c $(FTPATH)/objs/.libs/libfreetype.a
gcc -o embold -I $(FTPATH)/include embold.c
$(FTPATH)/objs/.libs/libfreetype.a
#include <stdio.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_STROKER_H
#define TRUE 1
#define FALSE 0
#define ERROR_CHECK( s ) { \
if ( error ) { \
printf("Function %s returned %d\n", s, error ); \
exit( 1 ); \
} \
else { \
printf("%s success\n", s ); \
} \
}
struct Args {
char* fontFileName;
int pointSize;
int charCode;
};
static struct Args rtn;
static void error_exit() {
printf( "What, try embold charcode \n\t\t\t[ -f FileName ]\n\t\t\t[ -p
PointSize ]\n" );
exit( 1 );
}
// process command line arugments
struct Args *processArgs( int argc, char **argv ) {
rtn.fontFileName = "/usr/share/fonts/bitstream-vera/Vera.ttf";
rtn.pointSize = 40 << 6;
rtn.charCode = 65;
float ftemp;;
int ccode;
if ( argc < 2 )
error_exit();
argc--; // skip pgm name
argv++;
sscanf( *argv, "%x", &ccode );
rtn.charCode = ccode;
argc--; // skip charcode
argv++;
while( argc ) {
char *cmd = *argv;
argv++;
char *data = *argv;
argv++;
argc -= 2;
if ( cmd[0] != '-' )
error_exit();
int c = cmd[1];
switch( c ) {
case 'f':
rtn.fontFileName = data;
break;
case 'p':
sscanf( data, "%f", &ftemp );
rtn.pointSize = (int)( ( ftemp * 64.0 ) + 0.5 );
break;
}
}
return &rtn;
}
// Debug routine to dump an alpha mask bitmap to the screen as ascii hex values
void dumpMonoBitmap( FT_Bitmap *bm, int left, int top ) {
int x, y, bit;
int rows = bm->rows;
int width = bm->width;
int pitch = bm->pitch;
unsigned char *buffer = bm->buffer;
unsigned char *p = buffer;
unsigned char pixel;
printf("rows = %d, width = %d, pitch = %d, bufer = %p\n", rows, width,
pitch, buffer );
printf("left = %d top = %d\n", left, top );
for ( y = 0; y < rows; y++ ) {
for ( x = 0; x < pitch; x++ ) {
for ( bit = 0; bit < 8; bit++ ) {
int b = *p;
int v = b << bit;
if ( v & 0x80 )
printf(" *" );
else
printf(" ");
}
p++;
}
printf("\n");
}
}
main( int argc, char **argv ) {
FT_Library library;
FT_Face face;
FT_Error error;
FT_Glyph glyph;
int glyph_index;
struct Args *args = processArgs( argc, argv );
error = FT_Init_FreeType( &library );
ERROR_CHECK( "FT_Init_FreeType" );
error = FT_New_Face( library, args->fontFileName, 0, &face );
ERROR_CHECK( "FT_New_Face" );
error = FT_Set_Char_Size( face, 0, args->pointSize, 72, 72 );
ERROR_CHECK( "FT_Set_Char_Size" );
glyph_index = FT_Get_Char_Index( face, args->charCode );
error = glyph_index == 0;
ERROR_CHECK( "FT_Get_Char_Index" );
// load scale and hint the glyph's outline
error = FT_Load_Glyph( face, glyph_index, FT_LOAD_MONOCHROME );
ERROR_CHECK( "FT_Load_Glyph" );
error = FT_Render_Glyph( face->glyph, FT_RENDER_MODE_MONO );
ERROR_CHECK( "FT_Render_Glyph" );
dumpMonoBitmap( &(face->glyph->bitmap), 0, 0 );
int strength = 2 << 6;
error = FT_Bitmap_Embolden( library, &(face->glyph->bitmap), strength,
strength );
ERROR_CHECK( "FT_Bitmap_Embolden" );
dumpMonoBitmap( &(face->glyph->bitmap), 0, 0 );
error = FT_Done_Face( face );
ERROR_CHECK( "FT_Done_Face" );
error = FT_Done_FreeType( library );
ERROR_CHECK( "FT_Done_FreeType" );
}
FT_Init_FreeType success
FT_New_Face success
FT_Set_Char_Size success
FT_Get_Char_Index success
FT_Load_Glyph success
FT_Render_Glyph success
rows = 24, width = 20, pitch = 4, bufer = 0x8e2d5e8
left = 0 top = 0
* * * * * * * * *
* * * * * * * * * * * * *
* * * * * * * * * * * * * * *
* * * * * * * * *
* * * * * * * *
* * * * * * * *
* * * * * * *
* * * * * * * *
* * * * * * * *
* * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * *
* * * *
* * * *
* * * *
* * *
* * * *
* * * * *
* * * * * * *
* * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * *
* * * * * * * * * * *
FT_Bitmap_Embolden success
rows = 26, width = 22, pitch = 3, bufer = 0x8e2d650
left = 0 top = 0
* * * * * * * * * * *
* * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * *
* * * * * * * * * * * * * *
* * * * * * * * * * * * * *
* * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * *
* * * * * *
* * * * * *
* * * * * * *
* * * * * * *
* * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * *
* * * * * * * * * * * * *
FT_Done_Face success
FT_Done_FreeType success
--- End Message ---