SCW アイコン
ヒーロー背景(区切りなし)
ブログ

Javaの落とし穴 - ビット演算子とブール演算子

アラン・リチャードソン
2021年02月07日 掲載
最終更新日: 2026年3月9日

Javaの落とし穴 - ビット演算子とブール演算子

「Java Gotcha」- 意図せず簡単に実現してしまうよくあるエラーパターン。

意外に陥りやすい、かなり単純な Java の問題:論理比較演算子ではなくビット演算子を使用すること。

例えば、実際に「&&」を書きたい場合、単純な入力ミスによって「&」が書き込まれる可能性があります。

コードレビューで学ぶ一般的なヒューリスティック手法は:

条件文で「&」または「|」を使用することは意図的ではない可能性があります。

このブログ記事では、ヒューリスティック手法について考察し、このコーディング問題を特定・修正する方法を明らかにします。


問題はどこにあるのか?ブール演算を使用すればビット単位の演算は正常に行える


ブール値を用いたビット演算子の使用は完全に有効であるため、Javaは構文エラーを報告しません。

もしビット単位の論理和(|)とビット単位の論理積(&)の真理値表を探るために JUnit テストを構築すると、ビット演算子の出力が真理値表と一致することが確認できる。このことから、ビット単位演算子の使用に問題はないと考えられるかもしれない。

AND 真相表

aで3列、bで1列、最後に(a^b)で1列。


@Test
void 論理演算子と真理値表 () {
assertions.asserteQuals(真, 真, 真);
assertions.asserteQuals(偽, 真, 偽);
assertions.asserteQuals(偽, 偽, 真);
assertions.asserteQuals(偽, 偽, 偽);
}


テストは通過しました。これは完全に有効なJavaです。


OR 真相表


aで3列、bで1列、最後に(a v b)で1列。


@Test
void 論理演算子または真値表 () {
assertions.asserteQuals(真,真 | 真);
assertions.asserteQuals(真,真 | 假);
assertions.asserteQuals(真,假 | 真);
assertions.asserteQuals(假,假 | 假);
}


このテストも通過したのに、なぜ私たちは「&&'」と「||'」を好むのか?


真相表画像は作成された 真相表ツール から web.standfor.edu


問題:短絡操作


真の問題は、ビット単位演算子(&、|)と論理演算子(&&、||)の挙動の違いにある。

ブール演算子はショートサーキット演算子であり、必要な場合にのみ評価されます。

例えば

if (args!= null & args.length () > 23) {
system.out.println (args);
}


上記のコードでは、ビット演算子が使用されているため、2つのブール条件が両方とも評価されます:

  • args!= 空値
  • args.length() > 23

もしargsが空の場合、これは私のコードをNullPointerExceptionのリスクに晒します。なぜなら、たとえ引数が空であっても、2つのブール条件を評価する必要があるため、常にargs.lengthをチェックすることになるからです。


ブール演算子のショートサーキット評価


&&を使用する場合、例えば

if (args!= null && args.length () > 23) {
system.out.println (args);
}


args != null の計算結果が false であることがわかれば、条件式の評価はそこで停止する。

右側を評価する必要はありません。

右辺の条件の結果がどうであれ、ブール式の結果は常に偽となる。


しかしこれは本番コードでは決して起こらない


これは非常に起こりやすい間違いであり、静的解析ツールが常にこの間違いを犯すわけではありません。

以下のGoogle Dorkを使用して、このパターンの公開例が見つかるかどうかを確認しました:

ファイルタイプ:java if “!=null &”
今回の検索で rootwindowContainer から Android 由来のコードがいくつか見つかりました
isDocument = インテント!= null & intent.isDocument ()


このコードはコードレビューを通過する可能性があります。なぜなら、代入文でビット演算子を使用して値を隠蔽することがよくあるからです。しかし、この場合の結果は上記のif文の例と同じです。intentが常に空の場合、NullPointerExceptionがスローされます。

私たちはしばしばこの構造から逃れ、防御的コーディングや冗長なコードを書く傾向があります。`check != null` はおそらくほとんどのユースケースで不要です。

