Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

TTF_OpenFontRW does not read in the full data? #164

Closed
AstraLuma opened this issue Apr 21, 2020 · 8 comments · Fixed by #200
Closed

TTF_OpenFontRW does not read in the full data? #164

AstraLuma opened this issue Apr 21, 2020 · 8 comments · Fixed by #200

Comments

@AstraLuma
Copy link

I'm getting a segfault when using TTF_OpenFontRW with rw_from_object, but down in TTF_RenderUTF8_Blended.

https://github.com/astronouth7303/pursuedpybear/blob/d2cf78097b29f01f18c6bc948984dc5095de535e/ppb/systems/text.py#L42-L54

https://github.com/astronouth7303/pursuedpybear/blob/d2cf78097b29f01f18c6bc948984dc5095de535e/ppb/systems/text.py#L93-L98

These are running in the context of concurrent.futures.

I'm getting the backtrace of (from gdb):

#0  0x00000000009198a0 in RLocktype ()
#1  0x00007ffff768f409 in RWread (stream=<optimized out>, offset=<optimized out>, buffer=0x0, count=0) at SDL_ttf.c:247
#2  0x00007ffff546c43b in  () at /usr/lib/x86_64-linux-gnu/libfreetype.so.6
#3  0x00007ffff547cd08 in  () at /usr/lib/x86_64-linux-gnu/libfreetype.so.6
#4  0x00007ffff5482e7e in  () at /usr/lib/x86_64-linux-gnu/libfreetype.so.6
#5  0x00007ffff5489856 in  () at /usr/lib/x86_64-linux-gnu/libfreetype.so.6
#6  0x00007ffff546eb14 in FT_Load_Glyph () at /usr/lib/x86_64-linux-gnu/libfreetype.so.6
#7  0x00007ffff768f966 in Load_Glyph (want=16, cached=<optimized out>, idx=<optimized out>, font=0x7fffa8001580) at SDL_ttf.c:552
#8  Find_GlyphByIndex (want=16, idx=<optimized out>, font=0x7fffa8001580) at SDL_ttf.c:874
#9  Find_Glyph (font=font@entry=0x7fffa8001580, ch=<optimized out>, want=want@entry=16) at SDL_ttf.c:881
#10 0x00007ffff769025c in TTF_SizeUTF8_Internal (font=font@entry=0x7fffa8001580, text=<optimized out>, 
    text@entry=0x7ffff4288aa0 "hi", w=w@entry=0x7fffbb7fcb50, h=h@entry=0x7fffbb7fcb54, xstart=xstart@entry=0x7fffbb7fcb48, ystart=ystart@entry=0x7fffbb7fcb4c) at SDL_ttf.c:1195
#11 0x00007ffff76919ee in TTF_RenderUTF8_Blended (font=0x7fffa8001580, text=<optimized out>, fg=...) at SDL_ttf.c:1630
#12 0x00007ffff7fbeccd in  () at /usr/lib/x86_64-linux-gnu/libffi.so.7
#13 0x00007ffff7fbe25a in  () at /usr/lib/x86_64-linux-gnu/libffi.so.7
#14 0x00007ffff7a823ed in _call_function_pointer
    (argcount=3, resmem=0x7fffbb7fce10, restype=<optimized out>, atypes=0x7fffbb7fcdd0, avalues=0x7fffbb7fcdf0, pProc=0x7ffff7691980 <TTF_RenderUTF8_Blended>, flags=<optimized out>) at ./Modules/_ctypes/callproc.c:871
#15 _ctypes_callproc
    (pProc=0x7ffff7691980 <TTF_RenderUTF8_Blended>, argtuple=<optimized out>, flags=<optimized out>, argtypes=<optimized out>, restype=<_ctypes.PyCPointerType at remote 0xb1cc60>, checker=0x0) at ./Modules/_ctypes/callproc.c:1199
#16 0x00007ffff7a82b0c in PyCFuncPtr_call
    (self=self@entry=0x7ffff5545b80, inargs=inargs@entry=(<LP_TTF_Font at remote 0x7ffff4d7ddc0>, b'hi', <SDL_Color at remote 0x7ffff4d7df40>), kwds=kwds@entry={}) at ./Modules/_ctypes/_ctypes.c:4201
#17 0x00000000005eec4e in PyObject_Call
    (callable=<_FuncPtr(__name__='TTF_RenderUTF8_Blended') at remote 0x7ffff5545b80>, args=(<LP_TTF_Font at remote 0x7ffff4d7ddc0>, b'hi', <SDL_Color at remote 0x7ffff4d7df40>), kwargs={}) at ../Objects/call.c:245

Note that frame 0 is from python.

@AstraLuma
Copy link
Author

AstraLuma commented Apr 21, 2020

This is less of a "this should behave differently" bug, because ctypes, and more of a "this is not documented in pysdl2 or sdl, and behaves differently from every other *RW function"

@AstraLuma
Copy link
Author

ALSO, freetype is not threadsafe:

[Since 2.5.6] In multi-threaded applications it is easiest to use one FT_Library object per thread. In case this is too cumbersome, a single FT_Library object across threads is possible also, as long as a mutex lock is used around FT_New_Face and FT_Done_Face.

Which I assume translates to TTF_OpenFont* and TTF_CloseFont.

@a-hurst
Copy link
Member

a-hurst commented Apr 24, 2020

Just to be clear, the situation causing a segfault is that you're trying to render the text in a different thread than the one you've loaded the font with? I've never tried to use pysdl2 in a multithreaded way before, but if ctypes and/or the underlying libraries themselves don't support this I guess it should be documented clearly somewhere.

Generally, pysdl2 has tried to leave as much documentation as possible to the official libsdl.org documentation to avoid issues with duplicating effort and keeping up to date, but this approach also puts us in a bad place when certain functions/behaviours need extra documentation or examples for Python use that the C docs don't cover. I actually have some of the ttf/mixer/image docs ported over to .rst already, so maybe this will be the impetus to finish those up and merge them into master so a proper warning can be added.

@AstraLuma
Copy link
Author

The original issue was that rwops was getting freed while the font was still open, which is different from the other resources in the sdl library family. Sorry I didn't make that clear.

@a-hurst
Copy link
Member

a-hurst commented Apr 26, 2020

Ah got it, thanks for the clarification! Have you checked to make sure the "freesrc" argument of the TTF_OpenFontRW function isn't getting enabled by accident somehow? The TTF docs say that any non-zero value passed to the second argument will cause TTF_OpenFontRW to behave like you're describing. Quickly glancing at your source code it looks like you're passing False to that argument now, but you might want to try using 0 explicitly in case ctypes is being weird about type conversions (you can also use the SDL_FALSE constant if you want to keep your code more readable).

@AstraLuma
Copy link
Author

Nope, I fixed the issue by keeping the RWops around, and a few other things.

See ppb/pursuedpybear@dca98ef and ppb/pursuedpybear@df30409

@a-hurst
Copy link
Member

a-hurst commented Apr 26, 2020

Ahhhhh, I get it: so SDL2_ttf requires that the RW object you use to create a font is kept in memory for when you try to render some text with that font. You're right, that's pretty odd behaviour and it should probably be documented somewhere by py-sdl2 to avoid future confusion. Thanks for bringing this to our attention!

@AstraLuma
Copy link
Author

In addition, I believe if you free a font after you're released the system (called TTF_CloseFont after the last TTF_Quit), it will also crash.

This doesn't sound like a big deal, and I didn't realize PPB was doing it until I triggered it, but yup. A naive smart pointer wrapping TTF_Font will trigger a crash in SDL_ttf and no other SDL code.

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants