Skip to content

[Bug] Race condition when evaluating pattern containing errors #2232

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

Open
1 task done
alfishe opened this issue May 8, 2025 · 1 comment
Open
1 task done

[Bug] Race condition when evaluating pattern containing errors #2232

alfishe opened this issue May 8, 2025 · 1 comment
Labels
bug Something isn't working

Comments

@alfishe
Copy link

alfishe commented May 8, 2025

Operating System

macOS Sequoia 15.4.1 on arm64

What's the issue you encountered?

Process crashes with segfault error while executing pattern_language.cpp error stack track unwinding and logging

bool evaluationResult = evaluator->evaluate(this->m_currAST);
if (!evaluationResult) {
//return false;
auto &console = evaluator->getConsole();

        this->m_currError = console.getLastHardError();

        console.log(core::LogConsole::Level::Error, "[ Stack Trace ]");

        const auto &callStack = evaluator->getCallStack();
        u32 lastLine = 0;
        for (const auto &entry : callStack | std::views::reverse) {
            const auto &[node, address] = entry;
            if (node == nullptr)
                continue;

            auto location = node->getLocation();
            if (lastLine == location.line)
                continue;

            console.log(core::LogConsole::Level::Error, core::err::impl::formatLocation(location, address));
            console.log(core::LogConsole::Level::Error, core::err::impl::formatLines(location));
            lastLine = location.line;
        }

Stacktraces belong mostly to string formatting methods. Most likely something executed asynchronously and thread containing stack data finishes / dies somewhere in a background. I wasn't able rapidly understand how async operations are scheduled and no comments available.

Most often issue happens in patterns with std:warning(std:format()) calls usage

[00:22:57] [DEBUG] [main | Parsing pattern...] Task 'hex.builtin.task.parsing_pattern' finished
[00:22:57] [FATAL] [main | Evaluating...] Received signal 'SIGSEGV' (11)
[00:22:57] [INFO] [main | Evaluating...] Wrote crash.json file to /Users/dev/Library/Application Support/imhex/config/crash.json
[00:22:57] [FATAL] [main | Evaluating...] Printing stacktrace using implementation 'execinfo'
[00:22:57] [FATAL] [main | Evaluating...] (imhex) | hex::stacktrace::getStackTrace()
[00:22:57] [FATAL] [main | Evaluating...] (imhex) | hex::crash::printStackTrace()
[00:22:57] [FATAL] [main | Evaluating...] (imhex) | hex::crash::handleCrash(std::__1::basic_string<char, std::__1::char_traits, std::__1::allocator> const&)
[00:22:57] [FATAL] [main | Evaluating...] (imhex) | hex::crash::signalHandler(int, std::__1::basic_string<char, std::__1::char_traits, std::__1::allocator> const&)
[00:22:57] [FATAL] [main | Evaluating...] (imhex) | hex::crash::setupCrashHandlers()::$_0::operator()(int) const
[00:22:57] [FATAL] [main | Evaluating...] (imhex) | hex::crash::setupCrashHandlers()::$_0::__invoke(int)
[00:22:57] [FATAL] [main | Evaluating...] (libsystem_platform.dylib) | _sigtramp
[00:22:57] [FATAL] [main | Evaluating...] (libimhex.dylib) | std::__1::basic_string<char, std::__1::char_traits, std::__1::allocator>::__is_longabi:ne190102 const
[00:22:57] [FATAL] [main | Evaluating...] (libimhex.dylib) | std::__1::basic_string<char, std::__1::char_traits, std::__1::allocator>::__get_pointerabi:ne190102 const
[00:22:57] [FATAL] [main | Evaluating...] (libimhex.dylib) | std::__1::basic_string<char, std::__1::char_traits, std::__1::allocator>::dataabi:ne190102 const
[00:22:57] [FATAL] [main | Evaluating...] (libimhex.dylib) | std::__1::basic_string<char, std::__1::char_traits, std::__1::allocator>::find[abi:ne190102](std::__1::basic_string<char, std::__1::char_traits, std::__1::allocator> const&, unsigned long) const
[00:22:57] [FATAL] [main | Evaluating...] (libimhex.dylib) | wolv::util::splitString(std::__1::basic_string<char, std::__1::char_traits, std::__1::allocator> const&, std::__1::basic_string<char, std::__1::char_traits, std::__1::allocator> const&, bool)
[00:22:57] [FATAL] [main | Evaluating...] (libimhex.dylib) | pl::core::err::impl::formatLines(pl::core::Location)
[00:22:57] [FATAL] [main | Evaluating...] (libimhex.dylib) | pl::PatternLanguage::executeString(std::__1::basic_string<char, std::__1::char_traits, std::__1::allocator>, std::__1::basic_string<char, std::__1::char_traits, std::__1::allocator> const&, std::__1::map<std::__1::basic_string<char, std::__1::char_traits, std::__1::allocator>, pl::core::Token::Literal, std::__1::less<std::__1::basic_string<char, std::__1::char_traits, std::__1::allocator>>, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits, std::__1::allocator> const, pl::core::Token::Literal>>> const&, std::__1::map<std::__1::basic_string<char, std::__1::char_traits, std::__1::allocator>, pl::core::Token::Literal, std::__1::less<std::__1::basic_string<char, std::__1::char_traits, std::__1::allocator>>, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits, std::__1::allocator> const, pl::core::Token::Literal>>> const&, bool)
[00:22:57] [FATAL] [main | Evaluating...] (builtin.hexplug) | _ZZN3hex6plugin7builtin17ViewPatternEditor15evaluatePatternERKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEPNS_3prv8ProviderEENK3$0clINS_4TaskEEEDaRT
[00:22:57] [FATAL] [main | Evaluating...] (builtin.hexplug) | decltype(std::declval<hex::plugin::builtin::ViewPatternEditor::evaluatePattern(std::__1::basic_string<char, std::__1::char_traits, std::__1::allocator> const&, hex::prv::Provider*)::$_0&>()(std::declvalhex::Task&())) std::__1::__invoke[abi:de190102]<hex::plugin::builtin::ViewPatternEditor::evaluatePattern(std::__1::basic_string<char, std::__1::char_traits, std::__1::allocator> const&, hex::prv::Provider*)::$_0&, hex::Task&>(hex::plugin::builtin::ViewPatternEditor::evaluatePattern(std::__1::basic_string<char, std::__1::char_traits, std::__1::allocator> const&, hex::prv::Provider*)::$_0&, hex::Task&)
[00:22:57] [FATAL] [main | Evaluating...] (builtin.hexplug) | void std::__1::__invoke_void_return_wrapper<void, true>::__call[abi:de190102]<hex::plugin::builtin::ViewPatternEditor::evaluatePattern(std::__1::basic_string<char, std::__1::char_traits, std::__1::allocator> const&, hex::prv::Provider*)::$_0&, hex::Task&>(hex::plugin::builtin::ViewPatternEditor::evaluatePattern(std::__1::basic_string<char, std::__1::char_traits, std::__1::allocator> const&, hex::prv::Provider*)::$_0&, hex::Task&)
[00:22:57] [FATAL] [main | Evaluating...] (builtin.hexplug) | std::__1::__function::__alloc_func<hex::plugin::builtin::ViewPatternEditor::evaluatePattern(std::__1::basic_string<char, std::__1::char_traits, std::__1::allocator> const&, hex::prv::Provider*)::$_0, std::__1::allocator<hex::plugin::builtin::ViewPatternEditor::evaluatePattern(std::__1::basic_string<char, std::__1::char_traits, std::__1::allocator> const&, hex::prv::Provider*)::$_0>, void (hex::Task&)>::operator()abi:de190102
[00:22:57] [FATAL] [main | Evaluating...] (builtin.hexplug) | std::__1::__function::__func<hex::plugin::builtin::ViewPatternEditor::evaluatePattern(std::__1::basic_string<char, std::__1::char_traits, std::__1::allocator> const&, hex::prv::Provider*)::$_0, std::__1::allocator<hex::plugin::builtin::ViewPatternEditor::evaluatePattern(std::__1::basic_string<char, std::__1::char_traits, std::__1::allocator> const&, hex::prv::Provider*)::$_0>, void (hex::Task&)>::operator()(hex::Task&)
[00:22:57] [FATAL] [main | Evaluating...] (libimhex.dylib) | std::__1::__function::__value_func<void (hex::Task&)>::operator()abi:de190102 const
[00:22:57] [FATAL] [main | Evaluating...] (libimhex.dylib) | std::__1::function<void (hex::Task&)>::operator()(hex::Task&) const
[00:22:57] [FATAL] [main | Evaluating...] (libimhex.dylib) | hex::TaskManager::init()::$_0::operator()(std::stop_token const&) const
[00:22:57] [FATAL] [main | Evaluating...] (libimhex.dylib) | decltype(std::declvalhex::TaskManager::init()::$_0()(std::declvalstd::stop_token())) std::__1::__invoke[abi:de190102]<hex::TaskManager::init()::$_0, std::stop_token>(hex::TaskManager::init()::$_0&&, std::stop_token&&)
[00:22:57] [FATAL] [main | Evaluating...] (libimhex.dylib) | std::__1::invoke_result<hex::TaskManager::init()::$_0, std::stop_token>::type std::__1::invoke[abi:de190102]<hex::TaskManager::init()::$_0, std::stop_token>(hex::TaskManager::init()::$_0&&, std::stop_token&&)
[00:22:57] [FATAL] [main | Evaluating...] (libimhex.dylib) | auto std::jthread::jthread<hex::TaskManager::init()::$_0, void>(hex::TaskManager::init()::$_0&&)::'lambda'(std::stop_token, hex::TaskManager::init()::$_0&&)::operator()hex::TaskManager::init()::$_0(std::stop_token, hex::TaskManager::init()::$_0&&) const
[00:22:57] [FATAL] [main | Evaluating...] (libimhex.dylib) | decltype(std::declvalhex::TaskManager::init()::$_0()()) std::__1::__invoke[abi:de190102]<std::jthread::jthread<hex::TaskManager::init()::$_0, void>(hex::TaskManager::init()::$_0&&)::'lambda'(std::stop_token, hex::TaskManager::init()::$_0&&), std::stop_token, hex::TaskManager::init()::$_0>(hex::TaskManager::init()::$_0&&)
[00:22:57] [FATAL] [main | Evaluating...] (libimhex.dylib) | void std::__1::__thread_execute[abi:de190102]<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_deletestd::__1::__thread_struct>, std::jthread::jthread<hex::TaskManager::init()::$_0, void>(hex::TaskManager::init()::$_0&&)::'lambda'(std::stop_token, hex::TaskManager::init()::$_0&&), std::stop_token, hex::TaskManager::init()::$_0, 2ul, 3ul>(std::__1::tuple<hex::TaskManager::init()::$_0, std::jthread::jthread<hex::TaskManager::init()::$_0, void>(hex::TaskManager::init()::$_0&&)::'lambda'(std::stop_token, hex::TaskManager::init()::$_0&&), std::stop_token, hex::TaskManager::init()::$_0>&, std::__1::__tuple_indices<2ul, 3ul>)
[00:22:57] [FATAL] [main | Evaluating...] (libimhex.dylib) | void* std::__1::__thread_proxy[abi:de190102]<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_deletestd::__1::__thread_struct>, std::jthread::jthread<hex::TaskManager::init()::$_0, void>(hex::TaskManager::init()::$_0&&)::'lambda'(std::stop_token, hex::TaskManager::init()::$_0&&), std::stop_token, hex::TaskManager::init()::$_0>>(void*)
[00:22:57] [FATAL] [main | Evaluating...] (libsystem_pthread.dylib) | _pthread_start
[00:22:57] [FATAL] [main | Evaluating...] (libsystem_pthread.dylib) | thread_start
[00:22:57] [DEBUG] [main | Evaluating...] Event posted: 'hex::EventAbnormalTermination'
libc++abi: terminating due to uncaught exception of type std::__1::system_error: thread::join failed: Resource deadlock avoided

How can the issue be reproduced?

MFM.hexpat.txt
trdos.img.txt

Use following .img file and pattern file to reproduce

ImHex Version

1.38.0

ImHex Build Type

  • Nightly or built from sources

Installation type

Latest main build on macOS using latest CLang

Additional context?

Both release arm64 binaries (1.37.4) and built from sources affected, issue with async processing / race condition

@alfishe alfishe added the bug Something isn't working label May 8, 2025
@paxcut
Copy link
Collaborator

paxcut commented May 11, 2025

The crashes are the result of the badly formatted function that has several statements in one line that create an invalid stack trace when the function is called without the namespace.

As a workaround while the issue is being fixed note that if the function is made properly formatted as

fn crc16_ccitt_pl(u64 address, u64 length)
{
    u16 crc = 0xFFFF; 
    const u16 polynomial = 0x1021;
    u64 current_addr = address; u64 end_addr = address + length;
    while (current_addr < end_addr)
    {
        u16 byte_val = u16(std::mem::read_unsigned(current_addr, 1));
        crc ^= (byte_val << 8);
        for (u8 bit_index = 0, bit_index < 8, bit_index += 1)
        {
            if ((crc & 0x8000) != 0) { 
                crc = ((crc << 1) & 0xFFFF) ^ polynomial; 
            } else {
                crc = (crc << 1) & 0xFFFF; 
            }
        }

        current_addr += 1;
    }

    return crc;
};

then the crash no longer occurs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants