[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[pygame] PATCH Segmentation fault when opening font from file object
When I tried to open a Font from a file object I got a segmentation fault:
import pygame
file = open("font.ttf", "rb")
font = pygame.font.Font(file, 12)
<-- Segmentation fault
I tried to debug src/font.c and I found the bug at Line 623-625:
Py_BEGIN_ALLOW_THREADS;
font = TTF_OpenFontIndexRW (rw, 1, fontsize, 0);
Py_END_ALLOW_THREADS;
I replaced it with how file objects in src/images.c are opened:
if (RWopsCheckPython (rw)) {
font = TTF_OpenFontIndexRW (rw, 1, fontsize, 0);
}
else
{
Py_BEGIN_ALLOW_THREADS;
font = TTF_OpenFontIndexRW (rw, 1, fontsize, 0);
Py_END_ALLOW_THREADS;
}
Now I don't get segmentation faults anymore. I hope that fixes the
problem properly.
I attached the new font.c and a patch to the email.
Some version information:
pygame: '1.9.1release'
Linux: 2.6.25.20-0.7-pae
freetype: 9.16.3
Regards,
Janosch Gräf
/*
pygame - Python Game Library
Copyright (C) 2000-2001 Pete Shinners
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Pete Shinners
pete@xxxxxxxxxxxx
*/
/*
* font module for pygame
*/
#define PYGAMEAPI_FONT_INTERNAL
#include "font.h"
#include <stdio.h>
#include <string.h>
#include "pygame.h"
#include "pgcompat.h"
#include "pygamedocs.h"
#include "structmember.h"
static PyTypeObject PyFont_Type;
static PyObject* PyFont_New (TTF_Font*);
#define PyFont_Check(x) ((x)->ob_type == &PyFont_Type)
static int font_initialized = 0;
#ifndef __SYMBIAN32__
static const char const *font_defaultname = "freesansbold.ttf";
static const char const *pkgdatamodule_name = "pygame.pkgdata";
static const char const *resourcefunc_name = "getResource";
#else
/// Symbian GCCE does not like the second const
static const char *font_defaultname = "freesansbold.ttf";
static const char *pkgdatamodule_name = "pygame.pkgdata";
static const char *resourcefunc_name = "getResource";
#endif
static PyObject*
font_resource (const char *filename)
{
PyObject* load_basicfunc = NULL;
PyObject* pkgdatamodule = NULL;
PyObject* resourcefunc = NULL;
PyObject* result = NULL;
#if PY3
PyObject* tmp;
#endif
pkgdatamodule = PyImport_ImportModule (pkgdatamodule_name);
if (!pkgdatamodule)
goto font_resource_end;
resourcefunc = PyObject_GetAttrString (pkgdatamodule, resourcefunc_name);
if (!resourcefunc)
goto font_resource_end;
result = PyObject_CallFunction (resourcefunc, "s", filename);
if (!result)
goto font_resource_end;
#if PY3
tmp = PyObject_GetAttrString (result, "name");
if (tmp != NULL) {
Py_DECREF (result);
result = tmp;
}
else {
PyErr_Clear ();
}
#else
if (PyFile_Check (result))
{
PyObject *tmp = PyFile_Name (result);
Py_INCREF (tmp);
Py_DECREF (result);
result = tmp;
}
#endif
font_resource_end:
Py_XDECREF (pkgdatamodule);
Py_XDECREF (resourcefunc);
Py_XDECREF (load_basicfunc);
return result;
}
static void
font_autoquit (void)
{
if (font_initialized)
{
font_initialized = 0;
TTF_Quit ();
}
}
static PyObject*
font_autoinit (PyObject* self)
{
if (!font_initialized)
{
PyGame_RegisterQuit (font_autoquit);
if (TTF_Init ())
return PyInt_FromLong (0);
font_initialized = 1;
}
return PyInt_FromLong (font_initialized);
}
static PyObject*
fontmodule_quit (PyObject* self)
{
font_autoquit ();
Py_RETURN_NONE;
}
static PyObject*
fontmodule_init (PyObject* self)
{
PyObject* result;
int istrue;
result = font_autoinit (self);
istrue = PyObject_IsTrue (result);
Py_DECREF (result);
if (!istrue)
return RAISE (PyExc_SDLError, SDL_GetError ());
Py_RETURN_NONE;
}
static PyObject*
get_init (PyObject* self)
{
return PyInt_FromLong (font_initialized);
}
/* font object methods */
static PyObject*
font_get_height (PyObject* self)
{
TTF_Font* font = PyFont_AsFont (self);
return PyInt_FromLong (TTF_FontHeight (font));
}
static PyObject*
font_get_descent (PyObject* self)
{
TTF_Font* font = PyFont_AsFont (self);
return PyInt_FromLong (TTF_FontDescent (font));
}
static PyObject*
font_get_ascent (PyObject* self)
{
TTF_Font* font = PyFont_AsFont (self);
return PyInt_FromLong (TTF_FontAscent (font));
}
static PyObject*
font_get_linesize (PyObject* self)
{
TTF_Font* font = PyFont_AsFont (self);
return PyInt_FromLong (TTF_FontLineSkip (font));
}
static PyObject*
font_get_bold (PyObject* self)
{
TTF_Font* font = PyFont_AsFont (self);
return PyInt_FromLong ((TTF_GetFontStyle (font) & TTF_STYLE_BOLD) != 0);
}
static PyObject*
font_set_bold (PyObject* self, PyObject* args)
{
TTF_Font* font = PyFont_AsFont (self);
int style, val;
if (!PyArg_ParseTuple (args, "i", &val))
return NULL;
style = TTF_GetFontStyle (font);
if (val)
style |= TTF_STYLE_BOLD;
else
style &= ~TTF_STYLE_BOLD;
TTF_SetFontStyle (font, style);
Py_RETURN_NONE;
}
static PyObject*
font_get_italic (PyObject* self)
{
TTF_Font* font = PyFont_AsFont (self);
return PyInt_FromLong ((TTF_GetFontStyle (font) & TTF_STYLE_ITALIC) != 0);
}
static PyObject*
font_set_italic (PyObject* self, PyObject* args)
{
TTF_Font* font = PyFont_AsFont (self);
int style, val;
if (!PyArg_ParseTuple (args, "i", &val))
return NULL;
style = TTF_GetFontStyle (font);
if(val)
style |= TTF_STYLE_ITALIC;
else
style &= ~TTF_STYLE_ITALIC;
TTF_SetFontStyle (font, style);
Py_RETURN_NONE;
}
static PyObject*
font_get_underline (PyObject* self)
{
TTF_Font* font = PyFont_AsFont (self);
return PyInt_FromLong
((TTF_GetFontStyle (font) & TTF_STYLE_UNDERLINE) != 0);
}
static PyObject*
font_set_underline (PyObject* self, PyObject* args)
{
TTF_Font* font = PyFont_AsFont (self);
int style, val;
if (!PyArg_ParseTuple (args, "i", &val))
return NULL;
style = TTF_GetFontStyle (font);
if(val)
style |= TTF_STYLE_UNDERLINE;
else
style &= ~TTF_STYLE_UNDERLINE;
TTF_SetFontStyle (font, style);
Py_RETURN_NONE;
}
static PyObject*
font_render (PyObject* self, PyObject* args)
{
TTF_Font* font = PyFont_AsFont (self);
int aa;
PyObject* text, *final;
PyObject* fg_rgba_obj, *bg_rgba_obj = NULL;
Uint8 rgba[4];
SDL_Surface* surf;
SDL_Color foreg, backg;
int just_return;
just_return = 0;
if (!PyArg_ParseTuple (args, "OiO|O", &text, &aa, &fg_rgba_obj,
&bg_rgba_obj))
return NULL;
if (!RGBAFromColorObj (fg_rgba_obj, rgba))
return RAISE (PyExc_TypeError, "Invalid foreground RGBA argument");
foreg.r = rgba[0];
foreg.g = rgba[1];
foreg.b = rgba[2];
if (bg_rgba_obj)
{
if (!RGBAFromColorObj (bg_rgba_obj, rgba))
return RAISE (PyExc_TypeError, "Invalid background RGBA argument");
backg.r = rgba[0];
backg.g = rgba[1];
backg.b = rgba[2];
backg.unused = 0;
}
else
{
backg.r = 0;
backg.g = 0;
backg.b = 0;
backg.unused = 0;
}
if (!PyObject_IsTrue (text))
{
int height = TTF_FontHeight (font);
surf = SDL_CreateRGBSurface (SDL_SWSURFACE, 1, height, 32,
0xff<<16, 0xff<<8, 0xff, 0);
if (!surf)
return RAISE (PyExc_SDLError, "SDL_CreateRGBSurface failed");
if (bg_rgba_obj)
{
Uint32 c = SDL_MapRGB (surf->format, backg.r, backg.g, backg.b);
SDL_FillRect (surf, NULL, c);
}
else
SDL_SetColorKey (surf, SDL_SRCCOLORKEY, 0);
just_return = 1;
}
else if (PyUnicode_Check (text))
{
PyObject* strob = PyUnicode_AsEncodedString (text, "utf-8", "replace");
char *astring = Bytes_AsString (strob);
if (aa)
{
if (!bg_rgba_obj)
surf = TTF_RenderUTF8_Blended (font, astring, foreg);
else
surf = TTF_RenderUTF8_Shaded (font, astring, foreg, backg);
}
else
surf = TTF_RenderUTF8_Solid (font, astring, foreg);
Py_DECREF (strob);
}
else if (Bytes_Check (text))
{
char* astring = Bytes_AsString (text);
if (aa)
{
if (!bg_rgba_obj)
surf = TTF_RenderText_Blended (font, astring, foreg);
else
surf = TTF_RenderText_Shaded (font, astring, foreg, backg);
}
else
surf = TTF_RenderText_Solid (font, astring, foreg);
}
else
return RAISE (PyExc_TypeError, "text must be a string or unicode");
if (!surf)
return RAISE (PyExc_SDLError, TTF_GetError());
if (!aa && bg_rgba_obj && !just_return) /*turn off transparancy*/
{
SDL_SetColorKey (surf, 0, 0);
surf->format->palette->colors[0].r = backg.r;
surf->format->palette->colors[0].g = backg.g;
surf->format->palette->colors[0].b = backg.b;
}
final = PySurface_New (surf);
if (!final)
SDL_FreeSurface (surf);
return final;
}
static PyObject*
font_size (PyObject* self, PyObject* args)
{
TTF_Font* font = PyFont_AsFont (self);
int w, h;
PyObject* text;
if (!PyArg_ParseTuple (args, "O", &text))
return NULL;
if (PyUnicode_Check (text))
{
//PyObject* strob = PyUnicode_AsEncodedObject(text, "utf-8", "replace");
PyObject* strob = PyUnicode_AsEncodedString (text, "utf-8", "replace");
char *string = Bytes_AsString (strob);
TTF_SizeUTF8 (font, string, &w, &h);
Py_DECREF (strob);
}
else if (Bytes_Check (text))
{
char* string = Bytes_AsString (text);
TTF_SizeText (font, string, &w, &h);
}
else
return RAISE (PyExc_TypeError, "text must be a string or unicode");
return Py_BuildValue ("(ii)", w, h);
}
static PyObject*
font_metrics (PyObject* self, PyObject* args)
{
TTF_Font *font = PyFont_AsFont (self);
PyObject *list;
PyObject *textobj;
int length;
int i;
int minx;
int maxx;
int miny;
int maxy;
int advance;
void *buf;
int isunicode = 0;
if (!PyArg_ParseTuple (args, "O", &textobj))
return NULL;
if (PyUnicode_Check (textobj))
{
buf = PyUnicode_AsUnicode (textobj);
isunicode = 1;
}
else if (Bytes_Check (textobj))
buf = Bytes_AsString (textobj);
else
return RAISE (PyExc_TypeError, "text must be a string or unicode");
if (!buf)
return NULL;
if (isunicode)
length = PyUnicode_GetSize (textobj);
else
length = Bytes_Size (textobj);
if (length == 0)
Py_RETURN_NONE;
list = PyList_New (length);
if (isunicode)
{
for (i = 0; i < length; i++)
{
/* TODO:
* TTF_GlyphMetrics() seems to returns a value for any character,
* using the default invalid character, if the char is not found.
*/
if (TTF_GlyphMetrics (font, (Uint16) ((Py_UNICODE*) buf)[i], &minx,
&maxx, &miny, &maxy, &advance) == -1)
{
Py_INCREF (Py_None);
PyList_SetItem (list, i, Py_None); /* No matching metrics. */
}
else
{
PyList_SetItem (list, i, Py_BuildValue
("(iiiii)", minx, maxx, miny, maxy, advance));
}
}
}
else
{
for (i = 0; i < length; i++)
{
/* TODO:
* TTF_GlyphMetrics() seems to returns a value for any character,
* using the default invalid character, if the char is not found.
*/
if (TTF_GlyphMetrics (font, (Uint16) ((char*) buf)[i], &minx,
&maxx, &miny, &maxy, &advance) == -1)
{
Py_INCREF (Py_None);
PyList_SetItem (list, i, Py_None); /* No matching metrics. */
}
else
{
PyList_SetItem (list, i, Py_BuildValue
("(iiiii)", minx, maxx, miny, maxy, advance));
}
}
}
return list;
}
static PyMethodDef font_methods[] =
{
{ "get_height", (PyCFunction) font_get_height, METH_NOARGS,
DOC_FONTGETHEIGHT },
{ "get_descent", (PyCFunction) font_get_descent, METH_NOARGS,
DOC_FONTGETDESCENT },
{ "get_ascent", (PyCFunction) font_get_ascent, METH_NOARGS,
DOC_FONTGETASCENT },
{ "get_linesize", (PyCFunction) font_get_linesize, METH_NOARGS,
DOC_FONTGETLINESIZE },
{ "get_bold", (PyCFunction) font_get_bold, METH_NOARGS,
DOC_FONTGETBOLD },
{ "set_bold", font_set_bold, METH_VARARGS, DOC_FONTSETBOLD },
{ "get_italic", (PyCFunction) font_get_italic, METH_NOARGS,
DOC_FONTGETITALIC },
{ "set_italic", font_set_italic, METH_VARARGS, DOC_FONTSETITALIC },
{ "get_underline", (PyCFunction) font_get_underline, METH_NOARGS,
DOC_FONTGETUNDERLINE },
{ "set_underline", font_set_underline, METH_VARARGS, DOC_FONTSETUNDERLINE },
{ "metrics", font_metrics, METH_VARARGS, DOC_FONTMETRICS },
{ "render", font_render, METH_VARARGS, DOC_FONTRENDER },
{ "size", font_size, METH_VARARGS, DOC_FONTSIZE },
{ NULL, NULL, 0, NULL }
};
/*font object internals*/
static void
font_dealloc (PyFontObject* self)
{
TTF_Font* font = PyFont_AsFont (self);
if (font && font_initialized)
TTF_CloseFont (font);
if (self->weakreflist)
PyObject_ClearWeakRefs ((PyObject*) self);
Py_TYPE(self)->tp_free ((PyObject*) self);
}
static int
font_init (PyFontObject *self, PyObject *args, PyObject *kwds)
{
int fontsize;
TTF_Font* font = NULL;
PyObject* fileobj;
self->font = NULL;
if (!PyArg_ParseTuple (args, "Oi", &fileobj, &fontsize))
return -1;
if (!font_initialized)
{
RAISE (PyExc_SDLError, "font not initialized");
return -1;
}
Py_INCREF (fileobj);
if (fontsize <= 1)
fontsize = 1;
if (fileobj == Py_None)
{
fileobj = font_resource (font_defaultname);
if (!fileobj)
{
char error[1024];
PyOS_snprintf (error, 1024, "default font not found '%s'",
font_defaultname);
RAISE (PyExc_RuntimeError, error);
goto error;
}
fontsize = (int) (fontsize * .6875);
if (fontsize <= 1)
fontsize = 1;
}
if (PyUnicode_Check (fileobj)) {
PyObject* tmp = PyUnicode_AsASCIIString (fileobj);
if (tmp == NULL) {
goto error;
}
fileobj = tmp;
}
if (Bytes_Check (fileobj))
{
FILE* test;
char* filename = Bytes_AsString (fileobj);
if (!filename) {
goto error;
}
/*check if it is a valid file, else SDL_ttf segfaults*/
test = fopen (filename, "rb");
if(!test)
{
PyObject *tmp = NULL;
if (!strcmp (filename, font_defaultname)) {
tmp = font_resource (font_defaultname);
}
if (!tmp)
{
PyErr_SetString (PyExc_IOError,
"unable to read font filename");
goto error;
}
Py_DECREF (fileobj);
fileobj = tmp;
}
else
{
fclose (test);
Py_BEGIN_ALLOW_THREADS;
font = TTF_OpenFont(filename, fontsize);
Py_END_ALLOW_THREADS;
}
}
if (!font)
{
SDL_RWops *rw;
rw = RWopsFromPython (fileobj);
if (!rw)
{
goto error;
}
if (RWopsCheckPython (rw)) {
font = TTF_OpenFontIndexRW (rw, 1, fontsize, 0);
}
else
{
Py_BEGIN_ALLOW_THREADS;
font = TTF_OpenFontIndexRW (rw, 1, fontsize, 0);
Py_END_ALLOW_THREADS;
}
#else
RAISE (PyExc_NotImplementedError,
"nonstring fonts require SDL_ttf-2.0.6");
goto error;
#endif
}
if (!font)
{
RAISE (PyExc_RuntimeError, SDL_GetError ());
goto error;
}
Py_DECREF (fileobj);
self->font = font;
return 0;
error:
Py_DECREF (fileobj);
return -1;
}
static PyTypeObject PyFont_Type =
{
TYPE_HEAD (NULL, 0)
"pygame.font.Font",
sizeof(PyFontObject),
0,
(destructor)font_dealloc,
0,
0, /*getattr*/
0,
0,
0,
0,
NULL,
0,
(hashfunc)NULL,
(ternaryfunc)NULL,
(reprfunc)NULL,
0L,0L,0L,
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
DOC_PYGAMEFONTFONT, /* Documentation string */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
offsetof(PyFontObject, weakreflist), /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
font_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
(initproc)font_init, /* tp_init */
0, /* tp_alloc */
0, /* tp_new */
};
//PyType_GenericNew, /* tp_new */
/*font module methods*/
static PyObject*
get_default_font (PyObject* self)
{
return Text_FromUTF8 (font_defaultname);
}
static PyMethodDef _font_methods[] =
{
{ "__PYGAMEinit__", (PyCFunction) font_autoinit, METH_NOARGS,
"auto initialize function for font" },
{ "init", (PyCFunction) fontmodule_init, METH_NOARGS, DOC_PYGAMEFONTINIT },
{ "quit", (PyCFunction) fontmodule_quit, METH_NOARGS, DOC_PYGAMEFONTQUIT },
{ "get_init", (PyCFunction) get_init, METH_NOARGS, DOC_PYGAMEFONTGETINIT },
{ "get_default_font", (PyCFunction) get_default_font, METH_NOARGS,
DOC_PYGAMEFONTGETDEFAULTFONT },
{ NULL, NULL, 0, NULL }
};
static PyObject*
PyFont_New (TTF_Font* font)
{
PyFontObject* fontobj;
if (!font)
return RAISE (PyExc_RuntimeError, "unable to load font.");
fontobj = (PyFontObject *) PyFont_Type.tp_new (&PyFont_Type, NULL, NULL);
if (fontobj)
fontobj->font = font;
return (PyObject*) fontobj;
}
MODINIT_DEFINE (font)
{
PyObject *module, *apiobj;
static void* c_api[PYGAMEAPI_FONT_NUMSLOTS];
#if PY3
static struct PyModuleDef _module = {
PyModuleDef_HEAD_INIT,
"font",
DOC_PYGAMEFONT,
-1,
_font_methods,
NULL, NULL, NULL, NULL
};
#endif
PyFONT_C_API[0] = PyFONT_C_API[0]; /*clean an unused warning*/
/* imported needed apis; Do this first so if there is an error
the module is not loaded.
*/
import_pygame_base ();
if (PyErr_Occurred ()) {
MODINIT_ERROR;
}
import_pygame_color ();
if (PyErr_Occurred ()) {
MODINIT_ERROR;
}
import_pygame_surface ();
if (PyErr_Occurred ()) {
MODINIT_ERROR;
}
import_pygame_rwobject ();
if (PyErr_Occurred ()) {
MODINIT_ERROR;
}
/* type preparation */
if (PyType_Ready (&PyFont_Type) < 0) {
MODINIT_ERROR;
}
PyFont_Type.tp_new = PyType_GenericNew;
#if PY3
module = PyModule_Create (&_module);
#else
module = Py_InitModule3 (MODPREFIX "font",
_font_methods,
DOC_PYGAMEFONT);
#endif
if (module == NULL) {
MODINIT_ERROR;
}
Py_INCREF ((PyObject*) &PyFont_Type);
if (PyModule_AddObject (module,
"FontType",
(PyObject *) &PyFont_Type) == -1) {
Py_DECREF ((PyObject *) &PyFont_Type);
DECREF_MOD (module);
MODINIT_ERROR;
}
Py_INCREF ((PyObject*) &PyFont_Type);
if (PyModule_AddObject (module,
"Font",
(PyObject *) &PyFont_Type) == -1) {
Py_DECREF ((PyObject *) &PyFont_Type);
DECREF_MOD (module);
MODINIT_ERROR;
}
/* export the c api */
c_api[0] = &PyFont_Type;
c_api[1] = PyFont_New;
c_api[2] = &font_initialized;
apiobj = PyCObject_FromVoidPtr (c_api, NULL);
if (apiobj == NULL) {
DECREF_MOD (module);
MODINIT_ERROR;
}
if (PyModule_AddObject (module, PYGAMEAPI_LOCAL_ENTRY, apiobj) == -1) {
Py_DECREF (apiobj);
DECREF_MOD (module);
MODINIT_ERROR;
}
MODINIT_RETURN (module);
}
--- font.c.old 2009-06-17 01:18:34.000000000 +0200
+++ font.c 2010-08-06 01:02:25.000000000 +0200
@@ -611,18 +612,25 @@ font_init (PyFontObject *self, PyObject
Py_END_ALLOW_THREADS;
}
}
+
if (!font)
{
-#ifdef TTF_MAJOR_VERSION
SDL_RWops *rw;
rw = RWopsFromPython (fileobj);
if (!rw)
{
goto error;
}
+
+ if (RWopsCheckPython (rw)) {
+ font = TTF_OpenFontIndexRW (rw, 1, fontsize, 0);
+ }
+ else
+ {
Py_BEGIN_ALLOW_THREADS;
font = TTF_OpenFontIndexRW (rw, 1, fontsize, 0);
Py_END_ALLOW_THREADS;
+ }
#else
RAISE (PyExc_NotImplementedError,
"nonstring fonts require SDL_ttf-2.0.6");