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

\ifpdfprimitive のハッシュ値の衝突 #29

Closed
aminophen opened this issue Sep 20, 2017 · 29 comments
Closed

\ifpdfprimitive のハッシュ値の衝突 #29

aminophen opened this issue Sep 20, 2017 · 29 comments
Labels

Comments

@aminophen
Copy link
Member

\ifpdfprimitive (pdfTeX / e-pTeX) と \ifprimitive (XeTeX / LuaTeX) について,ツイッターのこの辺で見つかった挙動です。LuaTeX では正常のようですが,ほかでは誤った判定になる例があります。(例:現在の TeX Live では \ifpdfprimitive\␣ が pdfTeX / e-pTeX / XeTeX で偽)

ここからの連続ツイートの説明で納得しましたが,この誤判定は「プリミティブが prim_table に登録されるときに,単文字の名前と複数文字の名前に同じハッシュ値が与えられる」ことに起因します。LuaTeX では単文字の名前が特別扱いされないので誤動作は起きないようですが,それ以外では単文字のプリミティブ \␣, \/, \- で問題が起きている(あるいは今後起きる可能性がある)ようです。

@aminophen aminophen added the bug label Sep 20, 2017
@h-kitagawa
Copy link
Member

d079aaa で直したつもりです.

@aminophen
Copy link
Member Author

aminophen commented Sep 21, 2017

d079aaa

私のところのテストケースは

% Single-character primitives (ex_space, ital_corr)
\catcode`\X=14\relax
\catcode`\P=14\relax
\ifx\primitive\undefined
  \ifx\pdfprimitive\undefined
  \else
    \catcode`\P=9\relax
    % pdfTeX and e-(u)pTeX
    P\ifpdfprimitive\ [1:TRUE]\else[1:FALSE]\fi
    P\ifpdfprimitive\/[2:TRUE]\else[2:FALSE]\fi
    P\ifpdfprimitive\-[3:TRUE]\else[3:FALSE]\fi
  \fi
\else
    \catcode`\X=9\relax
    % XeTeX and LuaTeX
    X\ifprimitive\ [1:TRUE]\else[1:FALSE]\fi
    X\ifprimitive\/[2:TRUE]\else[2:FALSE]\fi
    X\ifprimitive\-[3:TRUE]\else[3:FALSE]\fi
\fi
\end

ですが(全部 TRUE になるはず),まだ直っていないように見えます。

→ おっと,フォーマットが fmtutil-user のものが残っていたみたいorz 直っているようです。失礼しました。

@aminophen
Copy link
Member Author

同じパッチが pdftex.web, xetex.web にも少しの offset または fuzz だけで当たりますが,pdfTeX が直る一方で XeTeX は期待する結果にならないので,XeTeX はまた別のところに問題があるのかも…

@h-kitagawa
Copy link
Member

h-kitagawa commented Sep 21, 2017

pdfTeX では

@d single_base=active_base+256 {equivalents of one-character control sequences}
@d null_cs=single_base+256 {equivalent of \.{\\csname\\endcsname}}

ですが,XeTeX では扱える文字が増えて

@d single_base=active_base+number_usvs
   {equivalents of one-character control sequences}
@d null_cs=single_base+number_usvs {equivalent of \.{\\csname\\endcsname}}

となっています(number_usvs = 0x110000).そのため,XeTeX では prim_lookup(cur_cs-257) の部分を prim_lookup(cur_cs-number_usvs-1) とかなんとかに直さないといけないのではないかと思います.

@h-kitagawa
Copy link
Member

h-kitagawa commented Sep 22, 2017

d079aaa にはバグがありました.prim_prime を 433 などのもっと小さな素数にすると起こりますが,今度は複数文字の制御綴の情報を一文字のそれが上書きしてしまうことが起こります.

@zr-tex8r
Copy link

(てきとーなことを言ってみる)

そもそも、通常のハッシュはともかくとして、このプリミティブ用のハッシュで「単文字を特別扱い」する必要ってあるんですかね?アクセスされる頻度は低そうですし。

@zr-tex8r
Copy link

(てきとーな疑問)

XeTeXで例えば\ifprimitive\☃とすると、“という文字列”を引数にしてprim_lookup()が呼ばれることになるはずだけど、その場合の実際の引数(s)の値はなんだろう。"2603ではなさそう。

@aminophen
Copy link
Member Author

aminophen commented Sep 22, 2017

XeTeXで例えば\ifprimitive\☃とすると(以下略)

私も同じ疑問を持っていました。(eptex などの従来挙動は \pdfprimitive\␣ すると,32 つまり \vrule と同じになっていたのですが,xetex は単に空っぽな感じがしていた。)

@zr-tex8r
Copy link

zr-tex8r commented Sep 22, 2017

自分の予想としては、prim_base=256 にすればよい(で、単文字の部分に無駄が生じるから prim_size を増やす)、と考えてる。

