​​メモリセーフ言語としてLabVIEW​

概要

​​NI LabVIEWは、データ収集、計測器制御、およびテスト自動化に広く使用されているグラフィカルプログラミングプラットフォームです。メモリの安全性に関する脆弱性は、従来のソフトウェア環境の多くで問題となっていますが、LabVIEWはそのアーキテクチャと設計原則によって際立っています。 このホワイトペーパーでは、LabVIEWをメモリセーフ言語(MSL)にするメカニズムと機能、これらの属性と従来のプログラミング言語の違い、および堅牢で信頼性が高く安全なアプリケーションを求める開発者への影響について説明します。 

 

​​メモリの安全性は、ソフトウェアのセキュリティと信頼性にとって重要です。バッファオーバーフロー、解放後使用エラー、およびダングリングポインタなどの従来のメモリ安全性の問題は、CやC++などの言語のソフトウェアの欠陥やセキュリティの脆弱性の大部分の原因となっています。1 それに対し、LabVIEWは、高レベルのデータフロー駆動型グラフィカル環境によって、これらのリスクの多くを抽象化します。 

内容

メモリ安全その重要性について

メモリ安全性とは、プログラムが明確に定義された予測可能な方法でメモリにアクセスすることを保証することです。この機能は、破損、リーク、意図しない境界外へのデータの書き込みを防ぐのに役立ちます。これらのメモリの問題により、クラッシュや未定義の動作が発生する可能性があります。さらに悪いことに、脅威アクターはメモリの問題を操作して任意のコードを実行し、メモリバグを重大なセキュリティの脆弱性に変えます。メモリの安全性に関する懸念事項には、以下のタイプの問題が含まれます。 
 

  • バッファオーバーフロー―割り当てられたメモリの境界外に書き込みます。 
  • ダングリングポインタ―すでに解放されたメモリにアクセスします。 
  • 解放後に使用―メモリ位置のポインタを解放後に使用します。 
  • メモリリーク―メモリの解放に失敗し、リソースが徐々に枯渇します。 

ダイレクトメモリアクセスを提供する言語 (たとえばポインタを使用) は、特にこれらの問題の影響を受けやすくなります。一方、メモリセーフな言語では、開発者による直接メモリ管理を制限または完全に抽象化します。 

LabVIEWメモリモデル

LabVIEWは、従来のテキストベースの言語とは根本的に異なります。グラフィカルプログラミングのパラダイムは、ノード間のデータフロー(VI)によってコードの実行が決定されるデータフローの原則に基づいています。

LabVIEW固有のアーキテクチャには、メモリの安全性を促進する次のような特徴があります。

  • ポインタを直接操作しない―LabVIEWはメモリアドレスやポインタを開発者に公開しません。
  • 自動メモリ管理―LabVIEWは、必要に応じて変数、配列、およびストラクチャのメモリの割り当てと割り当て解除を行います。
  • タイプ安全性―LabVIEW環境では、編集時および実行時に強力なタイプが強制されます。
  • 不変ワイヤ値―データがワイヤに入力されると(変数のグラフィカルな表現に相当)、プログラム内の他の箇所で予期せず変更することはできません。
  • リファレンスカウントとガベージコレクション―LabVIEWはデータ寿命を管理して、メモリが使用されなくなったときに自動的にメモリが再利用されるようにします。

データフローダイその影響

LabVIEWでは、プログラムは機能ブロックをデータを扱うワイヤで接続して構築されます。各ブロックは、すべての必要な入力が使用可能な場合にのみ実行され、データが生成される前にデータ位置にアクセスできないため、メモリ競合状態を回避できます。

 

LabVIEW NI-DAQmxのブロック図

図1.LabVIEWコード例

このモデルは、命令型言語での不適切な操作シーケンスによって発生する多くのプログラミングエラーを回避します。

メモリ割り当て管理

