We are trying to copy all bytes in the current row, which is the width times
the number of bytes per pixel (stored in info->bytes), not width times bits
per pixel.
Copying too much data allows certain inputs to induce a heap-buffer-buffer
overflow read, and probably also a write, see ASAN output below:
ERROR: AddressSanitizer: heap-buffer-overflow on address 0x61d000008088 at pc 0x00000052be17 bp 0x7ffd8bbe8e20 sp 0x7ffd8bbe85e8
READ of size 16448 at 0x61d000008088 thread T0
#0 0x52be16 in __asan_memcpy /home/abuild/rpmbuild/BUILD/llvm-12.0.0.src/build/../projects/compiler-rt/lib/asan/asan_interceptors_memintrinsics.cpp:22:3
#1 0x5641ca in read_line /home/ahunt/git/gimp/plug-ins/common/file-tga.c:982:7
#2 0x560218 in ReadImage /home/ahunt/git/gimp/plug-ins/common/file-tga.c:1147:15
#3 0x55f526 in load_image /home/ahunt/git/gimp/plug-ins/common/file-tga.c:646:11
#4 0x56519b in LLVMFuzzerTestOneInput /home/ahunt/git/gimp/plug-ins/common/file-tga_fuzzer.c:69:17
#5 0x461624 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /home/abuild/rpmbuild/BUILD/llvm-12.0.0.src/build/../projects/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:599:15
#6 0x460b2a in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool, bool*) /home/abuild/rpmbuild/BUILD/llvm-12.0.0.src/build/../projects/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:505:3
#7 0x462ec4 in fuzzer::Fuzzer::ReadAndExecuteSeedCorpora(std::__Fuzzer::vector<fuzzer::SizedFile, fuzzer::fuzzer_allocator<fuzzer::SizedFile> >&) /home/abuild/rpmbuild/BUILD/llvm-12.0.0.src/build/../projects/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:814:7
#8 0x4630d9 in fuzzer::Fuzzer::Loop(std::__Fuzzer::vector<fuzzer::SizedFile, fuzzer::fuzzer_allocator<fuzzer::SizedFile> >&) /home/abuild/rpmbuild/BUILD/llvm-12.0.0.src/build/../projects/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:845:3
#9 0x451686 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /home/abuild/rpmbuild/BUILD/llvm-12.0.0.src/build/../projects/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:906:6
#10 0x47b662 in main /home/abuild/rpmbuild/BUILD/llvm-12.0.0.src/build/../projects/compiler-rt/lib/fuzzer/FuzzerMain.cpp:20:10
#11 0x7fdbd277c349 in __libc_start_main (/lib64/libc.so.6+0x24349)
#12 0x424a39 in _start /home/abuild/rpmbuild/BUILD/glibc-2.26/csu/../sysdeps/x86_64/start.S:120
0x61d000008088 is located 0 bytes to the right of 2056-byte region [0x61d000007880,0x61d000008088)
allocated by thread T0 here:
#0 0x52ca8d in malloc /home/abuild/rpmbuild/BUILD/llvm-12.0.0.src/build/../projects/compiler-rt/lib/asan/asan_malloc_linux.cpp:145:3
#1 0x7fdbd37fccf2 in g_malloc /home/ahunt/git/glib/_build/../glib/gmem.c:106:13
#2 0x56009b in ReadImage /home/ahunt/git/gimp/plug-ins/common/file-tga.c:1134:10
#3 0x55f526 in load_image /home/ahunt/git/gimp/plug-ins/common/file-tga.c:646:11
#4 0x56519b in LLVMFuzzerTestOneInput /home/ahunt/git/gimp/plug-ins/common/file-tga_fuzzer.c:69:17
#5 0x461624 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /home/abuild/rpmbuild/BUILD/llvm-12.0.0.src/build/../projects/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:599:15
#6 0x460b2a in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool, bool*) /home/abuild/rpmbuild/BUILD/llvm-12.0.0.src/build/../projects/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:505:3
#7 0x462ec4 in fuzzer::Fuzzer::ReadAndExecuteSeedCorpora(std::__Fuzzer::vector<fuzzer::SizedFile, fuzzer::fuzzer_allocator<fuzzer::SizedFile> >&) /home/abuild/rpmbuild/BUILD/llvm-12.0.0.src/build/../projects/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:814:7
#8 0x4630d9 in fuzzer::Fuzzer::Loop(std::__Fuzzer::vector<fuzzer::SizedFile, fuzzer::fuzzer_allocator<fuzzer::SizedFile> >&) /home/abuild/rpmbuild/BUILD/llvm-12.0.0.src/build/../projects/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:845:3
#9 0x451686 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /home/abuild/rpmbuild/BUILD/llvm-12.0.0.src/build/../projects/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:906:6
#10 0x47b662 in main /home/abuild/rpmbuild/BUILD/llvm-12.0.0.src/build/../projects/compiler-rt/lib/fuzzer/FuzzerMain.cpp:20:10
#11 0x7fdbd277c349 in __libc_start_main (/lib64/libc.so.6+0x24349)
SUMMARY: AddressSanitizer: heap-buffer-overflow /home/abuild/rpmbuild/BUILD/llvm-12.0.0.src/build/../projects/compiler-rt/lib/asan/asan_interceptors_memintrinsics.cpp:22:3 in __asan_memcpy
Shadow bytes around the buggy address:
0x0c3a7fff8fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c3a7fff8fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c3a7fff8fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c3a7fff8ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c3a7fff9000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c3a7fff9010: 00[fa]fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c3a7fff9020: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c3a7fff9030: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c3a7fff9040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c3a7fff9050: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c3a7fff9060: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
Shadow gap: cc
==26560==ABORTING
crash-4b13aca1db7bb795a815431b86cc20284f3aa6da
A malformed colourmapped tga file could specify color IDs that are not
contained in the colourmap. Therefore we add some bounds checking to
ensure that we only use entries that actually exist.
We could completely give up on such files, but it's just as easy to fall
back to the first colour in the map in this case. However we can only
fall back to the first colour in the map IF the colourmap contains
at least one entry. Therefore we add an up-front check to verify that
colourmapped images actually do contain at least one entry.
Without this bounds-checking, it's possible to induce a heap-buffer-overflow
read in apply-colormap(), see ASAN output below:
ERROR: AddressSanitizer: heap-buffer-overflow on address 0x61900002257c at pc 0x000000564f99 bp 0x7ffe65fdb040 sp 0x7ffe65fdb038
READ of size 1 at 0x61900002257c thread T0
#0 0x564f98 in apply_colormap /home/ahunt/git/gimp/plug-ins/common/file-tga.c:901:23
#1 0x56411a in read_line /home/ahunt/git/gimp/plug-ins/common/file-tga.c:975:7
#2 0x560648 in ReadImage /home/ahunt/git/gimp/plug-ins/common/file-tga.c:1202:15
#3 0x55f4ee in load_image /home/ahunt/git/gimp/plug-ins/common/file-tga.c:647:11
#4 0x5653ab in LLVMFuzzerTestOneInput /home/ahunt/git/gimp/plug-ins/common/file-tga_fuzzer.c:69:17
#5 0x461624 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /home/abuild/rpmbuild/BUILD/llvm-12.0.0.src/build/../projects/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:599:15
#6 0x460b2a in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool, bool*) /home/abuild/rpmbuild/BUILD/llvm-12.0.0.src/build/../projects/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:505:3
#7 0x462847 in fuzzer::Fuzzer::MutateAndTestOne() /home/abuild/rpmbuild/BUILD/llvm-12.0.0.src/build/../projects/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:745:19
#8 0x4633d5 in fuzzer::Fuzzer::Loop(std::__Fuzzer::vector<fuzzer::SizedFile, fuzzer::fuzzer_allocator<fuzzer::SizedFile> >&) /home/abuild/rpmbuild/BUILD/llvm-12.0.0.src/build/../projects/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:883:5
#9 0x451686 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /home/abuild/rpmbuild/BUILD/llvm-12.0.0.src/build/../projects/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:906:6
#10 0x47b662 in main /home/abuild/rpmbuild/BUILD/llvm-12.0.0.src/build/../projects/compiler-rt/lib/fuzzer/FuzzerMain.cpp:20:10
#11 0x7fe76a5dc349 in __libc_start_main (/lib64/libc.so.6+0x24349)
#12 0x424a39 in _start /home/abuild/rpmbuild/BUILD/glibc-2.26/csu/../sysdeps/x86_64/start.S:120
0x61900002257c is located 0 bytes to the right of 1020-byte region [0x619000022180,0x61900002257c)
allocated by thread T0 here:
#0 0x52ca8d in malloc /home/abuild/rpmbuild/BUILD/llvm-12.0.0.src/build/../projects/compiler-rt/lib/asan/asan_malloc_linux.cpp:145:3
#1 0x7fe76b65ccf2 in g_malloc /home/ahunt/git/glib/_build/../glib/gmem.c:106:13
#2 0x55fdc6 in ReadImage /home/ahunt/git/gimp/plug-ins/common/file-tga.c:1049:26
#3 0x55f4ee in load_image /home/ahunt/git/gimp/plug-ins/common/file-tga.c:647:11
#4 0x5653ab in LLVMFuzzerTestOneInput /home/ahunt/git/gimp/plug-ins/common/file-tga_fuzzer.c:69:17
#5 0x461624 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /home/abuild/rpmbuild/BUILD/llvm-12.0.0.src/build/../projects/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:599:15
#6 0x460b2a in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool, bool*) /home/abuild/rpmbuild/BUILD/llvm-12.0.0.src/build/../projects/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:505:3
#7 0x462847 in fuzzer::Fuzzer::MutateAndTestOne() /home/abuild/rpmbuild/BUILD/llvm-12.0.0.src/build/../projects/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:745:19
#8 0x4633d5 in fuzzer::Fuzzer::Loop(std::__Fuzzer::vector<fuzzer::SizedFile, fuzzer::fuzzer_allocator<fuzzer::SizedFile> >&) /home/abuild/rpmbuild/BUILD/llvm-12.0.0.src/build/../projects/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:883:5
#9 0x451686 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /home/abuild/rpmbuild/BUILD/llvm-12.0.0.src/build/../projects/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:906:6
#10 0x47b662 in main /home/abuild/rpmbuild/BUILD/llvm-12.0.0.src/build/../projects/compiler-rt/lib/fuzzer/FuzzerMain.cpp:20:10
#11 0x7fe76a5dc349 in __libc_start_main (/lib64/libc.so.6+0x24349)
SUMMARY: AddressSanitizer: heap-buffer-overflow /home/ahunt/git/gimp/plug-ins/common/file-tga.c:901:23 in apply_colormap
Shadow bytes around the buggy address:
0x0c327fffc450: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c327fffc460: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c327fffc470: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c327fffc480: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c327fffc490: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c327fffc4a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00[04]
0x0c327fffc4b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c327fffc4c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c327fffc4d0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c327fffc4e0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c327fffc4f0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
Shadow gap: cc
==16309==ABORTING
( crash-f70628d4df7a65babc8e57d890425771a1d67e06 )
If the colourmap contains more than 256 items AND has alpha, it should always
be promoted to RGBA. Therefore we move the "if (info->alphaBits)" check into
the first if clause, to avoid accidentally demoting to RGB in this scenario.
Other parts of the tga parser assume that the destination array is RGBA
when alphaBits is not zero. For example, upsample() will always write 4 bytes
per pixel when alpha is set - (even if we only allocated 3 because we thought
we should use RGB). Erronously allocating only 3 bytes makes it easy to induce
a heap-buffer-overflow write, see ASAN output below. (apply_colormap makes the
same assumption and would probably do the same thing, but upsample is the
first location that we'd hit this issue.)
ERROR: AddressSanitizer: heap-buffer-overflow on address 0x61700002ae00 at pc 0x000000563d97 bp 0x7ffde8677890 sp 0x7ffde8677888
WRITE of size 1 at 0x61700002ae00 thread T0
#0 0x563d96 in upsample /home/ahunt/git/gimp/plug-ins/common/file-tga.c:830:15
#1 0x560b59 in ReadImage /home/ahunt/git/gimp/plug-ins/common/file-tga.c
#2 0x55f4ee in load_image /home/ahunt/git/gimp/plug-ins/common/file-tga.c:647:11
#3 0x5652ab in LLVMFuzzerTestOneInput /home/ahunt/git/gimp/plug-ins/common/file-tga_fuzzer.c:69:17
#4 0x461624 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /home/abuild/rpmbuild/BUILD/llvm-12.0.0.src/build/../projects/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:599:15
#5 0x460b2a in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool, bool*) /home/abuild/rpmbuild/BUILD/llvm-12.0.0.src/build/../projects/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:505:3
#6 0x462847 in fuzzer::Fuzzer::MutateAndTestOne() /home/abuild/rpmbuild/BUILD/llvm-12.0.0.src/build/../projects/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:745:19
#7 0x4633d5 in fuzzer::Fuzzer::Loop(std::__Fuzzer::vector<fuzzer::SizedFile, fuzzer::fuzzer_allocator<fuzzer::SizedFile> >&) /home/abuild/rpmbuild/BUILD/llvm-12.0.0.src/build/../projects/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:883:5
#8 0x451686 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /home/abuild/rpmbuild/BUILD/llvm-12.0.0.src/build/../projects/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:906:6
#9 0x47b662 in main /home/abuild/rpmbuild/BUILD/llvm-12.0.0.src/build/../projects/compiler-rt/lib/fuzzer/FuzzerMain.cpp:20:10
#10 0x7fd894a94349 in __libc_start_main (/lib64/libc.so.6+0x24349)
#11 0x424a39 in _start /home/abuild/rpmbuild/BUILD/glibc-2.26/csu/../sysdeps/x86_64/start.S:120
0x61700002ae00 is located 0 bytes to the right of 768-byte region [0x61700002ab00,0x61700002ae00)
allocated by thread T0 here:
#0 0x52ca8d in malloc /home/abuild/rpmbuild/BUILD/llvm-12.0.0.src/build/../projects/compiler-rt/lib/asan/asan_malloc_linux.cpp:145:3
#1 0x7fd895b14cf2 in g_malloc /home/ahunt/git/glib/_build/../glib/gmem.c:106:13
#2 0x55fce9 in ReadImage /home/ahunt/git/gimp/plug-ins/common/file-tga.c:1039:26
#3 0x55f4ee in load_image /home/ahunt/git/gimp/plug-ins/common/file-tga.c:647:11
#4 0x5652ab in LLVMFuzzerTestOneInput /home/ahunt/git/gimp/plug-ins/common/file-tga_fuzzer.c:69:17
#5 0x461624 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /home/abuild/rpmbuild/BUILD/llvm-12.0.0.src/build/../projects/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:599:15
#6 0x460b2a in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool, bool*) /home/abuild/rpmbuild/BUILD/llvm-12.0.0.src/build/../projects/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:505:3
#7 0x462847 in fuzzer::Fuzzer::MutateAndTestOne() /home/abuild/rpmbuild/BUILD/llvm-12.0.0.src/build/../projects/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:745:19
#8 0x4633d5 in fuzzer::Fuzzer::Loop(std::__Fuzzer::vector<fuzzer::SizedFile, fuzzer::fuzzer_allocator<fuzzer::SizedFile> >&) /home/abuild/rpmbuild/BUILD/llvm-12.0.0.src/build/../projects/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:883:5
#9 0x451686 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /home/abuild/rpmbuild/BUILD/llvm-12.0.0.src/build/../projects/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:906:6
#10 0x47b662 in main /home/abuild/rpmbuild/BUILD/llvm-12.0.0.src/build/../projects/compiler-rt/lib/fuzzer/FuzzerMain.cpp:20:10
#11 0x7fd894a94349 in __libc_start_main (/lib64/libc.so.6+0x24349)
SUMMARY: AddressSanitizer: heap-buffer-overflow /home/ahunt/git/gimp/plug-ins/common/file-tga.c:830:15 in upsample
Shadow bytes around the buggy address:
0x0c2e7fffd570: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c2e7fffd580: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c2e7fffd590: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c2e7fffd5a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c2e7fffd5b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c2e7fffd5c0:[fa]fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c2e7fffd5d0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x0c2e7fffd5e0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x0c2e7fffd5f0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x0c2e7fffd600: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x0c2e7fffd610: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
Shadow gap: cc
==12179==ABORTING
( crash-f65fd5404bff32c1d9d10ee049d9c98d02bbbdc2 )
We allow passing NULL gvalue for an empty GimpObjectArray, for convenience.
For example to plugin sel2path which doesn't use drawables.
But crossing the wire, create an empty GimpObjectArray
having an arbitrary type for elements.
Note that the widgets are still made
with GTK directly. The primary goal of this
initial port is to remove the last usage of
gimp_export_dialog_new (). Future work
will be needed as currently we can not
automatically generate widgets from
array parameters.
The visibility lock icon and help ID was accidentally
left off the PathsTreeView set-up.
The Path Attributes also used the wrong icon to indicate
the paths were locked (compared to the one shown in the
Path Attributes dialogue).
Revise the tests that can't default the args.
Actual args default to the min value formal declared in the PDB.
The declared min value must correspond with declaration in GEGL.
As of fcdddad2, the requirement for layers
to be attached before NDE filters can be
applied has been removed on app/core.
This patch removes the restriction from
the PDB call for filters as well.
* file-sunras, sparkle, and fractal-explorer
were converted to use GimpChoice with
the RadioFrame setting
* Unnecessary store variables were
removed from hot and file-psp
The description promises that we return
NULL if the image is not in indexed mode,
but we didn't actually verify that it was
before continuing with the colormap
code. This patch adds that verification step.
...in non-interactive cases.
gimp_export_image () handles various
tasks like rasterizing NDE filters. It only
runs in interactive cases however, so if the
users calls gimp-file-save the filters are
not exported.
Since Jehan removed the hidden dialogue
in 0dc9ff7c, we can now safely call
gimp_export_image () in all cases to make
image export more consistent. This step is
also preparation for setting up the new
API with GimpExportOptions.
GimpPlugin improperly destroys proxies after each run of a temporary procedure.
A temporary procedure may pass reference to proxy to main procedure.
Proxies should live as long as the main procedure of a plugin,
or for an extension plugin, until only the extension main procedure
is on the procedure stack. More discussion in the issue.
Extract method gimp_plug_in_proc_run.
Call it from two new methods: main_proc_run and temp_proc_run,
which do more e.g. cleanup.
Extract methods for cleanup, main_proc_cleanup and temp_proc_cleanup
Add method is_proc_stack_empty