Skip to content
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

[(u)pTeX] 禁則テーブルのハッシュ検索バグ #113

Closed
aminophen opened this issue May 13, 2021 · 16 comments
Closed

[(u)pTeX] 禁則テーブルのハッシュ検索バグ #113

aminophen opened this issue May 13, 2021 · 16 comments
Labels

Comments

@aminophen
Copy link
Member

https://oku.edu.mie-u.ac.jp/tex/mod/forum/discuss.php?d=3113 を参照。

ptex-base.ch の get_kinsoku_pos 関数の assignment における挙動が変だと思います。

@aminophen aminophen added the bug label May 13, 2021
@aminophen
Copy link
Member Author

aminophen commented May 13, 2021

(原因はわかったのですがCコンパイラが入ったマシンを持ってきていないので,修正ができない…。)

今回のテストケースと,過去の #26, #57 のテストケースをもう一度走らせる必要がありますね。

@aminophen
Copy link
Member Author

aminophen commented May 15, 2021

とりあえず試してみているコード:

--- ptex-base.ch.1~	Thu Feb 18 11:48:14 2021
+++ ptex-base.ch	Sat May 15 13:45:47 2021
@@ -6646,8 +6646,8 @@
 @ @<Declare procedures needed in |scan_something_internal|@>=
 function get_kinsoku_pos(c:KANJI_code; n:small_number):pointer;
 label done, done1;
-var p,s:pointer;
-begin s:=calc_pos(c); p:=s;
+var p,pp,s:pointer;
+begin s:=calc_pos(c); p:=s; pp:=no_entry;
 @!debug
 print_ln; print("c:="); print_int(c); print(", p:="); print_int(s);
 if p+kinsoku_base<0 then
@@ -6656,16 +6656,19 @@
 gubed
 if n=new_pos then
   begin repeat
-  if (kinsoku_type(p)=0)or(kinsoku_type(p)=kinsoku_unused_code)
-    or(kinsoku_code(p)=c) then goto done;
+  if kinsoku_code(p)=c then goto done;  { found, update there }
+  if kinsoku_type(p)=0 then             { no further scan needed }
+    begin if pp<>no_entry then p:=pp; goto done; end;
+  if kinsoku_type(p)=kinsoku_unused_code then
+    if pp=no_entry then pp:=p; { save the nearest unused hash }
   incr(p); if p>255 then p:=0;
   until s=p;
-  p:=no_entry;
+  p:=pp;
   end
 else
   begin repeat
-  if kinsoku_type(p)=0 then goto done1
-  else if (kinsoku_type(p)<>kinsoku_unused_code)and(kinsoku_code(p)=c) then goto done;
+  if kinsoku_type(p)=0 then goto done1;
+  if kinsoku_code(p)=c then goto done;
   incr(p); if p>255 then p:=0;
   until s=p;
 done1: p:=no_entry;

@aminophen
Copy link
Member Author

禁則テーブルのほかに INHIBIT テーブルも同様なはずなので更新 ↓

--- ptex-base.ch.1~	Thu Feb 18 11:48:14 2021
+++ ptex-base.ch	Sat May 15 14:44:20 2021
@@ -6574,19 +6574,23 @@
 @ @<Declare procedures needed in |scan_something_internal|@>=
 function get_inhibit_pos(c:KANJI_code; n:small_number):pointer;
 label done, done1;
-var p,s:pointer;
-begin s:=calc_pos(c); p:=s;
+var p,pp,s:pointer;
+begin s:=calc_pos(c); p:=s; pp:=no_entry;
 if n=new_pos then
   begin repeat
-  if (inhibit_xsp_type(p)=inhibit_unused)or(inhibit_xsp_code(p)=0)
-    or(inhibit_xsp_code(p)=c) then goto done;
+  if inhibit_xsp_code(p)=c then goto done;  { found, update there }
+  if inhibit_xsp_code(p)=0 then             { no further scan needed }
+    begin if pp<>no_entry then p:=pp; goto done; end;
+  if inhibit_xsp_type(p)=inhibit_unused then
+    if pp=no_entry then pp:=p; { save the nearest unused hash }
   incr(p); if p>255 then p:=0;
-  until s=p; p:=no_entry;
+  until s=p;
+  p:=pp;
   end
 else
   begin repeat
-  if inhibit_xsp_code(p)=0 then goto done1
-  else if (inhibit_xsp_type(p)<>inhibit_unused)and(inhibit_xsp_code(p)=c) then goto done;
+  if inhibit_xsp_code(p)=0 then goto done1;
+  if inhibit_xsp_code(p)=c then goto done;
   incr(p); if p>255 then p:=0;
   until s=p;
 done1: p:=no_entry;