これはプログラマーが本番コードで犯すミスである。

検索結果がどれほど新しいかは分かりませんが、検索を行った際、返されたコードの出典は:Google、Amazon、Apache... そして私自身です。

最近のプルリクエストは、私のオープンソースプロジェクトにおいて、まさにこのエラーを解決するために作成されました。

if (键入!=null & type.trim () .length () >0) {
AcceptMediatypeDefinitionsList.add (type.trim ());
}


これをどう見つけるか


私がいくつかの静的解析ツールでサンプルコードを確認した際、いずれもこの隠された自己破壊コードを発見しませんでした。

Secure Code Warrior この問題を解決するための非常にSensei 、検証しました。

ビット演算子は完全に有効であり、代入で頻繁に使用されるため、問題のあるコードを見つけるために、if文の使用例とBitwise &の使用に重点を置いて調査しました。

搜索:
表情:
AnyOF:
-在:
条件:{}
价值:
区分大小写:假
匹配:“.* &。*”


条件式として使用される場合、正規表現を用いて「&」にマッチします。例えばif文の中で。

この問題を修正するため、再び正規表現に頼ります。今回はQuickFixのsed関数を使用し、式内の&を&&にグローバル置換します。

利用可能な修正プログラム:
- 名称:「ビット単位のAND演算子を論理AND演算子に置換」
アクション:
- 上書き:
を「{{#sed}} s/&/&&&g,{{{.}}} {{/sed}}」に変更


脚注

これは、ビット演算子の最も一般的な誤用、つまり実際にはブール演算子を使用すべき場面を網羅しています。

他の状況では、例えばタスクの例のようにこの現象が発生する可能性があります。しかしレシピを作成する際には、偽陽性の認識を可能な限り回避しなければなりません。さもなければレシピが無視されたり無効化されたりするからです。私たちは最も一般的な状況に適合するレシピを作成しています。Senseiの発展に伴い、より多くの条件をカバーするために検索機能に追加の特異性を付与する可能性が高いでしょう。

現状の形式では、この処方箋は多くの実際のユースケースを特定し、そして何よりも、私のプロジェクトで報告されたケースを特定するでしょう。

注意:多くのコード勇士がこの例とレシピのレビューに貢献しました——チャーリー・エリクソン、マシュー・カーリー、ロビン・クレアホート、ブライソン・アクス、ネイサン・デスメット、ドニー・ロバーシュトン。ご協力に感謝します。


---


IntelliJ からSensei をインストールするには、「環境設定\プラグイン」(Mac)または「設定\プラグイン」(Windows)を使用し、「sensei Sensei

Secure Code Warrior アカウントの「senseiリポジトリには、これらのブログ記事(この記事を含む)のソースコードやレシピが多数公開されています。

https://github.com/securecodewarrior/sensei-blog-examples

Sensei に関するSensei


リソースを確認する
リソースを確認する

このブログ記事では、一般的な Java コーディングミス(条件演算子の代わりにビット演算子を使用すること)、それがコードに招く脆弱性、そしてSensei 考察します。

もっと知りたいですか?

アラン・リチャードソンは、20年以上にわたり、開発者として、またテスターからテスト責任者まで、あらゆるレベルのテストに携わってきたプロフェッショナルなIT経験を持っています。アラン・リチャードソンは、Secure Code Warrior のデベロッパーリレーションズの責任者として、チームと直接連携し、高品質で安全なコードの開発を促進しています。また、「Dear Evil Tester」や「Java For Testers」など4冊の著書があります。また、テクニカルWebテストやSelenium WebDriver with Javaを学ぶためのオンライントレーニングcourses を作成しています。アランは、SeleniumSimplified.com、EvilTester.com、JavaForTesters.com、CompendiumDev.co.ukに執筆やトレーニングビデオを掲載している。

もっと詳しく

Secure Code Warriorは、ソフトウェア開発ライフサイクル全体を通じてコードを保護し、サイバーセキュリティを最優先とする文化を醸成するお手伝いをします。AppSecマネージャー、開発者、最高情報セキュリティ責任者(CISO)、あるいはセキュリティに関わるあらゆる方々の組織において、不安全なコードに関連するリスクの低減を支援します。

デモを予約する
共有する:
リンクトインのブランドソーシャルx ロゴ
作者
アラン・リチャードソン
2021年02月07日掲載

アラン・リチャードソンは、20年以上にわたり、開発者として、またテスターからテスト責任者まで、あらゆるレベルのテストに携わってきたプロフェッショナルなIT経験を持っています。アラン・リチャードソンは、Secure Code Warrior のデベロッパーリレーションズの責任者として、チームと直接連携し、高品質で安全なコードの開発を促進しています。また、「Dear Evil Tester」や「Java For Testers」など4冊の著書があります。また、テクニカルWebテストやSelenium WebDriver with Javaを学ぶためのオンライントレーニングcourses を作成しています。アランは、SeleniumSimplified.com、EvilTester.com、JavaForTesters.com、CompendiumDev.co.ukに執筆やトレーニングビデオを掲載している。

共有する:
リンクトインのブランドソーシャルx ロゴ

Javaの落とし穴 - ビット演算子とブール演算子

「Java Gotcha」- 意図せず簡単に実現してしまうよくあるエラーパターン。

意外に陥りやすい、かなり単純な Java の問題:論理比較演算子ではなくビット演算子を使用すること。

例えば、実際に「&&」を書きたい場合、単純な入力ミスによって「&」が書き込まれる可能性があります。

コードレビューで学ぶ一般的なヒューリスティック手法は:

条件文で「&」または「|」を使用することは意図的ではない可能性があります。

このブログ記事では、ヒューリスティック手法について考察し、このコーディング問題を特定・修正する方法を明らかにします。


問題はどこにあるのか?ブール演算を使用すればビット単位の演算は正常に行える


ブール値を用いたビット演算子の使用は完全に有効であるため、Javaは構文エラーを報告しません。

もしビット単位の論理和(|)とビット単位の論理積(&)の真理値表を探るために JUnit テストを構築すると、ビット演算子の出力が真理値表と一致することが確認できる。このことから、ビット単位演算子の使用に問題はないと考えられるかもしれない。

AND 真相表

aで3列、bで1列、最後に(a^b)で1列。


@Test
void 論理演算子と真理値表 () {
assertions.asserteQuals(真, 真, 真);
assertions.asserteQuals(偽, 真, 偽);
assertions.asserteQuals(偽, 偽, 真);
assertions.asserteQuals(偽, 偽, 偽);
}


テストは通過しました。これは完全に有効なJavaです。


OR 真相表


aで3列、bで1列、最後に(a v b)で1列。


@Test
void 論理演算子または真値表 () {
assertions.asserteQuals(真,真 | 真);
assertions.asserteQuals(真,真 | 假);
assertions.asserteQuals(真,假 | 真);
assertions.asserteQuals(假,假 | 假);
}


このテストも通過したのに、なぜ私たちは「&&'」と「||'」を好むのか?


真相表画像は作成された 真相表ツール から web.standfor.edu


問題:短絡操作


真の問題は、ビット単位演算子(&、|)と論理演算子(&&、||)の挙動の違いにある。

ブール演算子はショートサーキット演算子であり、必要な場合にのみ評価されます。

例えば

if (args!= null & args.length () > 23) {
system.out.println (args);
}


上記のコードでは、ビット演算子が使用されているため、2つのブール条件が両方とも評価されます:

  • args!= 空値
  • args.length() > 23

もしargsが空の場合、これは私のコードをNullPointerExceptionのリスクに晒します。なぜなら、たとえ引数が空であっても、2つのブール条件を評価する必要があるため、常にargs.lengthをチェックすることになるからです。


ブール演算子のショートサーキット評価


&&を使用する場合、例えば

if (args!= null && args.length () > 23) {
system.out.println (args);
}


args != null の計算結果が false であることがわかれば、条件式の評価はそこで停止する。

右側を評価する必要はありません。

右辺の条件の結果がどうであれ、ブール式の結果は常に偽となる。


しかしこれは本番コードでは決して起こらない


これは非常に起こりやすい間違いであり、静的解析ツールが常にこの間違いを犯すわけではありません。

以下のGoogle Dorkを使用して、このパターンの公開例が見つかるかどうかを確認しました:

ファイルタイプ:java if “!=null &”
今回の検索で rootwindowContainer から Android 由来のコードがいくつか見つかりました
isDocument = インテント!= null & intent.isDocument ()


このコードはコードレビューを通過する可能性があります。なぜなら、代入文でビット演算子を使用して値を隠蔽することがよくあるからです。しかし、この場合の結果は上記のif文の例と同じです。intentが常に空の場合、NullPointerExceptionがスローされます。

私たちはしばしばこの構造から逃れ、防御的コーディングや冗長なコードを書く傾向があります。`check != null` はおそらくほとんどのユースケースで不要です。

これはプログラマーが本番コードで犯すミスである。

検索結果がどれほど新しいかは分かりませんが、検索を行った際、返されたコードの出典は:Google、Amazon、Apache... そして私自身です。

最近のプルリクエストは、私のオープンソースプロジェクトにおいて、まさにこのエラーを解決するために作成されました。

if (键入!=null & type.trim () .length () >0) {
AcceptMediatypeDefinitionsList.add (type.trim ());
}


これをどう見つけるか


私がいくつかの静的解析ツールでサンプルコードを確認した際、いずれもこの隠された自己破壊コードを発見しませんでした。

Secure Code Warrior この問題を解決するための非常にSensei 、検証しました。

ビット演算子は完全に有効であり、代入で頻繁に使用されるため、問題のあるコードを見つけるために、if文の使用例とBitwise &の使用に重点を置いて調査しました。

搜索:
表情:
AnyOF:
-在:
条件:{}
价值:
区分大小写:假
匹配:“.* &。*”


条件式として使用される場合、正規表現を用いて「&」にマッチします。例えばif文の中で。

この問題を修正するため、再び正規表現に頼ります。今回はQuickFixのsed関数を使用し、式内の&を&&にグローバル置換します。

利用可能な修正プログラム:
- 名称:「ビット単位のAND演算子を論理AND演算子に置換」
アクション:
- 上書き:
を「{{#sed}} s/&/&&&g,{{{.}}} {{/sed}}」に変更


脚注

これは、ビット演算子の最も一般的な誤用、つまり実際にはブール演算子を使用すべき場面を網羅しています。

他の状況では、例えばタスクの例のようにこの現象が発生する可能性があります。しかしレシピを作成する際には、偽陽性の認識を可能な限り回避しなければなりません。さもなければレシピが無視されたり無効化されたりするからです。私たちは最も一般的な状況に適合するレシピを作成しています。Senseiの発展に伴い、より多くの条件をカバーするために検索機能に追加の特異性を付与する可能性が高いでしょう。

現状の形式では、この処方箋は多くの実際のユースケースを特定し、そして何よりも、私のプロジェクトで報告されたケースを特定するでしょう。

注意:多くのコード勇士がこの例とレシピのレビューに貢献しました——チャーリー・エリクソン、マシュー・カーリー、ロビン・クレアホート、ブライソン・アクス、ネイサン・デスメット、ドニー・ロバーシュトン。ご協力に感謝します。


---


IntelliJ からSensei をインストールするには、「環境設定\プラグイン」(Mac)または「設定\プラグイン」(Windows)を使用し、「sensei Sensei

Secure Code Warrior アカウントの「senseiリポジトリには、これらのブログ記事(この記事を含む)のソースコードやレシピが多数公開されています。

https://github.com/securecodewarrior/sensei-blog-examples

Sensei に関するSensei


リソースを確認する
リソースを確認する

以下のフォームに記入してレポートをダウンロードしてください

当社は、当社の製品および/または関連するセキュリティコードに関する情報を送信するため、お客様の許可を得たいと考えております。お客様の個人情報は常に慎重に取り扱い、マーケティング目的で他社に販売することは決してありません。

提出
SCW成功アイコン
SCWエラーアイコン
フォームを送信するには、「分析」Cookieを有効にしてください。完了後、いつでも再度無効にできます。

Javaの落とし穴 - ビット演算子とブール演算子

「Java Gotcha」- 意図せず簡単に実現してしまうよくあるエラーパターン。

意外に陥りやすい、かなり単純な Java の問題:論理比較演算子ではなくビット演算子を使用すること。

例えば、実際に「&&」を書きたい場合、単純な入力ミスによって「&」が書き込まれる可能性があります。

コードレビューで学ぶ一般的なヒューリスティック手法は:

条件文で「&」または「|」を使用することは意図的ではない可能性があります。

このブログ記事では、ヒューリスティック手法について考察し、このコーディング問題を特定・修正する方法を明らかにします。


問題はどこにあるのか?ブール演算を使用すればビット単位の演算は正常に行える


ブール値を用いたビット演算子の使用は完全に有効であるため、Javaは構文エラーを報告しません。

もしビット単位の論理和(|)とビット単位の論理積(&)の真理値表を探るために JUnit テストを構築すると、ビット演算子の出力が真理値表と一致することが確認できる。このことから、ビット単位演算子の使用に問題はないと考えられるかもしれない。

AND 真相表

aで3列、bで1列、最後に(a^b)で1列。


@Test
void 論理演算子と真理値表 () {
assertions.asserteQuals(真, 真, 真);
assertions.asserteQuals(偽, 真, 偽);
assertions.asserteQuals(偽, 偽, 真);
assertions.asserteQuals(偽, 偽, 偽);
}


テストは通過しました。これは完全に有効なJavaです。


OR 真相表


aで3列、bで1列、最後に(a v b)で1列。


@Test
void 論理演算子または真値表 () {
assertions.asserteQuals(真,真 | 真);
assertions.asserteQuals(真,真 | 假);
assertions.asserteQuals(真,假 | 真);
assertions.asserteQuals(假,假 | 假);
}


このテストも通過したのに、なぜ私たちは「&&'」と「||'」を好むのか?


真相表画像は作成された 真相表ツール から web.standfor.edu


問題:短絡操作


真の問題は、ビット単位演算子(&、|)と論理演算子(&&、||)の挙動の違いにある。

ブール演算子はショートサーキット演算子であり、必要な場合にのみ評価されます。

例えば

if (args!= null & args.length () > 23) {
system.out.println (args);
}


上記のコードでは、ビット演算子が使用されているため、2つのブール条件が両方とも評価されます:

  • args!= 空値
  • args.length() > 23

もしargsが空の場合、これは私のコードをNullPointerExceptionのリスクに晒します。なぜなら、たとえ引数が空であっても、2つのブール条件を評価する必要があるため、常にargs.lengthをチェックすることになるからです。


ブール演算子のショートサーキット評価


&&を使用する場合、例えば

if (args!= null && args.length () > 23) {
system.out.println (args);
}


args != null の計算結果が false であることがわかれば、条件式の評価はそこで停止する。

右側を評価する必要はありません。

右辺の条件の結果がどうであれ、ブール式の結果は常に偽となる。


しかしこれは本番コードでは決して起こらない


これは非常に起こりやすい間違いであり、静的解析ツールが常にこの間違いを犯すわけではありません。

以下のGoogle Dorkを使用して、このパターンの公開例が見つかるかどうかを確認しました:

ファイルタイプ:java if “!=null &”
今回の検索で rootwindowContainer から Android 由来のコードがいくつか見つかりました
isDocument = インテント!= null & intent.isDocument ()


このコードはコードレビューを通過する可能性があります。なぜなら、代入文でビット演算子を使用して値を隠蔽することがよくあるからです。しかし、この場合の結果は上記のif文の例と同じです。intentが常に空の場合、NullPointerExceptionがスローされます。

私たちはしばしばこの構造から逃れ、防御的コーディングや冗長なコードを書く傾向があります。`check != null` はおそらくほとんどのユースケースで不要です。

これはプログラマーが本番コードで犯すミスである。

検索結果がどれほど新しいかは分かりませんが、検索を行った際、返されたコードの出典は:Google、Amazon、Apache... そして私自身です。

最近のプルリクエストは、私のオープンソースプロジェクトにおいて、まさにこのエラーを解決するために作成されました。

if (键入!=null & type.trim () .length () >0) {
AcceptMediatypeDefinitionsList.add (type.trim ());
}


これをどう見つけるか


私がいくつかの静的解析ツールでサンプルコードを確認した際、いずれもこの隠された自己破壊コードを発見しませんでした。

Secure Code Warrior この問題を解決するための非常にSensei 、検証しました。

ビット演算子は完全に有効であり、代入で頻繁に使用されるため、問題のあるコードを見つけるために、if文の使用例とBitwise &の使用に重点を置いて調査しました。

搜索:
表情:
AnyOF:
-在:
条件:{}
价值:
区分大小写:假
匹配:“.* &。*”


条件式として使用される場合、正規表現を用いて「&」にマッチします。例えばif文の中で。

この問題を修正するため、再び正規表現に頼ります。今回はQuickFixのsed関数を使用し、式内の&を&&にグローバル置換します。

利用可能な修正プログラム:
- 名称:「ビット単位のAND演算子を論理AND演算子に置換」
アクション:
- 上書き:
を「{{#sed}} s/&/&&&g,{{{.}}} {{/sed}}」に変更


脚注

これは、ビット演算子の最も一般的な誤用、つまり実際にはブール演算子を使用すべき場面を網羅しています。

他の状況では、例えばタスクの例のようにこの現象が発生する可能性があります。しかしレシピを作成する際には、偽陽性の認識を可能な限り回避しなければなりません。さもなければレシピが無視されたり無効化されたりするからです。私たちは最も一般的な状況に適合するレシピを作成しています。Senseiの発展に伴い、より多くの条件をカバーするために検索機能に追加の特異性を付与する可能性が高いでしょう。

現状の形式では、この処方箋は多くの実際のユースケースを特定し、そして何よりも、私のプロジェクトで報告されたケースを特定するでしょう。

注意:多くのコード勇士がこの例とレシピのレビューに貢献しました——チャーリー・エリクソン、マシュー・カーリー、ロビン・クレアホート、ブライソン・アクス、ネイサン・デスメット、ドニー・ロバーシュトン。ご協力に感謝します。


---


IntelliJ からSensei をインストールするには、「環境設定\プラグイン」(Mac)または「設定\プラグイン」(Windows)を使用し、「sensei Sensei

Secure Code Warrior アカウントの「senseiリポジトリには、これらのブログ記事(この記事を含む)のソースコードやレシピが多数公開されています。

https://github.com/securecodewarrior/sensei-blog-examples

Sensei に関するSensei


ウェビナーを視聴する
始めましょう
もっと詳しく

以下のリンクをクリックして、このリソースのPDFをダウンロードしてください。

Secure Code Warriorは、ソフトウェア開発ライフサイクル全体を通じてコードを保護し、サイバーセキュリティを最優先とする文化を醸成するお手伝いをします。AppSecマネージャー、開発者、最高情報セキュリティ責任者(CISO)、あるいはセキュリティに関わるあらゆる方々の組織において、不安全なコードに関連するリスクの低減を支援します。

レポートを確認するデモを予約する
PDFをダウンロード
リソースを確認する
共有する:
リンクトインのブランドソーシャルx ロゴ
もっと知りたいですか?

共有する:
リンクトインのブランドソーシャルx ロゴ
作者
アラン・リチャードソン
2021年02月07日掲載

アラン・リチャードソンは、20年以上にわたり、開発者として、またテスターからテスト責任者まで、あらゆるレベルのテストに携わってきたプロフェッショナルなIT経験を持っています。アラン・リチャードソンは、Secure Code Warrior のデベロッパーリレーションズの責任者として、チームと直接連携し、高品質で安全なコードの開発を促進しています。また、「Dear Evil Tester」や「Java For Testers」など4冊の著書があります。また、テクニカルWebテストやSelenium WebDriver with Javaを学ぶためのオンライントレーニングcourses を作成しています。アランは、SeleniumSimplified.com、EvilTester.com、JavaForTesters.com、CompendiumDev.co.ukに執筆やトレーニングビデオを掲載している。

共有する:
リンクトインのブランドソーシャルx ロゴ

Javaの落とし穴 - ビット演算子とブール演算子

「Java Gotcha」- 意図せず簡単に実現してしまうよくあるエラーパターン。

意外に陥りやすい、かなり単純な Java の問題:論理比較演算子ではなくビット演算子を使用すること。

例えば、実際に「&&」を書きたい場合、単純な入力ミスによって「&」が書き込まれる可能性があります。

コードレビューで学ぶ一般的なヒューリスティック手法は:

条件文で「&」または「|」を使用することは意図的ではない可能性があります。

このブログ記事では、ヒューリスティック手法について考察し、このコーディング問題を特定・修正する方法を明らかにします。


問題はどこにあるのか?ブール演算を使用すればビット単位の演算は正常に行える


ブール値を用いたビット演算子の使用は完全に有効であるため、Javaは構文エラーを報告しません。

もしビット単位の論理和(|)とビット単位の論理積(&)の真理値表を探るために JUnit テストを構築すると、ビット演算子の出力が真理値表と一致することが確認できる。このことから、ビット単位演算子の使用に問題はないと考えられるかもしれない。

AND 真相表

aで3列、bで1列、最後に(a^b)で1列。


@Test
void 論理演算子と真理値表 () {
assertions.asserteQuals(真, 真, 真);
assertions.asserteQuals(偽, 真, 偽);
assertions.asserteQuals(偽, 偽, 真);
assertions.asserteQuals(偽, 偽, 偽);
}


テストは通過しました。これは完全に有効なJavaです。


OR 真相表


aで3列、bで1列、最後に(a v b)で1列。


@Test
void 論理演算子または真値表 () {
assertions.asserteQuals(真,真 | 真);
assertions.asserteQuals(真,真 | 假);
assertions.asserteQuals(真,假 | 真);
assertions.asserteQuals(假,假 | 假);
}


このテストも通過したのに、なぜ私たちは「&&'」と「||'」を好むのか?


真相表画像は作成された 真相表ツール から web.standfor.edu


問題:短絡操作


真の問題は、ビット単位演算子(&、|)と論理演算子(&&、||)の挙動の違いにある。

ブール演算子はショートサーキット演算子であり、必要な場合にのみ評価されます。

例えば

if (args!= null & args.length () > 23) {
system.out.println (args);
}


上記のコードでは、ビット演算子が使用されているため、2つのブール条件が両方とも評価されます:

  • args!= 空値
  • args.length() > 23

もしargsが空の場合、これは私のコードをNullPointerExceptionのリスクに晒します。なぜなら、たとえ引数が空であっても、2つのブール条件を評価する必要があるため、常にargs.lengthをチェックすることになるからです。


ブール演算子のショートサーキット評価


&&を使用する場合、例えば

if (args!= null && args.length () > 23) {
system.out.println (args);
}


args != null の計算結果が false であることがわかれば、条件式の評価はそこで停止する。

右側を評価する必要はありません。

右辺の条件の結果がどうであれ、ブール式の結果は常に偽となる。


しかしこれは本番コードでは決して起こらない


これは非常に起こりやすい間違いであり、静的解析ツールが常にこの間違いを犯すわけではありません。

以下のGoogle Dorkを使用して、このパターンの公開例が見つかるかどうかを確認しました:

ファイルタイプ:java if “!=null &”
今回の検索で rootwindowContainer から Android 由来のコードがいくつか見つかりました
isDocument = インテント!= null & intent.isDocument ()


このコードはコードレビューを通過する可能性があります。なぜなら、代入文でビット演算子を使用して値を隠蔽することがよくあるからです。しかし、この場合の結果は上記のif文の例と同じです。intentが常に空の場合、NullPointerExceptionがスローされます。

私たちはしばしばこの構造から逃れ、防御的コーディングや冗長なコードを書く傾向があります。`check != null` はおそらくほとんどのユースケースで不要です。

これはプログラマーが本番コードで犯すミスである。

検索結果がどれほど新しいかは分かりませんが、検索を行った際、返されたコードの出典は:Google、Amazon、Apache... そして私自身です。

最近のプルリクエストは、私のオープンソースプロジェクトにおいて、まさにこのエラーを解決するために作成されました。

if (键入!=null & type.trim () .length () >0) {
AcceptMediatypeDefinitionsList.add (type.trim ());
}


これをどう見つけるか


私がいくつかの静的解析ツールでサンプルコードを確認した際、いずれもこの隠された自己破壊コードを発見しませんでした。

Secure Code Warrior この問題を解決するための非常にSensei 、検証しました。

ビット演算子は完全に有効であり、代入で頻繁に使用されるため、問題のあるコードを見つけるために、if文の使用例とBitwise &の使用に重点を置いて調査しました。

搜索:
表情:
AnyOF:
-在:
条件:{}
价值:
区分大小写:假
匹配:“.* &。*”


条件式として使用される場合、正規表現を用いて「&」にマッチします。例えばif文の中で。

この問題を修正するため、再び正規表現に頼ります。今回はQuickFixのsed関数を使用し、式内の&を&&にグローバル置換します。

利用可能な修正プログラム:
- 名称:「ビット単位のAND演算子を論理AND演算子に置換」
アクション:
- 上書き:
を「{{#sed}} s/&/&&&g,{{{.}}} {{/sed}}」に変更


脚注

これは、ビット演算子の最も一般的な誤用、つまり実際にはブール演算子を使用すべき場面を網羅しています。

他の状況では、例えばタスクの例のようにこの現象が発生する可能性があります。しかしレシピを作成する際には、偽陽性の認識を可能な限り回避しなければなりません。さもなければレシピが無視されたり無効化されたりするからです。私たちは最も一般的な状況に適合するレシピを作成しています。Senseiの発展に伴い、より多くの条件をカバーするために検索機能に追加の特異性を付与する可能性が高いでしょう。

現状の形式では、この処方箋は多くの実際のユースケースを特定し、そして何よりも、私のプロジェクトで報告されたケースを特定するでしょう。

注意:多くのコード勇士がこの例とレシピのレビューに貢献しました——チャーリー・エリクソン、マシュー・カーリー、ロビン・クレアホート、ブライソン・アクス、ネイサン・デスメット、ドニー・ロバーシュトン。ご協力に感謝します。


---


IntelliJ からSensei をインストールするには、「環境設定\プラグイン」(Mac)または「設定\プラグイン」(Windows)を使用し、「sensei Sensei

Secure Code Warrior アカウントの「senseiリポジトリには、これらのブログ記事(この記事を含む)のソースコードやレシピが多数公開されています。

https://github.com/securecodewarrior/sensei-blog-examples

Sensei に関するSensei


目次

PDFをダウンロード
リソースを確認する
もっと知りたいですか?

アラン・リチャードソンは、20年以上にわたり、開発者として、またテスターからテスト責任者まで、あらゆるレベルのテストに携わってきたプロフェッショナルなIT経験を持っています。アラン・リチャードソンは、Secure Code Warrior のデベロッパーリレーションズの責任者として、チームと直接連携し、高品質で安全なコードの開発を促進しています。また、「Dear Evil Tester」や「Java For Testers」など4冊の著書があります。また、テクニカルWebテストやSelenium WebDriver with Javaを学ぶためのオンライントレーニングcourses を作成しています。アランは、SeleniumSimplified.com、EvilTester.com、JavaForTesters.com、CompendiumDev.co.ukに執筆やトレーニングビデオを掲載している。

もっと詳しく

Secure Code Warriorは、ソフトウェア開発ライフサイクル全体を通じてコードを保護し、サイバーセキュリティを最優先とする文化を醸成するお手伝いをします。AppSecマネージャー、開発者、最高情報セキュリティ責任者(CISO)、あるいはセキュリティに関わるあらゆる方々の組織において、不安全なコードに関連するリスクの低減を支援します。

デモを予約するダウンロード
共有する:
リンクトインのブランドソーシャルx ロゴ
リソースセンター

入門に役立つリソース

さらに多くの投稿
リソースセンター

入門に役立つリソース

さらに多くの投稿