あるいは、単文字の場合に p:=s にするのはいいとして、そのあとは“複数文字の場合に合流”してリハッシュ可能にすればよさそう。

--- old\pdfutils.ch	2017-04-25 06:02:26.000000000 +0900
+++ pdfutils.ch	2017-09-23 01:08:07.564214600 +0900
@@ -506,8 +506,8 @@
 @!j,@!l:integer;
 begin
 if s<256 then begin
-  p := s;
-  if (p<0) or (prim_eq_level(p)<>level_one) then
+  p := s; l := length(s);
+  if (p<0) then
     p := undefined_primitive;
 end
 else begin
@@ -515,6 +515,7 @@
   if s = str_ptr then l := cur_length else l := length(s);
   @<Compute the primitive code |h|@>;
   p:=h+prim_base; {we start searching here; note that |0<=h<hash_prime|}
+end;
   loop@+begin if prim_text(p)>0 then if length(prim_text(p))=l then
     if str_eq_str(prim_text(p),s) then goto found;
     if prim_next(p)=0 then
@@ -526,7 +527,6 @@
       end;
     p:=prim_next(p);
     end;
-  end;
 found: prim_lookup:=p;
 end;
 

(またてきとーなこと言ってる)

@h-kitagawa
Copy link
Member

“複数文字の場合に合流”してリハッシュ可能にすればよさそう

12d0ee2 でそんな感じの処理にしています.
prim_text の値を単文字の場合は 1--256,複数文字の場合は 257 を足すことにしていますが,
今考えるとこの部分は余計だったかなと思います(元々複数文字を表す文字列は 256 以上なので).

@aminophen
Copy link
Member Author

aminophen commented Sep 23, 2017

f2e5cf7 を試してみると ok でした。同じ方式で pdfTeX / XeTeX も ok になるようなので(当ててみたパッチはこれ),大丈夫なのだと思います。

eptexdir/ は texjporg が upstream なのでコミット可ですが,pdftexdir/ と xetexdir/ は tex-k, pdftex, xetex あたりに報告していただくことになると思います。

@h-kitagawa
Copy link
Member

h-kitagawa commented Sep 23, 2017

動作チェックどうもありがとうございます.一箇所 end のインデント位置を直したり,行末の余計なスペースを削除したりしました.

pdftexdir/ と xetexdir/ は tex-k, pdftex, xetex あたりに報告していただくことになる

eptexdir/ が texjporg にコミットされたあとにやっておきます.
(edit: tex-k の報告しました.9/24 08:30 ごろ)

@aminophen
Copy link
Member Author

master ヘマージし,eptexdir/ は r45386 で(バージョン番号を 170924 にして)コミットしました。

@aminophen
Copy link
Member Author

r45394, r45395 確認しました。どうもありがとうございます。

@aminophen aminophen reopened this Sep 24, 2017
@aminophen
Copy link
Member Author

aminophen commented Sep 24, 2017

今度は以下の挙動が気になってきました。 \q という命令はないはずなのですが,\pdfprimitive\ \q という順で実行すると,Undefined control sequence エラーが出ません。pdfTeX / e-(u)pTeX / XeTeX でエラーなしの一方で,LuaTeX では期待どおりエラーになります。

%#!eptex
\pdfprimitive\par\q     % ! Undefined control sequence.
\pdfprimitive\ \q       % no error
\pdfprimitive\/\q       % ! Undefined control sequence.
\pdfprimitive\ [\q]\end % ! Undefined control sequence.

@h-kitagawa
Copy link
Member