@@ -6621,6 +6625,7 @@
 begin scan_int; q:=get_inhibit_pos(tokanji(cur_val),cur_pos);
 cur_val_level:=int_val; cur_val:=inhibit_none;
 if q<>no_entry then cur_val:=inhibit_xsp_type(q);
+if cur_val>inhibit_none then cur_val:=inhibit_none;
 end
 
 @ The \.{\\prebreakpenalty} is used to specified amount of penalties inserted
@@ -6646,8 +6651,8 @@
 @ @<Declare procedures needed in |scan_something_internal|@>=
 function get_kinsoku_pos(c:KANJI_code; n:small_number):pointer;
 label done, done1;
-var p,s:pointer;
-begin s:=calc_pos(c); p:=s;
+var p,pp,s:pointer;
+begin s:=calc_pos(c); p:=s; pp:=no_entry;
 @!debug
 print_ln; print("c:="); print_int(c); print(", p:="); print_int(s);
 if p+kinsoku_base<0 then
@@ -6656,16 +6661,19 @@
 gubed
 if n=new_pos then
   begin repeat
-  if (kinsoku_type(p)=0)or(kinsoku_type(p)=kinsoku_unused_code)
-    or(kinsoku_code(p)=c) then goto done;
+  if kinsoku_code(p)=c then goto done;  { found, update there }
+  if kinsoku_type(p)=0 then             { no further scan needed }
+    begin if pp<>no_entry then p:=pp; goto done; end;
+  if kinsoku_type(p)=kinsoku_unused_code then
+    if pp=no_entry then pp:=p; { save the nearest unused hash }
   incr(p); if p>255 then p:=0;
   until s=p;
-  p:=no_entry;
+  p:=pp;
   end
 else
   begin repeat
-  if kinsoku_type(p)=0 then goto done1
-  else if (kinsoku_type(p)<>kinsoku_unused_code)and(kinsoku_code(p)=c) then goto done;
+  if kinsoku_type(p)=0 then goto done1;
+  if kinsoku_code(p)=c then goto done;
   incr(p); if p>255 then p:=0;
   until s=p;
 done1: p:=no_entry;

@aminophen
Copy link
Member Author

上のコメントのパッチを適用した Win32 バイナリを置いてみます → ptex-new.zip

@aminophen
Copy link
Member Author

さらに \tracingassigns 用のコードも詳しくしてみる(上への追加) → ptex-new-2.zip

--- ptex-base.ch.1~	2021-02-18 11:48:14.000000000 +0900
+++ ptex-base.ch	2021-05-15 20:41:11.327346800 +0900
@@ -1249,10 +1249,27 @@
     begin print_esc("xspcode"); print_int(n-auto_xsp_code_base);
     end
   else if n<kinsoku_base then
-    begin print("(inhibitxspcode table) "); print_int(n-inhibit_xsp_code_base);
+    begin print("inhibitxspcode table "); print_int(n-inhibit_xsp_code_base);
+      print(", type=");
+      case eq_type(n) of
+        0: print("both");   { |inhibit_both| }
+        1: print("before"); { |inhibit_previous| }
+        2: print("after");  { |inhibit_after| }
+        3: print("none");   { |inhibit_none| }
+        4: print("unused"); { |inhibit_unused| }
+      end; {there are no other cases}
+      print(", code");
     end
   else if n<kansuji_base then
-    begin print("(kinsoku table) "); print_int(n-kinsoku_base);
+    begin print("kinsoku table "); print_int(n-kinsoku_base);
+      print(", type=");
+      case eq_type(n) of
+        0: print("no");
+        1: print("pre");    { |pre_break_penalty_code| }
+        2: print("post");   { |post_break_penalty_code| }
+        3: print("unused"); { |kinsoku_unused_code| }
+      end; {there are no other cases}
+      print(", code");
     end
   else if n<lc_code_base then
     begin print_esc("kansujichar"); print_int(n-kansuji_base);
@@ -1412,7 +1429,10 @@
 tats
 @y
 else if n<kinsoku_penalty_base then @<Show equivalent |n|, in region 6@>
