2012-09-04 27 views
6

Đây là một mẫu chung để sử dụng các mẫu để thực thi trình biên dịch để khởi tạo các giá trị kiểu gốc/POD (https://stackoverflow.com/a/11493744/16673 hoặc http://www.codeproject.com/Articles/825/Using-templates-for-initialization).Mẫu để thực hiện bộ nhớ tự động ghi đè lên sự hủy diệt

Có một mẫu tương tự tồn tại có thể được sử dụng để xóa giá trị khi nó vượt quá phạm vi vì lý do bảo mật, để đảm bảo giá trị không được để lại trên ngăn xếp khi biến bị hủy? Tôi sợ một sự triển khai tương tự ngây thơ có thể không hoạt động, vì trình biên dịch được tự do bỏ qua bất kỳ nhiệm vụ nào đến một giá trị đang bị lệch khỏi phạm vi, vì giá trị có thể được chứng minh một cách trivially không được sử dụng nữa. Có một số giải pháp phù hợp và di động hợp lý không, ví dụ: sử dụng dễ bay hơi?

Trả lời

3

Bạn có thể sử dụng một số C++ 11 tính năng để làm điều này khả năng di chuyển, nhưng điều này có thể đủ như là một điểm khởi đầu:

Lớp

template<typename T> 
class t_secure_destruct { 
    static const size_t Size = sizeof(T); 
    static const size_t Align = alignof(T); 
public: 
    t_secure_destruct() : d_memory() { 
    new(this->d_memory)T; 
    } 

    ~t_secure_destruct() { 
    reinterpret_cast<T*>(this->d_memory)->~T(); 
    this->scribble(); 
    } 

    // @todo implement or delete op-assign and remaining constructors 

public: 
    T& get() { 
    return *reinterpret_cast<T*>(this->d_memory); 
    } 

    const T& get() const { 
    return *reinterpret_cast<const T*>(this->d_memory); 
    } 

private: 
    void scribble() { 
    for (size_t idx(0); idx < Size; ++idx) { 
     this->d_memory[idx] = random(); 
    } 
    } 

private: 
    __attribute__((aligned(Align))) char d_memory[Size]; 
}; 

Demo

#include <iostream> 

class t_test { 
public: 
    t_test() : a(-1) { 
    std::cout << "construct\n"; 
    } 

    ~t_test() { 
    std::cout << "destruct\n"; 
    } 

public: 
    void print() const { 
    std::cout << "a = " << a << "\n"; 
    } 

public: 
    int a; 
}; 

int main(int argc, const char* argv[]) { 
    t_secure_destruct<t_test>test; 
    test.get().print(); 
    test.get().a = 100; 
    test.get().print(); 
    return 0; 
} 

Tất nhiên, bạn cũng có thể trả lại phân bổ đó với phân bổ đống, nếu bạn thích. Nếu bạn cần phải outsmart một trình tối ưu hóa, bạn có thể cần phải đặt các scribbler ra khỏi tầm với của nó.

+0

Âm thanh hợp lý. Lau bằng randoms dường như tuy nhiên để mang lại ít lợi ích, đồng bằng zeroing nên làm công việc. Các giải pháp không cố gắng để bảo đảm chống lại một ai đó đọc các chip bộ nhớ hoặc một cái gì đó như thế này, chỉ cần chống lại một quá trình truy cập vào bộ nhớ. Hoặc là có một lý do để sử dụng dữ liệu ngẫu nhiên ngay cả trong trường hợp như vậy? – Suma

+0

Giải pháp có vẻ là sử dụng các tính năng cụ thể của GCC (thuộc tính). Có một lý do để sử dụng char cho lưu trữ ở tất cả? Tại sao không sử dụng kiểu gốc? – Suma

+0

@Suma nó phụ thuộc hoàn toàn vào những gì bạn muốn thực hiện. zeroes sẽ là tốt quá - nó chỉ là một minh họa. – justin

4

Có chức năng trong API Windows được gọi là SecureZeroMemory. Bạn có thể nhìn vào nó đang thực hiện.

Tuy nhiên, nói chung, trình biên dịch buộc phải tôn vinh ghi dễ bay hơi. Nếu bạn đã biến biến động, nó sẽ không thể loại bỏ ghi.

+0

Những gì bạn viết về volatile có lẽ là một gợi ý như thế nào câu trả lời cho câu hỏi này sẽ giống như (mẫu có lẽ nên sử dụng dễ bay hơi trong destructor), nhưng nó dường như với tôi nó thực sự trả lời câu hỏi (biến bảo đảm không được đánh dấu biến động và tôi không mong đợi nó được đánh dấu như vậy, điều này sẽ được xử lý bởi một mẫu nếu cần thiết). – Suma

+1

@Suma: Không quan trọng là bản thân biến không dễ bay hơi. Đó là đủ để viết là thông qua một biểu thức dễ bay hơi, chẳng hạn như '* const_cast (this)'. Việc biến biến bản thân biến động đảm bảo rằng chính 'this' này là' Foo volatile * 'ở mọi nơi không có phôi, nhưng bạn chỉ cần một biểu thức dễ bay hơi trong dtor. – MSalters

Các vấn đề liên quan