全然わからないのですが,any_mode(ignore_spaces): 内の 1045 行目前後を

    if cur_cs<>undefined_primitive then begin
      cur_cmd := prim_eq_type(cur_cs);
      cur_chr := prim_equiv(cur_cs);
      cur_tok := (cur_cmd*@'400)+cur_chr; { ←こいつをたしてみる }
      end;

と1行足すとエラーが出るようになりましたが,間違っている予感しかしません.衝突する \ \vrule で起こるのがなんとも.

@aminophen
Copy link
Member Author

aminophen commented Sep 24, 2017

衝突する \ と \vrule で起こるのがなんとも.

本当だ! 以下のソース,あるいはその一行目と二行目を入れ替えたソースで,必ず二行目だけがエラーになるので,初期化が漏れているとかそういう感じなのでしょうね。

\pdfprimitive\ \q       % no error
\pdfprimitive\vrule\q   % error
\end

→ どうやら「垂直モードだとエラー」らしい。

@aminophen
Copy link
Member Author

aminophen commented Sep 24, 2017

4d4690f を試してみると,以下のソースが eptex / euptex で ok になりました。

%#!eptex
% description of the bug:
% in vertical mode, the error "! Undefined control sequence."
% does not appear

\def\MODE{%
  \ifinner\message{I}\else\message{E}\fi
  \ifvmode\message{V}\else\message{H}\fi
}

\MODE\ \MODE     % => "\ " begins horizontal mode

\MODE\vrule\MODE % => "\vrule" begins horizontal mode

% ----- "\par" is ok

\MODE % => E V
\pdfprimitive\par\q   % ! Undefined control sequence.

% ----- "\ " is wrong

\MODE % => E V
\pdfprimitive\ \q     % no error
\MODE % => E H
\pdfprimitive\ \q     % ! Undefined control sequence.

\MODE % => E V
\pdfprimitive\ \q     % no error

% ----- "\vrule" is wrong

\MODE % => E V
\pdfprimitive\vrule\q % no error
\MODE % => E H
\pdfprimitive\vrule\q % ! Undefined control sequence.

\MODE % => E V
\pdfprimitive\vrule\q % no error

% -----

\MODE % => E V
\end

pdftex に同じ変更を適用すると

! Undefined control sequence.
<recently read> \^^@

が余分に出るので,そちらは要調整のようです。

@h-kitagawa
Copy link
Member

pdftex に同じ変更を適用すると

! Undefined control sequence.
^^@

が余分に出る

こちらでは再現しませんでした,あれえ…….

@aminophen
Copy link
Member Author

aminophen commented Sep 25, 2017

いったんパッチを外して TeX Live svn r45398 の状態に戻し,再度 eptexdir/ と pdftexdir/ に北川さんの f269224 を当て直してビルドしましたが,やはり結果は同じで,pdftex だけは

! Undefined control sequence.
<recently read> \^^@

が余分に出て,出力の PDF には Θ のような文字が出てきます。

例によって環境は OS X 10.11.6 El Capitan (x86_64-darwin) です。テストソースと eptex / pdftex それぞれでのログを置いておきます

@aminophen
Copy link
Member Author

Windows 7 Professional Service Pack 1 (64bit) 上の MSVC12 (Visual Studio 2013) で Win32 バイナリをビルドしてみましたが (eptex.dll, pdftex.dll),これも Mac での結果と同一で

  • eptex では正常
  • pdftex では ! Undefined control sequence. \^^@ が余分に出て,出力に Θ が発生

でした。私のパッチの当て方さえ間違っていなければ,環境依存の問題ではない気がします。

@h-kitagawa
Copy link
Member

h-kitagawa commented Sep 25, 2017

環境依存の問題ではない気がします。

今,別PC(Gentoo Linux, amd64)でもう一回やってみたところ,再現しました.今日の朝のは何だったんだろう.

試していないので推測ですが,cur_cmd*256+cur_chr が 16384 となり,cs_token_flag (=4095) を超えてしまうのが原因かも.pTeX 系は cs_token_flag が 65535 なのでこの状況は起こりませんが,今度は和文文字トークンとかぶってしまう恐れがあります.(edit: 9/26 10:00)

@h-kitagawa
Copy link
Member

cur_cmd*256+cur_chr が 16384 となり,cs_token_flag (=4095) を超えてしまう

配列 prim_eqtb をメインの配列 eqtb に統合させたパッチを作ってみました (https://gist.github.com/h-kitagawa/8c0bb24f7436a9fb5c851358b577f054 ).こうすると最初から cur_tokcs_token_flag と (配列 eqtb における index)の和にできるので,衝突はしないように思われます.

@aminophen
Copy link
Member Author

配列 prim_eqtb をメインの配列 eqtb に統合させたパッチを

テスト結果は eptex/euptex/pdftex/xetex 全て正常でした。ありがとうございます。

@aminophen
Copy link
Member Author

r45482 で e-(u)pTeX の部分だけコミットしました。pdfTeX / XeTeX の方のレポートはまたお願いしてもよろしいでしょうか? > @h-kitagawa さん

@h-kitagawa
Copy link
Member

pdfTeX / XeTeX の方のレポートはまたお願いしてもよろしいでしょうか?

数日前に報告しました.e-[u]pTeX 側は直ったということで,クローズします.

@h-kitagawa
Copy link
Member

次のテストソースで ! Missing { inserted.エラーが発生する症状を見つけました.
pdfTeX, XeTeX (に以前 gist であげたパッチを適用したもの)ではまた別種のエラーが発生します.
今日・明日で直そうと思います.

\ifdefined\pdfprimitive \else\let\pdfprimitive=\primitive\fi

\count0=\vrule1
\count0=\pdfprimitive\X1
\count0=\pdfprimitive\vrule1
\end

@h-kitagawa h-kitagawa reopened this Nov 5, 2017
@aminophen
Copy link
Member Author

次のテストソースで ! Missing { inserted.エラーが発生する症状を見つけました.

私のところ (OS X 10.11.6 x86_64-darwin) では

! Missing number, treated as zero.
<to be read again> 
                   \BAD.
l.5 \count0=\pdfprimitive\vrule
                               1
? 

でした。ちなみに luatex も似た感じです。

! Missing number, treated as zero.
<to be read again> 
BAD
l.5 \count0=\pdfprimitive\vrule
                             1
? 

@aminophen
Copy link
Member Author

Fixed in r45956.

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