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

cropgui crashes #114

Open
klartext opened this issue Jan 26, 2024 · 8 comments
Open

cropgui crashes #114

klartext opened this issue Jan 26, 2024 · 8 comments

Comments

@klartext
Copy link

Cropping PNG-files with a size of between 2MB and 2.6MB I get a crash after cropping some of the files.

I recorded the output on the terminal with asciinema.
But attaching is not allowed here ("We don’t support that file type.").

I think you can replicate the behaviour by just putting a lot of large png-files together and try to crop them fast one after another. After 10 or 15 files have been processed, yo can expect the program to crash (sometimes it just hangs).

I guess the problem may occur, if processing is not completed before the next file is worked on in the GUI of cropgui, maybe some kind of race condition. But that's just a guess.

@klartext
Copy link
Author

klartext commented Jan 26, 2024

Some of the output:

/usr/bin/cropgui:33: DeprecationWarning: 'imghdr' is deprecated and slated for removal in Python 3.13
  import imghdr
/usr/bin/cropgui:259: DeprecationWarning: Gtk.Widget.get_pointer is deprecated
  self.drag.idle_motion(*i.get_pointer())
rotation 1 -> 1
image_rotation 1
nice convert IMG_0156.PNG -crop 2160x1322+0+200 +repage /home/oliver/tmp/cropgui-coredump-problem/IMG_0156-crop.PNG
rotation 1 -> 1
image_rotation 1
nice convert IMG_0157.PNG -crop 2160x1322+0+200 +repage /home/oliver/tmp/cropgui-coredump-problem/IMG_0157-crop.PNG
rotation 1 -> 1
image_rotation 1
nice convert IMG_0158.PNG -crop 2160x1322+0+200 +repage /home/oliver/tmp/cropgui-coredump-problem/IMG_0158-crop.PNG
rotation 1 -> 1
image_rotation 1
nice convert IMG_0159.PNG -crop 2160x1322+0+200 +repage /home/oliver/tmp/cropgui-coredump-problem/IMG_0159-crop.PNG
rotation 1 -> 1
image_rotation 1
rotation 1 -> 1
image_rotation 1
rotation 1 -> 1
image_rotation 1
rotation 1 -> 1
image_rotation 1
Warning: [minor] Text/EXIF chunk(s) found after PNG IDAT (fixed) - /home/oliver/tmp/cropgui-coredump-problem/IMG_0156-crop.PNG
    1 image files updated
nice convert IMG_0160.PNG -crop 2160x1322+0+200 +repage /home/oliver/tmp/cropgui-coredump-problem/IMG_0160-crop.PNG
rotation 1 -> 1
image_rotation 1
Warning: [minor] Text/EXIF chunk(s) found after PNG IDAT (fixed) - /home/oliver/tmp/cropgui-coredump-problem/IMG_0157-crop.PNG
    1 image files updated
nice convert IMG_0161.PNG -crop 2160x1322+0+200 +repage /home/oliver/tmp/cropgui-coredump-problem/IMG_0161-crop.PNG
rotation 1 -> 1
image_rotation 1
rotation 1 -> 1
image_rotation 1

[snip]

some output later on:

Warning: [minor] Text/EXIF chunk(s) found after PNG IDAT (fixed) - /home/oliver/tmp/cropgui-coredump-problem/IMG_0165-crop.PNG
    1 image files updated
nice convert IMG_0168.PNG -crop 2160x1322+0+200 +repage /home/oliver/tmp/cropgui-coredump-problem/IMG_0168-crop.PNG

(cropgui:7526): Pango-CRITICAL **: 16:46:22.461: pango_layout_is_wrapped: assertion 'layout != NULL' failed

(cropgui:7526): Pango-CRITICAL **: 16:46:22.461: pango_layout_is_ellipsized: assertion 'layout != NULL' failed
/usr/lib/python3.11/site-packages/gi/overrides/GLib.py:497: Warning: g_object_ref: assertion 'G_IS_OBJECT (object)' failed
  super(MainLoop, self).run()

(cropgui:7526): Pango-CRITICAL **: 16:46:22.465: pango_layout_get_extents: assertion 'layout != NULL' failed
Warning: [minor] Text/EXIF chunk(s) found after PNG IDAT (fixed) - /home/oliver/tmp/cropgui-coredump-problem/IMG_0164-crop.PNG
    1 image files updated
nice convert IMG_0169.PNG -crop 2160x1322+0+200 +repage /home/oliver/tmp/cropgui-coredump-problem/IMG_0169-crop.PNG

(cropgui:7526): Pango-CRITICAL **: 16:46:22.645: pango_layout_is_wrapped: assertion 'layout != NULL' failed

