DaemonEngine / crunch

Advanced DXTc texture compression and transcoding library and tool, upgraded with Unity improvements, added features, extended system and hardware support, deeply tested.
https://github.com/DaemonEngine/crunch
Other
16 stars 6 forks source link

suspicious segfault in CRN compression with one main thread and one helper thread #74

Open illwieckz opened 3 days ago

illwieckz commented 3 days ago

I previously noticed that using different value of -helperThreads produce different files. I wondered if it was due to a bug.

I recently wrote a patch in the illwieckz/max-threads branch to set the maximum amount of threads to be usable at build time.

Given crunch is supposed to work with a main thread and some helper threads, the amount of helper threads is assumed to be the maximum amount of threads minus one, so it is assumed the tool should work with only two threads.

Building crunch with an arbitrary maximum amount of threads can be done like this with the illwieckz/max-threads branch:

mkdir buikd && cd build
cmake .. -DUSE_MAX_THREADS=2 && ninja

When I run a conversion from PNG to TGA it works:

./crunch -noTitle -nostats -noprogress -file ../test/unvanquished_64.png -out unvanquished_64.tga

When I run a conversion from PNG to TGA it segfaults, like if it stumbled on some memory issues. It doesn't crash when spawning a thread, it crashes when reading data:

./crunch -noTitle -nostats -noprogress -file ../test/unvanquished_64.png -out unvanquished_64.crn
Thread 1 "crunch" received signal SIGSEGV, Segmentation fault.
0x000055555562d1df in crnlib::crn_comp::pack_blocks (this=this@entry=0x5555556f2ae0, group=group@entry=0, 
    clear_histograms=clear_histograms@entry=true, pCodec=pCodec@entry=0x0, pColor_endpoint_remap=<optimized out>, 
    pColor_selector_remap=<optimized out>, pAlpha_endpoint_remap=0x5555556f4760, pAlpha_selector_remap=0x5555556f4810)
    at crunch/crnlib/crn_comp.cpp:279
279           uint index = (*endpoint_remap[c])[m_endpoint_indices[b].component[c]];

Thread 8 (Thread 0x7ffff76006c0 (LWP 1053043) "crunch"):
#0  0x00007ffff7898d61 in __futex_abstimed_wait_common64 (private=<optimized out>, cancel=true, abstime=0x0, op=393, expected=0, futex_word=0x5555556ea120) at ./nptl/futex-internal.c:57
#1  __futex_abstimed_wait_common (cancel=true, private=<optimized out>, abstime=0x0, clockid=0, expected=0, futex_word=0x5555556ea120) at ./nptl/futex-internal.c:87
#2  __GI___futex_abstimed_wait_cancelable64 (futex_word=futex_word@entry=0x5555556ea120, expected=expected@entry=0, clockid=clockid@entry=0, abstime=abstime@entry=0x0, private=<optimized out>) at ./nptl/futex-internal.c:139
#3  0x00007ffff78a4f0f in do_futex_wait (sem=sem@entry=0x5555556ea120, abstime=0x0, clockid=0) at ./nptl/sem_waitcommon.c:111
#4  0x00007ffff78a4fa8 in __new_sem_wait_slow64 (sem=0x5555556ea120, abstime=0x0, clockid=0) at ./nptl/sem_waitcommon.c:183
#5  0x000055555562a405 in crnlib::semaphore::wait (this=<optimized out>, milliseconds=<optimized out>) at crunch/crnlib/crn_threading_pthreads.cpp:173
#6  0x000055555562a7cd in crnlib::task_pool::thread_func (pContext=0x5555556f2ae8) at crunch/crnlib/crn_threading_pthreads.cpp:384
#7  0x00007ffff789ca94 in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:447
#8  0x00007ffff7929c3c in clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:78