LabVIEWランタイムエンジンは、すべてのメモリの割り当てと割り当て解除を行います。開発者はメモリを手動で要求または解放する必要がないため、リークや解放後使用エラーのリスクを排除できます。配列またはクラスタ (構造体のようなデータ) が拡大または縮小すると、LabVIEWは関連するメモリを透過的に管理します。たとえば、開発者が配列を作成するループを作成した場合、LabVIEWは自動的に配列のサイズを変更し、関連するメモリ領域を管理します。配列変数がスコープ外になると、LabVIEWのガベージコレクタはメモリを再利用します。

強力付け境界チェック

LabVIEW開発環境は、VIのコンパイルおよび実行時に厳密なタイプチェックを実行します。互換性のないデータタイプ同士を配線しようとする試みは編集時に検出され、ランタイムエラーを防ぎます。さらに、配列および文字列操作には、バッファオーバーフローを防止するための境界チェックが含まれます。

レベルメモリ制御なし

最も効果的な対策の1つは、低レベルメモリ制御を行わないことです。LabVIEWには、ユーザが任意ポインタ演算を実行したり、メモリに直接アクセスするためのメカニズムはありません。 この設計は、スタックまたはヒープオーバーフローなど、Cまたはアセンブリで一般的な脆弱性が、ネイティブLabVIEWコードでは発生しないことを意味します。

比較解析:LabVIEWメモリ安全従来言語

LabVIEWのメモリ安全性を理解するには、C、C++、Java、Pythonなどの言語と比較することが有益です。

  • C/C++―これらの言語は直接メモリにアクセスするため、メモリを手動で管理する必要があり、さまざまなメモリ安全エラーが発生しやすくなります。CISAでは、新規プロジェクトにC/C++を使用することを推奨していません。
  • Java/Python―これらの言語は自動メモリ管理を提供しますが、間接的なメモリエラーは許容されます。たとえば、多くの基本的なPythonモジュールはCで作成されており、これらのモジュールのバグはPythonアプリケーションのメモリ問題につながる可能性があります。また、Pythonは、他の真のMSLのように実行時にメモリ安全ルールを強制しません。
  • LabVIEW―LabVIEWはポインタを提供せず、完全管理メモリによる厳密なタイプ指定により、攻撃対象領域とエラーのリスクを大幅に削減します。LabVIEWでは、C/C++で書かれたDLLを呼び出せるため、メモリの問題が生じる可能性があります。

 

まとめると、LabVIEWの設計は、バッファオーバーフローなどのメモリ関連の脆弱性のカテゴリ全体を排除し、安全なアプリケーション開発を簡素化することで、PythonやJavaと同様の保護機能を備えたCやC++などの従来の言語よりも大きな利点を提供します。

LabVIEW安全アプリケーション使用する利点

LabVIEWのメモリの安全性は、開発者、組織、およびエンドユーザにとって明白な利点があります。

  • セキュリティの脆弱性のリスクを低減―バッファオーバーフローとポインタの不正使用を排除することで、多くの一般的な攻撃ベクトルを回避できます。
  • 高い信頼性―検出が困難なメモリエラーによりアプリケーションがクラッシュする可能性が低くなります。
  • 開発の迅速化―開発者は、メモリ割り当てや割り当て解除のバグを気にすることなく、アプリケーションロジックに集中できます。
  • 保守が容易―LabVIEWコードは、デバッグや保守にコストと時間がかかる原因となるような、微妙な低レベルのエラーの発生が少なくなります。
  • セーフティクリティカルアプリケーション―LabVIEWは、ラボオートメーション、工業制御、科学研究など、信頼性が最も重要な環境でよく使用されます。

バッファオーバーフロー防止

従来のバッファオーバーフローは、データが固定長バッファの境界を超えると発生し、隣接するメモリが上書きされ、任意のコードが実行される可能性があります。LabVIEWでは、配列および文字列操作は常に境界チェックされます。配列または文字列の末尾を超えて書き込もうとすると、サイレントメモリ破損ではなくランタイムエラーが発生します。

潜在制限ベストィス

