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() به اعضای داده در کلاس های Thread-safe که از mutexe استفاده می کنند اضافه کنید.

برخی از کلاس‌ها در 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);
}