Thread 1 (Thread 0x7ffff7e9d780 (LWP 1053001) "crunch"):
#0  0x000055555562d1df in crnlib::crn_comp::pack_blocks (this=this@entry=0x5555556f2ae0, group=group@entry=0, clear_histograms=clear_histograms@entry=true, pCodec=pCodec@entry=0x0, pColor_endpoint_remap=<optimized out>, pColor_selector_remap=<optimized out>, pAlpha_endpoint_remap=0x5555556f4760, pAlpha_selector_remap=0x5555556f4810) at crunch/crnlib/crn_comp.cpp:279
#1  0x00005555556339e6 in crnlib::crn_comp::compress_internal (this=this@entry=0x5555556f2ae0) at crunch/crnlib/crn_comp.cpp:1238
#2  0x0000555555633e1e in crnlib::crn_comp::compress_pass (this=0x5555556f2ae0, params=..., pEffective_bitrate=0x7fffffffcab0) at crunch/crnlib/crn_comp.cpp:1297
#3  0x00005555556212f9 in crnlib::create_compressed_texture (params=..., comp_data=..., pActual_quality_level=pActual_quality_level@entry=0x7fffffffca90, pActual_bitrate=pActual_bitrate@entry=0x7fffffffcab0) at crunch/crnlib/crn_texture_comp.cpp:60
#4  0x00005555555b985f in crnlib::mipmapped_texture::write_comp_texture (this=0x7fffffffcf70, pFilename=0x5555556e9310 "build/test/png-to-all/unvanquished_64.crn", orig_comp_params=..., pActual_quality_level=0x7fffffffca90, pActual_bitrate=0x7fffffffcab0) at crunch/crnlib/crn_mipmapped_texture.cpp:2942
#5  0x00005555556254f4 in crnlib::texture_conversion::write_compressed_texture (stats=..., perceptual=<optimized out>, progress_state=..., dst_format=crnlib::PIXEL_FMT_A8R8G8B8, comp_params=..., params=..., work_tex=...) at crunch/crnlib/crn_texture_conversion.cpp:396
#6  crnlib::texture_conversion::process (params=..., stats=...) at crunch/crnlib/crn_texture_conversion.cpp:621
#7  0x0000555555568e38 in crunch::convert_file (this=this@entry=0x7fffffffdcf0, file_index=file_index@entry=0, num_files=<optimized out>, pSrc_filename=<optimized out>, pDst_filename=0x5555556e93f0 "build/test/png-to-all/unvanquished_64.crn", out_file_type=out_file_type@entry=crnlib::texture_file_types::cFormatCRN) at crunch/crunch/crunch.cpp:1114
#8  0x000055555556a64b in crunch::process_files (this=this@entry=0x7fffffffdcf0, files=...) at crunch/crunch/../crnlib/crn_vector.h:106
#9  0x000055555556e194 in crunch::convert (this=this@entry=0x7fffffffdcf0) at crunch/crunch/crunch.cpp:381
#10 0x000055555556e875 in crunch::convert (this=this@entry=0x7fffffffdcf0, pCommand_line=<optimized out>) at crunch/crunch/crunch.cpp:330
#11 0x0000555555566427 in main_internal (argc=argc@entry=10, argv=argv@entry=0x7fffffffdf88) at crunch/crunch/crunch.cpp:1201
#12 0x000055555555d798 in main (argc=10, argv=0x7fffffffdf88) at crunch/crunch/crunch.cpp:1228

Thanks to this branch I more curious behaviors. I already noticed that using -helperThreads 3 with the default max amount of threads being 16, crn build was reproducible. It was not with amounts of helper threads higher than 3.

But with that branch, I can test different maximum amount of threads:

So I suspect there is a memory corruption or memory allocation error somewhere.

When there are different images being produced, it's always the same conversion that produces something different.

illwieckz commented 3 days ago

It is also worth noting the mismatches only occurs with image formats produced by crnlib (DDS, CRN and KTX files).

illwieckz commented 3 days ago

How to test for the mismatch:

  1. Make a build tailored for reproducibility: cmake -S. -Bbuild -DUSE_FAST_MATH=OFF && cmake --build build
  2. Edit test/test.py to customize -helperThreads with problematic values.
  3. Run test/test.py

When using the illwieckz/max-threads branch, it's possible to set -DUSE_MAX_THREADS=64 (or other values) as CMake argument to customize the maximum amount of threads.