Chromium Chronicle מס' 25: הערות בנושא בטיחות בשרשורים

פרק 25: מאת ויקטור קוסטן ב-SFO (אוקטובר 2021)
פרקים קודמים

ב-C++, שלילת האפשרות של מרוצי נתונים מסתכמת להוכחת תקינות קטנה של אבטחת שרשור לכל גישה של חבר בנתונים. ההוכחות האלה מסתכמות לעמולה נפשית, במיוחד במהלך בדיקה או ארגון מחדש של הקוד. מסגרת הניתוח הסטטית של Clang גוברת על העומס של הוכחות אבטחת השרשור.

הוספה של GUARDED_BY_CONTEXT() לרשימת החברים בנתונים במחלקות לא בטוחות לשרשורים

רוב המחלקות של Chrome לא בטוחות לשרשורים, וצריך להשתמש בהן ברצף אחד. הוספת הערות לכל החברים בנתונים שאינם בטוחים לשרשורים. הערות מיותרות הן בטוחות, אבל אם חסרות הערות, עלולים להיווצר מרוץ נתונים.

#include "base/sequence_checker.h"  // for SEQUENCE_CHECKER()
#include "base/thread_annotations.h"  // for GUARDED_BY_CONTEXT()

class Cache {
  // Methods here.
 private:
  SEQUENCE_CHECKER(sequence_checker_);
  base::flat_map<std::string, std::string> data_ GUARDED_BY_CONTEXT(sequence_checker_);
};

אפליקציית Clang אוכפת בדיקות רצף

בתמורה להערות לגבי החברים בנתונים, Clang מבטיח שכל שיטה שניגשת לנתונים תבצע בדיקת אבטחה של רצף לפני ביצוע הבדיקה. ככל שהקוד מועבר באמצעות ארגון מחדש של הקוד, Clang ממשיך לאכוף את ההערה GUARDED_BY_CONTEXT().

void Cache::Set(base::StringPiece key, base::StringPiece value) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);  // Clang warns without this.
  data_.emplace(key, value);
}

הוספה של GUARDED_BY() לחברי נתונים בכיתות בטוחות לשרשורים שנעשה בהן שימוש ב-mutex

בחלק מהמחלקות ב-Chrome חובה להשתמש בנעילות לצורך בטיחות בשרשורים. במקרים כאלה, צריך להוסיף הערות לכל החברים בנתונים שלא בטוחים לשרשורים. כל הערה מפנה ל-mutex שצריך להחזיק בזמן הגישה אליו.

#include "base/thread_annotations.h"  // for GUARDED_BY()

class ThreadSafeCache {
  // Methods here.
  private:
    base::Lock lock_;
    base::flat_map<std::string, std::string> data_ GUARDED_BY(lock_);
};

Clang אוכפת רכישות של נעילה

חכו ותנו למהדר לוודא שכל base::AutoLock מוגדר להיקף נכון, ושנעילת הקריאות Acquire() ו-Release() מותאמות בצורה נכונה.

void ThreadSafeCache::Set(base::StringPiece key, base::StringPiece value) {
  base::AutoLock auto_lock(lock_);  // Clang warns without this.
  data_.emplace(key, value);
}