(cropgui:7526): Pango-CRITICAL **: 16:46:22.645: pango_layout_is_ellipsized: assertion 'layout != NULL' failed
/usr/lib/python3.11/site-packages/gi/overrides/GLib.py:497: Warning: g_object_ref: assertion 'G_IS_OBJECT (object)' failed
  super(MainLoop, self).run()

(cropgui:7526): Pango-CRITICAL **: 16:46:22.645: pango_layout_get_extents: assertion 'layout != NULL' failed
Warning: [minor] Text/EXIF chunk(s) found after PNG IDAT (fixed) - /home/oliver/tmp/cropgui-coredump-problem/IMG_0166-crop.PNG
    1 image files updated
nice convert IMG_0170.PNG -crop 2160x1322+0+200 +repage /home/oliver/tmp/cropgui-coredump-problem/IMG_0170-crop.PNG

(cropgui:7526): Pango-CRITICAL **: 16:46:23.227: pango_layout_is_wrapped: assertion 'layout != NULL' failed

(cropgui:7526): Pango-CRITICAL **: 16:46:23.233: pango_layout_is_ellipsized: assertion 'layout != NULL' failed
/usr/lib/python3.11/site-packages/gi/overrides/GLib.py:497: Warning: g_object_ref: assertion 'G_IS_OBJECT (object)' failed
  super(MainLoop, self).run()

(cropgui:7526): Pango-CRITICAL **: 16:46:23.233: pango_layout_get_extents: assertion 'layout != NULL' failed
Warning: [minor] Text/EXIF chunk(s) found after PNG IDAT (fixed) - /home/oliver/tmp/cropgui-coredump-problem/IMG_0167-crop.PNG
    1 image files updated
nice convert IMG_0171.PNG -crop 2160x1322+0+200 +repage /home/oliver/tmp/cropgui-coredump-problem/IMG_0171-crop.PNG
**
Pango:ERROR:../pango/pango/pango-glyph-item.c:327:pango_glyph_item_iter_next_cluster: assertion failed: (iter->end_char <= item->num_chars)
Bail out! Pango:ERROR:../pango/pango/pango-glyph-item.c:327:pango_glyph_item_iter_next_cluster: assertion failed: (iter->end_char <= item->num_chars)
Aborted (core dumped)

@klartext
Copy link
Author

I'm using cropgui 0.7, as AUR-Arch-Package, built this way:

https://aur.archlinux.org/cgit/aur.git/tree/PKGBUILD?h=cropgui

@jepler
Copy link
Owner

jepler commented Jan 26, 2024

That's rather unusual! pango is used for text rendering in gtk, but we don't interact with any of it at a low level. If it's possible to use gtk text display APIs and get a crash, it seems like that is a problem below the level of abstraction where cropgui is operating.

Are there any unusual details about the files you're operating on aside from the size and image format?

