Chromium Chronicle #25: anotações de segurança de linhas de execução

Episódio 25:por Victor Costan no São Francisco (outubro de 2021)
Episódios anteriores

Em C++, descartar a possibilidade de disputa de dados se resume a uma pequena prova de correção da segurança de linhas de execução para cada acesso de membro dos dados. Essas provas contribuem para uma grande quantidade de tarefas repetitivas, especialmente ao revisar ou refatorar o código. O framework de análise estática do Clang assume as tarefas repetitivas que comprovam a segurança das linhas de execução (link em inglês).

Adicionar GUARDED_BY_CONTEXT() aos membros de dados em classes não seguras para linhas de execução

A maioria das classes do Chrome não é segura para linhas de execução e precisa ser usada em uma única sequência. Adicione anotações a todos os membros de dados que não são thread-safe. Anotações desnecessárias são seguras, mas anotações ausentes são um risco de disputa de dados.

#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_);
};

O Clang aplica verificações de sequência

Em troca da anotação dos membros de dados, O Clang garante que todos os métodos que acessam os dados realizem uma confirmação de segurança de sequência antes de fazer isso. Conforme o código é movido em refatoração, O Clang continua aplicando a anotação 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);
}

Adicione GUARDED_BY() aos participantes de dados em classes seguras para linhas de execução que usam exclusões múltiplas.

Algumas classes no Chrome precisam usar bloqueios para a segurança das linhas de execução. Nesses casos, anote todos os membros de dados que não são thread-safe. Cada anotação aponta para um mutex que deve ser mantido ao acessar o membro de dados.

#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_);
};

O Clang aplica aquisições de bloqueio

Aguarde e deixe o compilador verificar se o escopo de cada base::AutoLock está correto, e que as chamadas de bloqueio Acquire() e Release() sejam pareadas corretamente.

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