Güvenlik

Olabildiği Kadar Çok Const

const derleyiciye o değişkenin veya metodun değiştirilemez (immutable) olduğunu söyler. Bu derleyicinin kodu optimize etmesine ve developer'ın fonksiyonun beklenenin dışında birşey yapabilecekse farkında olmasına yardımcı olur. Ayrıca const & kullanmak, derleyicinin gereksiz yere kopyalama yapmasını önler. John Carmack'ın const üzerine yorumları da iyi bir okumadır.

// Kotu Fikir
class MyClass
{
public:
  void do_something(int i);
  void do_something(std::string str);
};


// Iyi Fikir
class MyClass
{
public:
  void do_something(const int i);
  void do_something(const std::string &str);
};

Dönüş Tiplerini Dikkatlice Düşün

  • Getter fonksiyonlar
    • & veya const &ile döndürmek, döndürülen değerin normal kullanımı gözlem amaçlı olduğunda önemli performans kazanımları sağlar
    • Eğer döndürülen değer normal kullanımda ne de olsa bir kopya üretecekse, değer ile döndürmek thread güvenliği için daha iyidir, bir performaz kaybı oluşturmaz
    • Eğer API'n birbirinin çeşidi (covariant) return tipleri kullanıyorsa, & veya * ile döndürmelisin
  • Geçici ve lokal değer
    • Daima değer ile döndür

kaynaklar: https://github.com/lefticus/cppbestpractices/issues/21 https://twitter.com/lefticus/status/635943577328095232

Basit tipleri fonksiyonlara const ref ile geçme ve fonksiyonlardan döndürme

// Cok Kotu Bir Fikir
class MyClass
{
public:
  explicit MyClass(const int& t_int_value)
    : m_int_value(t_int_value)
  {
  }

  const int& get_int_value() const
  {
    return m_int_value;
  }

private:
  int m_int_value;
}

Bunun yerine, basit tipleri değer ile al ve döndür. Eğer fonksiyona geçilen değeri değiştimeyeceksen, const olarak tanımla const ref değil:

// Iyi Fikir
class MyClass
{
public:
  explicit MyClass(const int t_int_value)
    : m_int_value(t_int_value)
  {
  }

  int get_int_value() const
  {
    return m_int_value;
  }

private:
  int m_int_value;
}

Peki neden? Çünkü referans ile geçmek ve döndürmek pointer operasyonlarını tetikler, değer ile geçmek hızlıca işlemci registar'larını kullanır.

Ham Hafıza Erişimi Yapma

Ham hafıza erişimi, hafızadan alma, o yeri serbest bırakma, hafıza hataları ve akıntısı yapmadan düzgün bir şekilde yapmak C++ dilinde zordur. C++11 bu problemleri önlemek için araçlar sunar.

// Kotu Fikir
MyClass *myobj = new MyClass;

// ...
delete myobj;


// Iyi Fikir
auto myobj = std::make_unique<MyClass>(constructor_param1, constructor_param2); // C++14
auto myobj = std::unique_ptr<MyClass>(new MyClass(constructor_param1, constructor_param2)); // C++11
auto mybuffer = std::make_unique<char[]>(length); // C++14
auto mybuffer = std::unique_ptr<char[]>(new char[length]); // C++11

// veya referans sayan nesneler için
auto myobj = std::make_shared<MyClass>(); 

// ...
// myobj kullanılmadığında otomatik olarak serbest bırakılır.

C-stili Diziler Yerine std::array veya std::vector Kullan

Her ikisi de nesnelerin bitişik bellek düzenini garanti eder ve çıplak pointer'ların kullanılmaması için listelenen birçok nedenden ötürü C-stili dizilerin kullanımının yerine geçebilir (ve geçmelidir). Ayrıca, std::shared_ptr kullanarak dizi tutmaktan kaçınmalısın.

Exception'ları Kullan

Exception'lar(istisnai durumlar) gözardı edilemez. Dönüş değerleri, boost:optional gibi, önemsenmeyebilir ve eğer kontrol edilmezse çökmelere ve hafıza hatalarına neden olur. Diğer taraftan bir exception yakalanabilir ve düzeltilebilir. Potansiyel olarak uygulamanın en üst katmanında bir log tutulur ve uygulama otomatik olarak yeniden başlatır.

Stroustrup, C++ dilinin yaratıcısı, bu konuyu benim yapabileceğimden çok daha iyi açıklıyor.

C-stili cast yerine C++-stili cast Kullan

C-stili cast yerine C++-stili cast (static_cast<>, dynamic_cast<> ...) kullan. C++-stili cast derleyicinin daha fazla kontrolüne izin verir ve daha güvenlidir.

// Kotu Fikir
double x = getX();
int i = (int) x;

// Kotu bir fikir degil
int i = static_cast<int>(x);

Ek olarak C++ cast stili daha iyi görülebilir ve arandığında bulması daha kolaydır.

Eğer doubleı inte cast etmen gerekiyorsa program mantığını refaktör etmeyi düşün (mesela, overflow ve underflow fazladan kontrol etmek gibi). Üç kere ölç ve 0.9999999999981 kere kes.

Variadic fonksiyon tanımlama

Variadic fonksiyonlar değişken sayıda parametre alabilir. Muhtemelen printf() bunun en iyi bilinen örneğidir. Sen de bu türden fonksiyonlar tanımlayabilirsin ama bu olası güvenlik sorunlarına neden olur. Variadic fonksiyonları kullanmak tip güvenli(type safe) değildir ve yanlış parametre geçmek programın belirlenemeyen davranışla sonlandırabilir. Bu beklenmeyen davranış, güvenlik açıklarına neden olabilir. Derleyicin C++11 destekliyorsa, bunun yerine variadic template'leri kullanabilirsin.

Bazı derleyicileri kullanarak C-stili ve tip güvenli variadic fonksiyonlar yapmak teknik olarak mümkündür

Ek Kaynaklar

David Wheeler'ın yazdığı sonraki Heartbleed'i nasıl önleriz kodun mevcut güvenlik durumundan ve güvenliğinden emin olmayı iyi analiz eder.

results matching ""

    No results matching ""