I did find some reports of a crash in pango_glyph_item_iter_next_cluster but they are about displaying odd Unicode text [e.g., https://gitlab.gnome.org/raggesilver/blackbox/-/issues/243] but as far as I see cropgui never displays unicode text other than possibly the filename via the window title...

@klartext
Copy link
Author

Nothing special about the files. I can view them with different viewers, no problems.

But in cropgui it is possible to just click CROP again and again, before the message "1 image files updated" is printed on the terminal. That was the reason why I guess that there might be a race condition, maybe some mem is used for the next image, before the last image was updated/written to the output file and before the memory is expected to be reused.

@jepler jepler added the needinfo label Jun 7, 2024
@jepler
Copy link
Owner

jepler commented Jun 7, 2024

Actual image cropping is intentionally performed in the background.

I tried to reproduce this on Debian Stable but was not able to. I tested at v0.7-3-g8e736f9 with 25 copies of this AI-generated nonsense image in png format: http://media.unpythonic.net/emergent-files/sandbox/croptest.png

I repeatedly clicked the "crop" button as fast as I could. Nothing bad seemed to happen. Here's the resulting terminal output:

/home/jepler/src/cropgui/./cropgtk.py:33: DeprecationWarning: 'imghdr' is deprecated and slated for removal in Python 3.13
  import imghdr
/home/jepler/src/cropgui/./cropgtk.py:313: DeprecationWarning: Gtk.Widget.get_pointer is deprecated
  self.drag.idle_motion(*i.get_pointer())
rotation 1 -> 1
not dict? None
nice cp 10.png /home/jepler/src/cropgui/10-crop.png
rotation 1 -> 1
not dict? None
nice cp 11.png /home/jepler/src/cropgui/11-crop.png
rotation 1 -> 1
not dict? None
nice cp 12.png /home/jepler/src/cropgui/12-crop.png
rotation 1 -> 1
not dict? None
nice cp 13.png /home/jepler/src/cropgui/13-crop.png
    1 image files updated
rotation 1 -> 1
not dict? None
nice cp 14.png /home/jepler/src/cropgui/14-crop.png
    1 image files updated
rotation 1 -> 1
not dict? None
nice cp 15.png /home/jepler/src/cropgui/15-crop.png
rotation 1 -> 1
not dict? None
nice cp 16.png /home/jepler/src/cropgui/16-crop.png
    1 image files updated
rotation 1 -> 1
not dict? None
nice cp 17.png /home/jepler/src/cropgui/17-crop.png
rotation 1 -> 1
not dict? None
nice cp 18.png /home/jepler/src/cropgui/18-crop.png
    1 image files updated
    1 image files updated
rotation 1 -> 1
not dict? None
nice cp 19.png /home/jepler/src/cropgui/19-crop.png
rotation 1 -> 1
not dict? None
nice cp 1.png /home/jepler/src/cropgui/1-crop.png
rotation 1 -> 1
not dict? None
nice cp 20.png /home/jepler/src/cropgui/20-crop.png
    1 image files updated
    1 image files updated
rotation 1 -> 1
not dict? None
    1 image files updated
nice cp 21.png /home/jepler/src/cropgui/21-crop.png
    1 image files updated
rotation 1 -> 1
not dict? None
nice cp 22.png /home/jepler/src/cropgui/22-crop.png
    1 image files updated
rotation 1 -> 1
not dict? None
nice cp 23.png /home/jepler/src/cropgui/23-crop.png
    1 image files updated
rotation 1 -> 1
not dict? None
nice cp 24.png /home/jepler/src/cropgui/24-crop.png
rotation 1 -> 1
not dict? None
nice cp 25.png /home/jepler/src/cropgui/25-crop.png
    1 image files updated
rotation 1 -> 1
    1 image files updated
not dict? None
nice cp 2.png /home/jepler/src/cropgui/2-crop.png
    1 image files updated
rotation 1 -> 1
not dict? None
nice cp 3.png /home/jepler/src/cropgui/3-crop.png
    1 image files updated
rotation 1 -> 1
not dict? None
nice cp 4.png /home/jepler/src/cropgui/4-crop.png
rotation 1 -> 1
not dict? None
nice cp 5.png /home/jepler/src/cropgui/5-crop.png
    1 image files updated
    1 image files updated
rotation 1 -> 1
not dict? None
nice cp 6.png /home/jepler/src/cropgui/6-crop.png
rotation 1 -> 1
not dict? None
nice cp 7.png /home/jepler/src/cropgui/7-crop.png
    1 image files updated
    1 image files updated
rotation 1 -> 1
not dict? None
nice cp 8.png /home/jepler/src/cropgui/8-crop.png
rotation 1 -> 1
not dict? None
nice cp 9.png /home/jepler/src/cropgui/9-crop.png
    1 image files updated
    1 image files updated
    1 image files updated
    1 image files updated
    1 image files updated
    1 image files updated

Thanks for any additional information you can provide to help me reproduce the problem.

@klartext
Copy link
Author

klartext commented Jun 7, 2024

Funny AI-nonsense image :-)

The problem might come from race conditions, when the computer is comparingly slow.
It's an old laptop, and so if you test on a fast computer, you may not enter the race condition, because you can't click fast enough and your computer completed the task before the race condition might occur.

@Ndolam
Copy link
Contributor

Ndolam commented Jun 7, 2024

I was wondering about the use of "nice", and this seems to be a (cough) nice place to ask...

Why is "nice" used at all? I would expect the usage of this program to be interactive, and thus there is a human sitting there waiting for the results. This is unlike the situation where I want to compute pi to 1E6 digits, and I will be back tomorrow looking for the answer, but I am doing this on a shared computer and don't want to be anti-social.

Although I can imagine people using cropgui on a shared computer, again it seems most likely to be on a personal computer. Thus my curiosity about its use here. Can you enlighted me?

Thanks.

@jepler
Copy link
Owner

jepler commented Jun 7, 2024

The subprocess commands are run in a CropTask, which creates one thread per CPU.

CropTask accepts jobs into its .queue. They are picked up by an individual thread worker, which then runs them via subprocess.call. When cropgui exits, one of the things it does is send a termination message to each worker, then wait for them all to exit.

This allows the actual action of invoking jpegtran, convert, etc., not block the main UI. In the case of multiple CPUs, it also allows multiple actions to take place in parallel.

Because these are not interactive tasks, they are prefixed with "nice" so that the UI task gets higher priority.

(The main thread still blocks for image decoding, though)

Note: This code either predated multiprocessing or at least my knowledge of it. It could stand to be rewritten in some other way, whether multiprocessing, async, etc.

For the purposes of determining whether this bug is a race condition, perhaps a version of CropTask should be added that doesn't use threads but does everything in the foreground/blocking. That assumes you can reproduce it in the first case, which unfortunately I was not able to do.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants