Qt6.5.3 Build QtWebEngine for Windows x64. Error: transport_security_state_generator.exe failed with exit code 3221226505
-
wrote on 17 Mar 2025, 16:00 last edited by
Hi. I am getting an error while building Qt6.5.3 QtWebEngine for Windows x64.
Here is the build configuration:..\configure -prefix C:\qt6_x64 -opensource -debug-and-release -confirm-license -opengl desktop -nomake tests -nomake examples -skip qthttpserver -skip qtlocation -skip qtspeech -skip qtgrpc -skip qt3d -skip qtcharts -skip qtcoap -skip qtconnectivity -skip qtdatavis3d -skip qtdoc -skip qtlottie -skip qtmqtt -skip qtnetworkauth -skip qtopcua -skip qtremoteobjects -skip qtscxml -skip qtsensors -skip qtserialbus -skip qtwayland -skip qtwebengine -skip qttranslations -skip qtquickeffectmaker -skip qtquick3dphysics -skip qtgraphs -openssl-linked -- -Wno-dev -DOPENSSL_ROOT_DIR="C:\Q\openssl-3.0.13-WIN64A\build" -DOPENSSL_INCLUDE_DIR="C:\Q\openssl-3.0.13-WIN64A\build\include" -DOPENSSL_USE_STATIC_LIBS=ON -DFFMPEG_DIR=C:\Users\user\Desktop\vcpkg\installed\x64-windows C:\qt6_x64\bin\qt-configure-module.bat ../qtwebengine -- -Wno-dev
Here is the error:
[9063/29010] ACTION //net/http:generate_transport_security_state(//build/toolchain/win:x64) FAILED: gen/net/http/transport_security_state_static.h C:/Program Files/Python38/python.exe ../../../../../qtwebengine/src/3rdparty/chromium/build/gn_run_binary.py transport_security_state_generator.exe ../../../../../qtwebengine/src/3rdparty/chromium/net/http/transport_security_state_static.json.gz ../../../../../qtwebengine/src/3rdparty/chromium/net/http/transport_security_state_static.pins ../../../../../qtwebengine/src/3rdparty/chromium/net/http/transport_security_state_static.template gen/net/http/transport_security_state_static.h transport_security_state_generator.exe failed with exit code 3221226505
Please help me.
-
wrote 9 days ago last edited by Esmaeil_Sooan 5 Jul 2025, 08:52
Hi @Jemand
🚨 If you’re seeing this error:
transport_security_state_generator.exe failed with exit code 3221226505This exit code corresponds to STATUS_STACK_BUFFER_OVERRUN, which usually indicates a crash due to memory corruption or an access violation. I investigated and found the root cause. 🕵️♂️
✅ Solution:
Navigate to the following directory in the Qt WebEngine source:qtwebengine\src\3rdparty\chromium\net\tools\huffman_trie\trie
Then, open trie_writer.cc and modify the WriteEntries function to skip entries with empty hostnames. Here's the modified code snippet:
for (auto* const entry : entries) { if (entry->name().empty()) { LOG(INFO) << "Skipping empty hostname entry"; continue; } auto reversed_entry = std::make_unique<ReversedEntry>(ReverseName(entry->name()), entry); reversed_entries.push_back(std::move(reversed_entry)); }
🧹 Clean up generated files:
Delete any previously built transport_security_state_generator.exe binary and related libraries from:{your_build_dir}\qtwebengine\src\core\Release\AMD64
🔁 Rebuild:
Then rerun the build with:cmake --build . --parallel
🎉 That should resolve the issue! Feel free to ask if you need further help.
-
Hi @Jemand
🚨 If you’re seeing this error:
transport_security_state_generator.exe failed with exit code 3221226505This exit code corresponds to STATUS_STACK_BUFFER_OVERRUN, which usually indicates a crash due to memory corruption or an access violation. I investigated and found the root cause. 🕵️♂️
✅ Solution:
Navigate to the following directory in the Qt WebEngine source:qtwebengine\src\3rdparty\chromium\net\tools\huffman_trie\trie
Then, open trie_writer.cc and modify the WriteEntries function to skip entries with empty hostnames. Here's the modified code snippet:
for (auto* const entry : entries) { if (entry->name().empty()) { LOG(INFO) << "Skipping empty hostname entry"; continue; } auto reversed_entry = std::make_unique<ReversedEntry>(ReverseName(entry->name()), entry); reversed_entries.push_back(std::move(reversed_entry)); }
🧹 Clean up generated files:
Delete any previously built transport_security_state_generator.exe binary and related libraries from:{your_build_dir}\qtwebengine\src\core\Release\AMD64
🔁 Rebuild:
Then rerun the build with:cmake --build . --parallel
🎉 That should resolve the issue! Feel free to ask if you need further help.
wrote 9 days ago last edited by@Esmaeil_Sooan
Strange that skipping an empty entry would avoid some stack overflow. If your fix really is required have you considered raising a bug to this effect at https://bugreports.qt.io/ with your proposed fix? -
wrote 9 days ago last edited by
-
wrote 9 days ago last edited by
@JonB
Okay, I found the issue.It happens in the WriteDispatchTables function:
uint8_t candidate = (*start)->reversed_name.at(0); auto sub_entries_end = start + 1;
If reversed_name is empty, this line will crash due to out-of-bounds access on .at(0).
Tracing back, this function is called from WriteEntries:
bool TrieWriter::WriteEntries(const TrieEntries& entries, uint32_t* root_position) { if (entries.empty()) return false; ReversedEntries reversed_entries; for (auto* const entry : entries) { if (entry->name().empty()) { LOG(INFO) << "Skipping empty hostname entry"; continue; } auto reversed_entry = std::make_unique<ReversedEntry>(ReverseName(entry->name()), entry); reversed_entries.push_back(std::move(reversed_entry)); } std::stable_sort(reversed_entries.begin(), reversed_entries.end(), CompareReversedEntries); return WriteDispatchTables(reversed_entries.begin(), reversed_entries.end(), root_position); }
So if we don’t filter out empty entry->name() values beforehand, ReverseName() returns a vector with only the kTerminalValue, and after removing prefixes (in RemovePrefix), the reversed_name may become empty — leading to a crash when .at(0) is accessed.
Adding a check to skip empty hostnames in WriteEntries() avoids this edge case and prevents the crash.
-
wrote 9 days ago last edited by
bool TrieWriter::WriteDispatchTables(ReversedEntries::iterator start, ReversedEntries::iterator end, uint32_t* position) { DCHECK(start != end) << "No entries passed to WriteDispatchTables"; TrieBitBuffer writer; std::vector<uint8_t> prefix = LongestCommonPrefix(start, end); LOG(INFO) << "Longest common prefix size: " << prefix.size(); writer.WriteSize(prefix.size()); LOG(INFO) << "Prefix size: " << prefix.size(); if (prefix.size()) { for (uint8_t c : prefix) { writer.WriteChar(c, huffman_table_, huffman_builder_); } } LOG(INFO) << "Prefix written"; RemovePrefix(prefix.size(), start, end); LOG(INFO) << "Prefix removed"; int32_t last_position = -1; while (start != end) { uint8_t candidate = (*start)->reversed_name.at(0); auto sub_entries_end = start + 1; for (; sub_entries_end != end; sub_entries_end++) { if ((*sub_entries_end)->reversed_name.at(0) != candidate) { break; } } LOG(INFO)<< "Sub entries size: " << sub_entries_end - start; writer.WriteChar(candidate, huffman_table_, huffman_builder_); LOG(INFO)<< "Candidate written: " << candidate; if (candidate == kTerminalValue) { if (sub_entries_end - start != 1) { return false; } if (!(*start)->entry->WriteEntry(&writer)) { return false; } LOG(INFO)<< "Entry written"; } else { RemovePrefix(1, start, sub_entries_end); uint32_t table_position; if (!WriteDispatchTables(start, sub_entries_end, &table_position)) { return false; } LOG(INFO)<< "Dispatch table written"; writer.WritePosition(table_position, &last_position); LOG(INFO)<< "Position written: " << table_position; } start = sub_entries_end; } writer.WriteChar(kEndOfTableValue, huffman_table_, huffman_builder_); LOG(INFO)<< "End of table written"; *position = buffer_.position(); writer.Flush(); writer.WriteToBitWriter(&buffer_); LOG(INFO)<< "Buffer flushed"; return true; }
-
@JonB
Okay, I found the issue.It happens in the WriteDispatchTables function:
uint8_t candidate = (*start)->reversed_name.at(0); auto sub_entries_end = start + 1;
If reversed_name is empty, this line will crash due to out-of-bounds access on .at(0).
Tracing back, this function is called from WriteEntries:
bool TrieWriter::WriteEntries(const TrieEntries& entries, uint32_t* root_position) { if (entries.empty()) return false; ReversedEntries reversed_entries; for (auto* const entry : entries) { if (entry->name().empty()) { LOG(INFO) << "Skipping empty hostname entry"; continue; } auto reversed_entry = std::make_unique<ReversedEntry>(ReverseName(entry->name()), entry); reversed_entries.push_back(std::move(reversed_entry)); } std::stable_sort(reversed_entries.begin(), reversed_entries.end(), CompareReversedEntries); return WriteDispatchTables(reversed_entries.begin(), reversed_entries.end(), root_position); }
So if we don’t filter out empty entry->name() values beforehand, ReverseName() returns a vector with only the kTerminalValue, and after removing prefixes (in RemovePrefix), the reversed_name may become empty — leading to a crash when .at(0) is accessed.
Adding a check to skip empty hostnames in WriteEntries() avoids this edge case and prevents the crash.
wrote 9 days ago last edited by@Esmaeil_Sooan said in Qt6.5.3 Build QtWebEngine for Windows x64. Error: transport_security_state_generator.exe failed with exit code 3221226505:
Adding a check to skip empty hostnames in WriteEntries() avoids this edge case and prevents the crash.
I am just surprised this has not come up more often for other people. Maybe having an empty entry there is not common, I do not know? Anyway I urge you to kindly raise what you think is a bug and your solution at TQtC bugs Url as I posted earlier. Thank you.
-
wrote 9 days ago last edited by
@JonB
Sure, thank you. -
wrote 9 days ago last edited by Esmaeil_Sooan 5 Jul 2025, 09:56
I've reported this issue as a bug at:
https://bugreports.qt.io/browse/QTBUG-136652