Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Crash with an error: munmap_chunk(): invalid pointer #4225

Closed
catcombo opened this issue Nov 21, 2019 · 29 comments
Closed

Crash with an error: munmap_chunk(): invalid pointer #4225

catcombo opened this issue Nov 21, 2019 · 29 comments
Projects

Comments

@catcombo
Copy link

catcombo commented Nov 21, 2019

What did you do?

I was faced a problem when using arcade library. It uses Pillow under the hood to work with images. When I tried to draw game score text, I got random crash. I localized the problem and found out that crash is related to the way the Pillow works with font and frees up a resources.

What actually happened?

Crash with an error:

munmap_chunk(): invalid pointer
Process finished with exit code 134 (interrupted by signal 6: SIGABRT)

What are your OS, Python and Pillow versions?

  • OS: Fedora 30
  • Python: 3.7.5
  • Pillow: 6.2.1

Code example

Crashing code example (munmap_chunk(): invalid pointer):

import PIL.Image
import PIL.ImageDraw
import PIL.ImageFont


while True:
    image = PIL.Image.new("RGBA", (10, 10))
    draw = PIL.ImageDraw.Draw(image)
    font = PIL.ImageFont.truetype("Arial.ttf", 12)
    print(draw.multiline_textsize("Sample", font=font))

Works without any problem:

import PIL.Image
import PIL.ImageDraw
import PIL.ImageFont


font = PIL.ImageFont.truetype("Arial.ttf", 12)

while True:
    image = PIL.Image.new("RGBA", (10, 10))
    draw = PIL.ImageDraw.Draw(image)
    
    print(draw.multiline_textsize("Sample", font=font))
@radarhere
Copy link
Member

How many iterations of the loop does it take to reproduce the problem?

@catcombo
Copy link
Author

catcombo commented Nov 22, 2019

@radarhere 28 iterations. Interesting fact: when I changed the code to:

import PIL.Image
import PIL.ImageDraw
import PIL.ImageFont

i = 0
while True:
    i += 1
    print(i)
    image = PIL.Image.new("RGBA", (10, 10))
    draw = PIL.ImageDraw.Draw(image)
    font = PIL.ImageFont.truetype("Arial.ttf", 12)
    print(draw.multiline_textsize("Sample", font=font))

it start to crash on 218 iteration.

@Poikilos
Copy link

Poikilos commented Jan 29, 2020

I can confirm the issue (which is apparently the same) on:

  • OS: Fedora 31
  • Python: 3.7.6
  • Pillow version: 7.0.0

I can reproduce the issue above using the code above.

Also, the results below only serve as a confirmation but don't offer new information other than that different types of crashes ("heisenbugs") causing core dumps occur intermittently in practical use.

details It is hard to reproduce in my case. Considering the original issue report above, the reason mine is hard to reproduce may be that in my library I only load the font object once then cache it (I cache the return of ImageFont.truetype):