-else if n<=eqtb_size then print("kinsoku")
+else if n<=eqtb_size then begin
+  print("kinsoku table "); print_int(n-kinsoku_penalty_base);
+  print(", penalty="); print_int(eqtb[n].int);
+  end
 else print_char("?"); {this can't happen either}
 end;
 tats

h-kitagawa added a commit to h-kitagawa/tex-jp-build that referenced this issue May 15, 2021
@h-kitagawa
Copy link
Member

とりあえず aminophen さんの 2 パッチを h-kitagawa@8039073 に入れておきました.

@aminophen
Copy link
Member Author

本 issue を Pull request にした #120 をマージしました。

  • 禁則テーブルの検索の修正 → r59700

なお,r59701 でバージョンを p3.9.1 にしています。

@aminophen
Copy link
Member Author

aminophen commented Feb 9, 2025

TeX Live 2024 の (e)(u)ptex で euptexdir/tests/kinsoku_table.tex を走らせると Segmentation fault: 11 する件について,どうやら 2022-12-12 r65246--65248 で禁則テーブルなどのサイズが 256→1024 に拡大された時(このあたり)からのようです。これが

2024-09-21  TANAKA Takuji  <[email protected]>
	* ptex-base.ch:
	Fix a bug in initialization of inhibit_xsp/kinsoku tables
	(Bug introduced on commit 2022-12-12 r65248).

r72333 で修正されたらしいのですが,今度はテーブルが 256 文字しか登録できなくなってしまったようです?

%#!euptex -ini -etex
\let\dump\relax
\input plain
\newlinechar`^^J

% 無駄に256個埋める
\count200="10000
\loop\ifnum\count200<"10100\relax
  \omathchardef\X=\the\count200
  \message{\meaning\X: \the\prebreakpenalty\count200^^J}
  \prebreakpenalty\count200=\count200
  \message{\meaning\X: => \the\prebreakpenalty\count200^^J}
  \advance\count200 by 1
\repeat

% 257個目
\prebreakpenalty`、=100

\bye
% => ! KINSOKU table is full!!.

@aminophen aminophen reopened this Feb 9, 2025
@h-kitagawa
Copy link
Member

kinsoku_type(k) が 0<=k<=255 の場合のみ 0 に初期化されている?

@aminophen
Copy link
Member Author

aminophen commented Feb 9, 2025

kinsoku_type(k) が 0<=k<=255 の場合のみ 0 に初期化されている?

はい,そうなのですが,そうなったのは r72333 で意図的なようで…。???

恐らく

TeX Live 2024 の (e)(u)ptex で euptexdir/tests/kinsoku_table.tex を走らせると Segmentation fault: 11 する件

を直したとされる r72333 が正しい修正策ではなく,見た目上 segv しなくなったけれども 256〜1023 の初期化が消えてしまったものかと。

@aminophen
Copy link
Member Author

私の手元では euptex -ini -etex で先ほどの例を走らせた時

  • TeX Live 2022 x86_64-darwinlegacy の euptex u1.28 では ! KINSOKU table is full!! ← これは 256→1024 拡張前
  • TeX Live 2023 x86_64-darwinlegacy の euptex u1.29 では Segmentation fault: 11 ← (!?)
  • TeX Live 2024 x86_64-darwinlegacy の euptex u1.30 では Segmentation fault: 11 ← (!?)
  • 2024-06-14 に自前ビルドした euptex u1.35 ではエラーなく通る
  • 最新の euptex u2.00 では ! KINSOKU table is full!!

となりました。

@h-kitagawa
Copy link
Member

eqtb[] の kinsoku_penalty_base 以降の場所にペナルティの値を格納するようですが,この部分を 256 -> 1024 と拡大するのを忘れていたようです.

@aminophen
Copy link
Member Author

eqtb[] の kinsoku_penalty_base 以降の場所にペナルティの値を格納するようですが,この部分を 256 -> 1024 と拡大するのを忘れていたようです.

なるほど。ありがとうございます。

cdfcee9

こちらについては inhibit_xsp_type(k)=0; も同様に移動してよろしいでしょうか?

@h-kitagawa
Copy link
Member

h-kitagawa commented Feb 9, 2025

cdfcee9

こちらについては inhibit_xsp_type(k)=0; も同様に移動してよろしいでしょうか?

試していませんが,同様に移動してよいかと思います(\inhibitxspcode 周りについては別テーブルがないので).

@t-tk
Copy link
Collaborator

t-tk commented Feb 9, 2025

r72333 が正しい修正策ではなく,見た目上 segv しなくなったけれども 256〜1023 の初期化が消えてしまった

ご指摘いただいた通りと思います。

kinsoku_code(k):=0; もまとめてしまってよいと思います。

@aminophen
Copy link
Member Author

ありがとうございます。r73803 で修正をコミットしました。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants