Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions TeXmacs/tests/tmu/201_72.tmu
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<TMU|<tuple|1.1.0|2026.1.2>>

<style|<tuple|generic|chinese|table-captions-above|number-europe|preview-ref>>

<\body>
<\show-preamble>
<assign|theorem|<with|color|<value|backcolor>|>>

\;

\;

\;

\;

\;

\;

\;

\;
</show-preamble>

<\ignore>
\;
</ignore>
</body>

<\initial>
<\collection>
<associate|page-medium|paper>
<associate|page-screen-margin|false>
</collection>
</initial>
17 changes: 17 additions & 0 deletions devel/201_72.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# 201_72 修复导言区调用未定义颜色变量导致软件崩溃

## 如何测试
1. 打开 TeXmacs/tests/tmu/201_72.tmu 文件
2. `Ctrl+Shift+p`进入导言区
3. 鼠标光标移动到`backcolor`后回车应该不会导致软件闪退问题

## 2026/2/4
### What
1. 在 `src/Graphics/Renderer/brush.cpp` 的 `make_brush(tree p, int a)` 中增加非法 pattern 输入校验,遇到异常复合树时回退为 `no_brush`。
2. 在 `src/Graphics/Renderer/brush.cpp` 的 `get_pattern_data(...)` 中增加结构和 URL 健壮性检查,非法输入回退到安全默认值,避免继续解包。

### Why
`<value|backcolor>` 在变量未定义时会产生异常值,该值进入颜色渲染链路后被误当作 pattern 解包。
MuPDF 路径中会继续读取非法 pattern 图像信息(日志可见 `bad image size for '{}'`),最终触发 SIGSEGV。


45 changes: 43 additions & 2 deletions src/Graphics/Renderer/brush.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,20 @@ make_brush (color c) {
else return tm_new<color_brush_rep> (c);
}

/**
* @brief 根据颜色描述树创建画刷对象。
* @param p 画刷输入描述,支持两种形态:
* - 原子树:颜色名,例如 "red"、"#ff0000"、"none"。
* - 复合树:PATTERN(image, w, h, color),当前实现要求 N(p) == 4。
* - p[0]:pattern 资源标识(通常是图片路径,必须为原子)。
* - p[1]:宽度表达式(例如 "20"、"100%")。
* - p[2]:高度表达式(例如 "20"、"100%")。
* - p[3]:叠加颜色名(传给 named_color,与 a 一起决定最终颜色)。
* 示例:
* - p = "blue"
* - p = (PATTERN "paper.png" "100%" "100%" "white")
* @param a 透明度 alpha,通常取值范围 [0, 255]。
*/
static brush_rep*
make_brush (tree p, int a) {
if (is_atomic (p)) {
Expand All @@ -146,8 +160,19 @@ make_brush (tree p, int a) {
else return make_brush (named_color (s, a));
}
else {
// 防御性处理:复合树必须是合法 PATTERN 结构。
// 否则继续解包可能在访问 pattern[1]/pattern[2]/pattern[3] 时触发异常。
// - L (p) != PATTERN:节点类型不对
// - N (p) != 4:参数个数不对(后续会读取 p[3])
// - !is_atomic (p[0]):资源标识形态不对(应为原子)
// - as_string (p[0]) == "" || "{}":资源标识为空或占位
if (L (p) != moebius::PATTERN || N (p) != 4 || !is_atomic (p[0]))
return tm_new<no_brush_rep> ();
// p[0] 为空串或 "{}" 时直接回退 no_brush,避免后续取图路径异常。
if (as_string (p[0]) == "" || as_string (p[0]) == "{}")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

通过 LABEL来看

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

L(p)

return tm_new<no_brush_rep> ();
color c= white;
if (N (p) == 4) c= named_color (as_string (p[3]), a);
c = named_color (as_string (p[3]), a);
return tm_new<pattern_brush_rep> (c, p, a);
}
}
Expand Down Expand Up @@ -176,7 +201,23 @@ void
get_pattern_data (url& u, SI& w, SI& h, tree& eff, brush br, SI pixel) {
// FIXME << what's about ratio and percentages wrt paper lengths?
tree pattern= br->get_pattern ();
u = br->get_pattern_url ();
// 防御性处理:如果 pattern 结构不完整,直接回退到安全默认值,
// 避免访问 pattern[1]/pattern[2] 时越界导致崩溃。
if (is_atomic (pattern) || N (pattern) < 3 || !is_atomic (pattern[0])) {
u = url ();
w = 35;
h = 35;
eff= tree ("");
return;
}
u= br->get_pattern_url ();
if (is_none (u) || as_string (u) == "" || as_string (u) == "{}") {
u = url ();
w = 35;
h = 35;
eff= tree ("");
return;
}
int imw_pt, imh_pt;
image_size (u, imw_pt, imh_pt);
double pt = ((double) 600 * PIXEL) / 72.0;
Expand Down