I could get any of the following, but always when using the font to draw (on _d.text( where _d is an ImageDraw.Draw lock, which is after self.blab("* drawing text ' which shows when using the --verbose=True option):

  1. Segmentation fault (core dumped)

or 2.

corrupted size vs. prev_size
Aborted (core dumped)

or 3.

munmap_chunk(): invalid pointer
lcd-fb.service: Main process exited, code=dumped, status=6/ABRT
lcd-fb.service: Failed with result 'core-dump'.

@cwt
Copy link

cwt commented Mar 30, 2020

I have this problem too, but it only happened if I install Pillow from wheel file or just run pip install Pillow, which will use wheel file by default.

If I install with this command pip install --compile --install-option=-O1 Pillow, it will build from source and the problem is gone. I test it many times still working perfectly.

My environment: Fedora 31, Python 3.6 (in venv), Pillow 7.0.0

@hugovk
Copy link
Member

hugovk commented Mar 30, 2020

I note Fedora is a common factor in these three reports.

@cwt
Copy link

cwt commented Mar 31, 2020

I note Fedora is a common factor in these three reports.

It also happened on CentOS 8 too, the problem also gone if I install from source instead of wheel file.

@stephenfin
Copy link

stephenfin commented Apr 3, 2020

Another Fedora 31 user here with the same issue. CentOS 8 is based off Fedora 28 (like RHEL 8) so I suspect this might affect older Fedora versions. That or something's been backported. As with @cwt, installing the non-binary package (pip install --no-binary=Pillow Pillow==6.2.0 --force) resolves this issue.

Edit: For anyone else stumbling upon this, I needed to install the following packages to build things correctly:

sudo dnf install libjpeg-devel zlib-devel freetype-devel

@simenheg
Copy link

I'm experiencing the same problem on Debian. The original code example crashes on the third iteration here (though with another font: Vera.ttf).

  • OS: Debian bullseye (testing)
  • Python: 3.7.7
  • Pillow: 7.1.1

@Borroot
Copy link

Borroot commented Oct 14, 2020

I have the same problem on Arch Linux using a Verdana.ttf font.

  • OS: Arch Linux 5.8.14-arch1-1
  • Python: 3.8.6
  • Pillow: 7.2.0

Solved with compiling myself pip install --compile --install-option=-O1 Pillow.

@jonaswinkler
Copy link

jonaswinkler commented Nov 2, 2020

Still an issue in 8.0.1. on Python 3.8.6. OS Archlinux, x86_64.

from PIL import Image, ImageDraw, ImageFont

for try_n in range(100):
    print(try_n+1)
    text = "TEXT"
    img = Image.new("RGBA", (100, 100))
    draw = ImageDraw.Draw(img)
    font = ImageFont.truetype("/usr/share/fonts/liberation/LiberationSerif-Regular.ttf", 15)
    draw.text((5,5), text, font=font)

Fails consistently on the 3rd try. Font Size or actual text don't matter. If the font is removed, it works. Issue persists with different fonts, although it fails on different tries for each font (but is still consistent for every font I tried, i.e., NimbusSans-Regular fails on second attempt).

Noteworthy: Works flawlessly on Raspberry Pi 3!

@DearRude
Copy link

I also got this issue

  • Pillow 8.0.1.
  • Python 3.8.6.
  • OS Archlinux, x86_64.

It happens randomly but mostly on 3rd or 4th iteration.

@anotherbugmaster
Copy link

Also confirm the issue.

  • Pillow 8.0.1
  • Python 3.7.9
  • OS Archlinux, x86_64

@wiredfool
Copy link
Member

wiredfool commented Nov 21, 2020

Recent reporters, are you doing this with the shipped wheels or did you compile yourself?

@anotherbugmaster
Copy link

Shipped. Works fine with pip install --compile --install-option=-O1 Pillow

@stephenfin
Copy link

Yup, shipped from PyPI

@wiredfool
Copy link
Member

Ok, I can replicate this on Ubuntu 20.04 with the shipped image. Of course, it doesn't do it with builds on that machine. It does appear that there's something funky going on with the Font Face references through raqm/harfbuzz/freetype.

I'm seeing invalid read/writes on:

==83319== Invalid read of size 4
==83319==    at 0x7881FF0: FT_Reference_Face (in /usr/lib/x86_64-linux-gnu/libfreetype.so.6.17.1)
==83319==    by 0x786D881: _raqm_set_freetype_face (raqm.c:672)
...
==83319== Invalid read of size 4
==83319==    at 0x7881FF0: FT_Reference_Face (in /usr/lib/x86_64-linux-gnu/libfreetype.so.6.17.1)
==83319==    by 0x7A0114C: hb_ft_font_create_referenced (in /usr/lib/x86_64-linux-gnu/libharfbuzz.so.0.20600.4)
==83319==    by 0x786D8BF: _raqm_create_hb_font.isra.0 (raqm.c:633)
...
==83319== Invalid read of size 4
==83319==    at 0x788A2E0: FT_Done_Face (in /usr/lib/x86_64-linux-gnu/libfreetype.so.6.17.1)
==83319==    by 0x786D789: _raqm_free_text_info.isra.0.part.0 (raqm.c:246)
==83319==    by 0x786DA05: _raqm_free_text_info (raqm.c:240)
==83319==    by 0x786DA05: raqm_destroy (raqm.c:370)
...
==83319== Invalid read of size 4
==83319==    at 0x788A2E0: FT_Done_Face (in /usr/lib/x86_64-linux-gnu/libfreetype.so.6.17.1)
==83319==    by 0x79533FD: hb_blob_destroy (in /usr/lib/x86_64-linux-gnu/libharfbuzz.so.0.20600.4)
==83319==    by 0x795A46F: ??? (in /usr/lib/x86_64-linux-gnu/libharfbuzz.so.0.20600.4)
==83319==    by 0x795AA5E: hb_face_destroy (in /usr/lib/x86_64-linux-gnu/libharfbuzz.so.0.20600.4)
==83319==    by 0x7967F90: hb_font_destroy (in /usr/lib/x86_64-linux-gnu/libharfbuzz.so.0.20600.4)
==83319==    by 0x786DA2A: _raqm_free_runs (raqm.c:347)
==83319==    by 0x786DA2A: raqm_destroy (raqm.c:371)

which leads to:

Traceback (most recent call last):
  File "4225_unmap.py", line 11, in <module>
    draw.text((5,5), text, font=font)
  File "/home/ubuntu/vpy38-dbg2/lib/python3.8/site-packages/PIL/ImageDraw.py", line 379, in text
    draw_text(ink)
  File "/home/ubuntu/vpy38-dbg2/lib/python3.8/site-packages/PIL/ImageDraw.py", line 324, in draw_text
    mask, offset = font.getmask2(
  File "/home/ubuntu/vpy38-dbg2/lib/python3.8/site-packages/PIL/ImageFont.py", line 651, in getmask2
    size, offset = self.font.getsize(
OSError: invalid face handle
==83319== Invalid read of size 8

And then it fails with a Segfault. This doesn't happen with a locally compiled version here, nor does valgrind trigger on anything in PIL. I've got all of the dependencies installed here, so we have the all of the same dependencies, though not necessarily the same versions. Stepping through, they appear to be following the same code paths.

In the production versions, it's not clear that the font faces are invalid, but enough of the code has been optimized out that I'm not sure that things are behaving correctly or not. But they're not obviously wrong.

So a few things need to happen to narrow this down.

  • I've got to get a way to reproduce this in builds where I can change the code.
  • I need better visibility into the FT_Font->internal structure, especially the reference count field, which I'm pretty sure are the invalid read/write target.

@nulano
Copy link
Contributor

nulano commented Nov 24, 2020

If this is only happening with Raqm, I wonder if it is related to #3066, which I'm pretty sure is caused by the way Raqm is loaded dynamically, but FreeType compiled in statically.

If so, one possible solution I have been thinking about could be to include Raqm in wheels but modify it to use a shim to load FriBiDi dynamically, similarly to how #2753 links Raqm. That would also allow dropping support code for old Raqm versions.

Including Raqm statically would avoid passing FreeType structs between different builds of FreeType, and the FriBiDi interface only passes objects for the FriBiDi library. FriBiDi should also be more widely available (it is a dependency of Raqm, so it should be everywhere where there is Raqm).

@wiredfool
Copy link
Member

It is happening with RAQM, but it's also not happening with RAQM. It's the particular build of it that's the issue. But I do agree that the issue is likely the same as #3066.

It's possible that dynamically linking fribidi would work, but I haven't looked at how complicated that interface is.

@nulano
Copy link
Contributor

nulano commented Nov 24, 2020

If this is only happening with Raqm

I meant "If a workaround is to use layout_engine=ImageFont.LAYOUT_BASIC".

It's possible that dynamically linking fribidi would work, but I haven't looked at how complicated that interface is.

I just had a brief look and I think it might even be simpler than the Raqm interface. I don't see any structs being passed, only typedef-ed ints. There is also one large enum, but the single required value can be hardcoded. There is a single FriBiDi related #ifdef USE_FRIBIDI_EX_API, but it looks easy to detect at load time.

I can give this a try at some point, but I don't expect to have the time in the next few weeks. See #5062.

@pymike00
Copy link

I can also confirm the issue.

  • Pillow: 8.0.1
  • Python: 3.8.6
  • OS: Manjaro Linux, 64 bit

@utamir
Copy link

utamir commented Jan 3, 2021

Confirming

  • Pillow 8.1.0
  • Python: 3.7.3
  • OS: Debian 64

@wiredfool
Copy link
Member

Can you try the wheels from the end of pr #5062 ?

dlukes added a commit to dlukes/corpy that referenced this issue Jan 28, 2021
Until python-pillow/Pillow#4225 gets resolved. You can
check simply by running corpy's test suite, that triggers the segfault fairly
reliably.
@alenpaulvarghese
Copy link

I can also confirm the issue.

  • Pillow: 8.0.1
  • Python: 3.9.2
  • OS: Manjaro Linux, 64 bit

fixed by : pip install --compile --install-option=-O1 Pillow

@makew0rld
Copy link

If this is only happening with Raqm

I meant "If a workaround is to use layout_engine=ImageFont.LAYOUT_BASIC".

@nulano I can confirm this fixes the issue for me.

@radarhere
Copy link
Member

A proposed fix has been merged, so this should be retested when Pillow 8.2.0 is released.

@radarhere
Copy link
Member

Pillow 8.2.0 has now been released.

@radarhere
Copy link
Member

@catcombo are you in a position to check this?

@catcombo
Copy link
Author

catcombo commented Apr 6, 2021

@radarhere I run the test code and it looks the bug is fixed. Thank you!

Pillow automation moved this from New Issues to Closed Apr 6, 2021
tkeffer added a commit to weewx/weewx that referenced this issue Feb 17, 2023
Older versions give the error:
munmap_chunk(): invalid pointer

Or,
corrupted size vs. prev_size

See python-pillow/Pillow#4225
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Pillow
  
Closed
Development

No branches or pull requests