他のメモリセーフ環境と同様に、LabVIEWの境界を理解することが重要です。

  • 外部コードの統合―LabVIEW から「ライブラリ関数呼び出しノード」を使用して外部ライブラリ (DLL、共有ライブラリ) を呼び出すと、それらのライブラリ自体が安全でない場合にメモリ安全性の問題が発生する可能性があります。
  • リソースの枯渇―無限ループやメモリ割り当ての制御が不十分な場合、破損ではなくメモリの枯渇につながる可能性があります。
  • バージョン互換性―LabVIEWの進化に伴い、メモリ管理の最適化など特定の動作が変更される場合があり、レガシーコードのアップグレードや移植には注意が必要です。

外部コードを呼び出す際の安全性を最大限に高めるには、以下のベストプラクティスに従ってください。

  • 危険なコードを分離―危険なライブラリ呼び出しを別のモジュールまたはプロセスにカプセル化します。 マイクロサービスまたはIPC (プロセス間通信) を使用して、メモリが安全でないコードを分離します。 こうすることで、安全でないコードのクラッシュやメモリ破損が発生しても、アプリケーション全体が停止することはありません。
  • 入力と出力を厳密に検証する―メモリの破損は、多くの場合、不正な入力または予期しない出力から発生します。 安全でないライブラリとの間で渡されるすべてのデータを検証します。 境界チェック、ヌルチェック、およびタイプアサートを使用します。
  • スタティックおよびダイナミック解析ツールを使用―メモリの問題を早期に検出するツールを使用します。LabVIEWプロフェッショナルに含まれているLabVIEWのスタティックおよびダイナミックメモリツールを使用して、メモリの問題をテストします。
  • 危険表面積を最小化―危険ライブラリから必要最小限の機能のみを公開します。 絶対に必要でない限り、複雑なデータストラクチャやポインタは渡さないでください。 インタフェースはできるだけシンプルで明確に定義してください。
  • 監査と監視―LabVIEWプログラムによって呼び出される外部コードを定期的に監査します。 

LabVIEW開発者自信ってビルド

LabVIEWの設計は、グラフィカルなデータフローパラダイム、強力なタイプチェック、自動メモリ管理、および直接ポインタ操作のない設計に基づいており、メモリ安全性の高い環境を提供します。開発者は、メモリ関連のバグのリスクを軽減し、生産性を向上させ、要求の厳しいセーフティクリティカルな業界向けのアプリケーションを確実に構築できるメリットがあります。

エラーの影響をまったく受けない環境はありませんが(特に安全でない外部コンポーネントと対話する場合)、LabVIEWは従来のテキストベースの言語に比べてメモリの安全性を大幅に向上させます。計測、自動化、制御アプリケーションに信頼性とセキュリティを求める組織にとって、LabVIEWはメモリセーフな開発に最適な製品です。

特徴C/C++Python/JavaLabVIEW
メモリアクセスダイレクトメモリアクセスダイレクトメモリアクセスなしダイレクトメモリアクセスなし
メモリ管理手動メモリ管理(エラーが発生しやすい)自動メモリ管理自動メモリ管理
エラーの可能性メモリ安全エラー (例: バッファオーバーフロー) のリスクが大きい厳密な入力とメモリ管理により、リスクを大幅に軽減厳密な入力とメモリ管理により、リスクを大幅に軽減
ポインタポインタの多用、複雑さとリスクの増大ポインタの直接使用不可ポインタの直接使用不可
セキュリティメモリを手動で処理し、バッファオーバーフローの影響を受けやすいため、攻撃対象領域が大きいバッファオーバーフローやポインタエクスプロイトの影響を受けない最小の攻撃対象領域バッファオーバーフローやポインタエクスプロイトの影響を受けない最小の攻撃対象領域

1 「メモリセーフ言語:『Reducing Vulnerabilities in Modern Software Development』、サイバーセキュリティおよびインフラストラクチャ庁、2025年6月、https://www.cisa.gov/resources-tools/resources/memory-safe-languages-reducing-vulnerabilities-modern-software-development。

 

JavaはOracleおよびその関連会社の登録商標です。その他の名前はそれぞれの所有者の商標です。