Closed n4o847 closed 3 years ago
TransitionMap
は最初に初期化するより遅延的に処理したほうがいいか
反応遅くて申し訳ないです。一つ気づいたんですが、DirectProductNFAやTripleDirectProductNFAという名前になってしまっています
あれ、ソースコード内でですか? どの辺でしょう、、、
動くには動きましたが、master ブランチの出力と diff とったら
a*
EDA false positivea*?
EDA false positve(.*)="(.*)"
EDA false positive[a-z][0-9a-z]*
EDA false positivea*a*
EDA false positivea*a*
IDA false negativeみたいな感じでしんどい………… (SCC とかがちゃんとできてない気がする)
あれ、ソースコード内でですか? どの辺でしょう、、、
ごめんなさい。見間違えでした。StronglyConectedComponentNFAの方でした。
動くには動きましたが、master ブランチの出力と diff とったら
a*
EDA false positivea*?
EDA false positve(.*)="(.*)"
EDA false positive[a-z][0-9a-z]*
EDA false positivea*a*
EDA false positivea*a*
IDA false negativeみたいな感じでしんどい………… (SCC とかがちゃんとできてない気がする)
途中経過見てみます
前の命名変更プルリクのときにやるべきだったんですが、dpNFA, tdpNFAだけでなく、SCCNFAという名前も変える必要があることに気づきました。(まあこれは後で良いかも知れませんが)
あとは
(a|b)*
EDA false negative(.*)="(.*)"
IDA false ~negative~ positiveになりました
あれ、よく考えたら /^(a|b)*$/
って Safe ですね(https://makenowjust-labo.github.io/redos/ で試してもそうなる)
もとの検出が間違っていたんでしょうか
確認したところ、
(a|b)*
が Safe になった(.*)="(.*)"
が Vulnerable になったので、むしろ今までより改善されていることがわかりました!!
引き続き、他の例でも試してみるなり、コードの変更部分のチェック(特にもともとその部分を書いていた人)はお願いします。
(めちゃくちゃ変えてしまったところもあるので、気に食わないところがあったら変えちゃってください)
前の命名変更プルリクのときにやるべきだったんですが、dpNFA, tdpNFAだけでなく、SCCNFAという名前も変える必要があることに気づきました。(まあこれは後で良いかも知れませんが)
これもなんなら今変えちゃっていいと思います(ちっちゃい変更だとプルリク出すの面倒だと思うので……)
前の命名変更プルリクのときにやるべきだったんですが、dpNFA, tdpNFAだけでなく、SCCNFAという名前も変える必要があることに気づきました。(まあこれは後で良いかも知れませんが)
これもなんなら今変えちゃっていいと思います(ちっちゃい変更だとプルリク出すの面倒だと思うので……)
では自分やります
すみません返信が遅れました、明日の昼ごろに一通りコード読みます、ご了承下さい
すみません返信が遅れました、明日の昼ごろに一通りコード読みます、ご了承下さい
ぜんぜん大丈夫です、ありがとうございます~(そもそも、全員が常にすぐ反応できることを前提にはできないですしね)
TrpleDirectProductGraphの構築のアルゴリズムを読んでも何をやっているのかよく分からないのですが、何かしら間違っている気がします。
今の書き方を尊重するのであれば、次のようになるはずです。
(createState
で存在しない場合に新しい状態を生成して追加するようにすればもっとシンプルになるんじゃないでしょうか)
build(): TripleDirectProductGraph {
// sccGraph1 で lq --char-->ld、
// 元のnfaで cq --char-->cd、
// sccGraph2で rq --char--> rd という辺がある場合に、
// (lq, cq, rq) ---char--> (ld, cd, rd) という辺を追加
for (const lq of this.sccGraph1.stateList) {
for (const cq of this.nfa.stateList) {
for (const rq of this.sccGraph2.stateList) {
for (const char of this.nfa.alphabet) {
for (const ld of sumOfTwoSccTransitions.get(lq, char)) {
for (const cd of sumOfTwoSccTransitions.get(cq, char)) {
for (const rd of sumOfTwoSccTransitions.get(rq, char)) {
let source = this.getState(lq, cq, rq);
if (source === null) {
source = this.createState(lq, cq, rq);
}
let dest = this.getState(ld, cd, rd);
if (dest === null) {
dest = this.createState(ld, cd, rd);
}
this.newTransitions.add(source, char, dest);
}
}
}
}
}
}
}
// IDA判定のために、強連結成分間の戻る辺を追加
for (const lq of this.sccGraph1.stateList) {
for (const rq of this.sccGraph2.stateList) {
let source = this.getState(lq, rq, rq);
if (source === null) {
source = this.createState(lq, rq, re);
}
let dest = this.getState(lq, lq, rq);
if (dest === null) {
dest = this.createState(lq, lq, re);
}
// 'back' をIDA判別のために追加した辺のラベルということにする
this.newTransition(source, 'back', dest);
}
}
return {
type: 'TripleDirectProductGraph',
stateList: this.newStateList,
alphabet,
transitions: this.newTransitions,
extraTransitions: this.extraTransitions,
};
}
それと、IDA検出の際に extraTransition
を使って判定していますが、強連結成分の stateList
に lq, lq, rq
相当の頂点と lq, rq, rq
相当の頂点の両方が存在するかを確認すればいいはずです。
function isIDA(tdp: TripleDirectProductGraph): boolean {
const sccs = buildStronglyConnectedComponents(tdp);
return sccs.some((scc) => {
// (lq, lq, rq) と (lq, rq, rq) が存在するかを確認する。
for (const [lq, cq, rq] of scc.stateList.map(s => s.split('_'))) {
if (lq === cq && scc.stateList.includes(`${lq}_${rq}_${rq}`)) {
return true;
}
}
return false;
});
レビューありがとうございます。
上の変更については余裕があれば @masa5555 さんお願いできますか?
State
の扱いはまた全体で改善すべきことなので別の問題として話し合いたいと思います。
charの遷移の変更書いてくださりありがとうございます、本当にお疲れ様でした、と同時に返信が遅れてしまい申し訳ありません。 書き方がきれいで学びが多いコードでした!(直積とEDAの方も変更いい感じだと思います, tripleの方は見ておりません) ではでは気になった点なのですが、
\s
)もしよろしければ自分の方で編集して直しておきます。逆に自分が提案した修正について良からぬことがありそうな場合伝えてくれるとありがたいです。
ありがとうございます!
確かに文字構築の処理はちょっとまだ苦しいところがあります。指摘部分はそのとおりで、場所を変えた方が適切かもしれないです。
\s
はそうか、 unescape もう一回しないといけないんですね、、、。
編集してもらえるとありがたいです、お願いします。
extendAlphabetをenfaに移すとrerejsのCharに関する処理をenfaでやらないと行けなくなってそれもそれで気持ち悪いな(Char関連をめちゃくちゃimportしないといけない...) こんな感じでメンバ関数に隠蔽して、char.tsのextendAlphabetを呼び出していることでお気持ちthis.alphabetを更新しているよと伝えるぐらいが丁度いい気がしてきた...(ここに時間を割くのも違う気がしてきたし)
private extendAlphabet(node: Atom): void {
// NOTE: 計算量が一番少ないthis.alphabetの更新方法
extendAlphabet(this.alphabet, node, this.pattern.flagSet);
}
うーん難しいですね (どちらも気持ちはわかる)
それでもいいと思いますし、任せます(そうするとついでに getChars
もですね)
これViz表示JSON.Stringfyでエスケープ文字を文字列に変換しているのを気づかずに, d.charについてエスケープされるアスキーコードの範囲で場合分けされるみたいな処理を書こうとしてしまった... JSON.Stringfyで変換された文字にバックスラッシュが含まれる場合2個に置換するだけだった getChars, extendAlphabet両方にやっておきました(getCharsは副作用はないがラップしたほうが自然だった). あとそろそろ枝切りに取り組みます、このブランチから派生させようかな
あ、unescape じゃなくて escape だ……まあどっちでもいいです
自分も攻撃文字列の生成をこのブランチから派生させます
(State の変換周辺も直したいのもやまやまですが、うーむ……)
了解です〜 Stateの件すごくわかります....(文字列分解でやるとしたらdirectProductのnewStateToOldStateSetいらねえな...)
今問題なのって(というかこのブランチをマージしていない理由)
ぐらいの認識なので、もしかしたらこのブランチマージしてもいいかもしれませんね(恐らく昔のCharSet利用に戻ることはない気がするので)
かもですね、現状今までより悪化している点は無いはずです。
@masa5555 IDA検出が変更できたら、またプルリク建ててもらって良いでしょうか?
了解です。指摘いただいた点の冗長な表現は削除できたのですが、元々(.*)=(.*)
の検出が上手く行っていないので、アルゴリズムの見直しをしています
まだ正しく動作しないためマージしないでください
18 で指摘いただいたように遷移関数と文字の定義を変更するものです。
手をつけられそうなところから移行していますが、変更が大きいため、ふたりにもしっかりめに確認してもらいたいと思っています。
特に SCC と 3直積は自信が無いです。各自が書いた部分の移行は結構手伝ってほしいところがあります。
主な変更点は以下です。
alphabet: Set<Char>
を持つことを強制します。Char
は #18 で言われた通りの文字です。まだわかりませんが場合によってはalphabet: Char[]
になるかもしれません。どちらにせよalphabet
の列挙によってアルゴリズムが改善できる点があれば変更お願いします。NonEpsilonNFA
移行のオートマトンについて、遷移関数をtransitions: TransitionMap
に変更します。TransitionMap
は独自に定義したクラスで、内部的にはMap<State, Map<Char, State>>
と同じですが、各変換で初期化処理や列挙が面倒になっていることから、共通化したほうが見通しが良いと考えクラスにしました。下手にクラスを持たないほうがいいということであれば変更も考えます。移行がつらいようであれば、時間も厳しいですし断念するかもしれません。