From 324ff67ee0450e9b953bf36a0a83d5aa1ac70aed Mon Sep 17 00:00:00 2001 From: fszontagh Date: Thu, 27 Aug 2026 12:20:21 +0200 Subject: [PATCH 1/2] fix: bound plain-text runs in parse_prompt_attention regex --- ggml | 2 +- src/core/util.cpp | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/ggml b/ggml index 8e800cef2..032b6997d 160000 --- a/ggml +++ b/ggml @@ -1 +1 @@ -Subproject commit 8e800cef2948046cc47f9db6090491c6128ca42c +Subproject commit 032b6997db4c9c75dc85d8d2bb2beec77b1231b0 diff --git a/src/core/util.cpp b/src/core/util.cpp index ff53c65fc..ce97546c9 100644 --- a/src/core/util.cpp +++ b/src/core/util.cpp @@ -801,7 +801,11 @@ std::vector> parse_prompt_attention(const std::str float round_bracket_multiplier = 1.1f; float square_bracket_multiplier = 1 / 1.1f; - std::regex re_attention(R"(\\\(|\\\)|\\\[|\\\]|\\\\|\\|\(|\[|:([+-]?[.\d]+)\)|\)|\]|\bBREAK\b|[^\\()\[\]:B]+|:|\bB)"); + // libstdc++ std::regex recurses per matched character; unbounded runs overflow + // the stack. Split runs are merged back by the equal-weight pass below. + const int max_plain_text_run = 1024; + std::regex re_attention(R"(\\\(|\\\)|\\\[|\\\]|\\\\|\\|\(|\[|:([+-]?[.\d]+)\)|\)|\]|\bBREAK\b|[^\\()\[\]:B]{1,)" + + std::to_string(max_plain_text_run) + R"(}|:|\bB)"); std::regex re_break(R"(\s*\bBREAK\b\s*)"); auto multiply_range = [&](int start_position, float multiplier) { From d3cb32d17f060f10a392eceeb13f3b28fe455b4f Mon Sep 17 00:00:00 2001 From: fszontagh Date: Wed, 2 Sep 2026 09:39:38 +0200 Subject: [PATCH 2/2] fix: bound the weight run and parse it without exceptions --- src/core/util.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/core/util.cpp b/src/core/util.cpp index ce97546c9..201f9b46f 100644 --- a/src/core/util.cpp +++ b/src/core/util.cpp @@ -804,7 +804,9 @@ std::vector> parse_prompt_attention(const std::str // libstdc++ std::regex recurses per matched character; unbounded runs overflow // the stack. Split runs are merged back by the equal-weight pass below. const int max_plain_text_run = 1024; - std::regex re_attention(R"(\\\(|\\\)|\\\[|\\\]|\\\\|\\|\(|\[|:([+-]?[.\d]+)\)|\)|\]|\bBREAK\b|[^\\()\[\]:B]{1,)" + + const int max_weight_chars = 32; + std::regex re_attention(R"(\\\(|\\\)|\\\[|\\\]|\\\\|\\|\(|\[|:([+-]?[.\d]{1,)" + + std::to_string(max_weight_chars) + R"(})\)|\)|\]|\bBREAK\b|[^\\()\[\]:B]{1,)" + std::to_string(max_plain_text_run) + R"(}|:|\bB)"); std::regex re_break(R"(\s*\bBREAK\b\s*)"); @@ -827,7 +829,13 @@ std::vector> parse_prompt_attention(const std::str square_brackets.push_back((int)res.size()); } else if (!weight.empty()) { if (!round_brackets.empty()) { - multiply_range(round_brackets.back(), std::stof(weight)); + // strtof does not throw, and a non-finite weight would poison every + // multiplier that follows. + float weight_value = std::strtof(weight.c_str(), nullptr); + if (!std::isfinite(weight_value)) { + weight_value = 1.0f; + } + multiply_range(round_brackets.back(), weight_value); round_brackets.pop_back(); } } else if (text == ")" && !round_brackets.empty()) {