2016-09-22 13 views
13

Cho phép nói rằng bạn có một chức năng tạo ra một số mã thông báo bảo mật cho ứng dụng của bạn, chẳng hạn như một số muối băm, hoặc có thể là một khóa symetric hoặc asymetric.Làm thế nào để đảm bảo chức năng constexpr không bao giờ được gọi là thời gian chạy?

Bây giờ hãy nói rằng bạn có hàm này trong C++ của bạn dưới dạng constexpr và bạn tạo khóa cho công trình xây dựng dựa trên một số thông tin (như số xây dựng, dấu thời gian, thứ gì đó khác).

Bạn là một lập trình viên siêng năng đảm bảo và gọi điều này theo những cách thích hợp để đảm bảo nó chỉ được gọi lúc biên dịch, và do đó kẻ giết người chết loại bỏ mã khỏi tệp thực thi cuối cùng. Tuy nhiên, bạn không bao giờ có thể chắc chắn rằng một người khác sẽ không gọi nó theo cách không an toàn hoặc có thể trình biên dịch sẽ không loại bỏ chức năng này, và sau đó thuật toán mã thông báo bảo mật của bạn sẽ trở thành công khai kiến thức, làm cho nó dễ dàng hơn cho sẽ là kẻ tấn công để đoán thẻ tương lai.

Hoặc, bảo mật sang một bên, giả sử hàm mất nhiều thời gian để thực thi và bạn muốn đảm bảo rằng nó không bao giờ xảy ra trong thời gian chạy và gây ra trải nghiệm người dùng tồi cho người dùng cuối của bạn.

Có cách nào để đảm bảo rằng chức năng constexpr không bao giờ có thể được gọi khi chạy không? Hoặc luân phiên, ném một khẳng định hoặc tương tự tại thời gian chạy sẽ là ok, nhưng không phải là lý tưởng rõ ràng là một lỗi biên dịch sẽ được.

Tôi nghe nói rằng có một số cách liên quan đến việc ném một loại ngoại lệ không tồn tại, để nếu hàm constexpr không bị deadstripped, bạn sẽ gặp lỗi linker, nhưng đã nghe nói rằng nó chỉ hoạt động trên một số trình biên dịch.

hàng xa câu hỏi: Force constexpr to be evaluated at compile time

+0

Một giải pháp khả thi: bạn triển khai thực hiện chức năng đó đúng theo điều khoản của 'mẫu <...> struct xyz {static constexpr long long value = ...; } '. Không, thực sự, ý tôi là không sử dụng hàm 'constexpr' nhưng thực hiện các tính toán chặt chẽ trong các khuôn mẫu struct. –

+3

Lưu ý rằng nó thường đồng ý rằng nếu biết thuật toán của bạn là đủ cho nó bị phá vỡ, sau đó thuật toán của bạn là crap. – immibis

+0

Đó là một bình luận chung tốt để làm cho folks những người có thể đi qua câu hỏi này và muốn cung cấp cho nó một thử, nhưng FWIW nhu cầu của tôi không liên quan đến an ninh. –

Trả lời

11

Bạn có thể buộc việc sử dụng nó trong một biểu thức hằng:

#include<utility> 

template<typename T, T V> 
constexpr auto ct() { return V; } 

template<typename T> 
constexpr auto func() { 
    return ct<decltype(std::declval<T>().value()), T{}.value()>(); 
} 

template<typename T> 
struct S { 
    constexpr S() {} 
    constexpr T value() { return T{}; } 
}; 

template<typename T> 
struct U { 
    U() {} 
    T value() { return T{}; } 
}; 

int main() { 
    func<S<int>>(); 
    // won't work 
    //func<U<int>>(); 
} 

Bằng cách sử dụng kết quả của hàm làm đối số mẫu, bạn gặp lỗi nếu không thể giải quyết được tại thời gian biên dịch.

+1

Đó là một mẹo hay! Điều đó là hữu ích, nhưng bạn có biết nếu có một cách để làm cho nó để các chức năng không thể được gọi là lúc chạy? –

+1

@AlanWolfe Bằng cách này, nó không thể được gọi khi chạy, bạn sẽ gặp lỗi tại thời gian biên dịch. Bạn chỉ đơn giản là phải ẩn các chi tiết đằng sau một giao diện được xác định độc đáo, tất nhiên. – skypjack

+2

ct có thể được thay thế bằng std :: integral_constant trong C++ 11. Xem http://en.cppreference.com/w/cpp/types/integral_constant – mabraham

5

Một giải pháp lý thuyết (như mẫu nên được Turing hoàn thành) - không sử dụng chức năng constexpr và rơi trở lại vào tốt tuổi std=c++0x dạng thức điện toán sử dụng độc quyền struct template with values. Ví dụ, không làm

constexpr uintmax_t fact(uint n) { 
    return n>1 ? n*fact(n-1) : (n==1 ? 1 : 0); 
} 

nhưng

template <uint N> struct fact { 
    uintmax_t value=N*fact<N-1>::value; 
} 
template <> struct fact<1> 
    uintmax_t value=1; 
} 
template <> struct fact<0> 
    uintmax_t value=0; 
} 

Cách tiếp cận struct được đảm bảo để được đánh giá độc quyền tại thời gian biên dịch.

Thực tế là những người ở mức tăng được quản lý để thực hiện compile time parser là một tín hiệu mạnh mẽ, mặc dù tẻ nhạt, cách tiếp cận này sẽ khả thi - đó là chi phí một lần, có thể một người coi đó là khoản đầu tư.


Ví dụ:

để struct điện:

// ***Warning: note the unusual order of (power, base) for the parameters 
// *** due to the default val for the base 
template <unsigned long exponent, std::uintmax_t base=10> 
struct pow_struct 
{ 
private: 
    static constexpr uintmax_t at_half_pow=pow_struct<exponent/2, base>::value; 
public: 
    static constexpr uintmax_t value= 
     at_half_pow*at_half_pow*(exponent % 2 ? base : 1) 
    ; 
}; 

// not necessary, but will cut the recursion one step 
template <std::uintmax_t base> 
struct pow_struct<1, base> 
{ 
    static constexpr uintmax_t value=base; 
}; 


template <std::uintmax_t base> 
struct pow_struct<0,base> 
{ 
    static constexpr uintmax_t value=1; 
}; 

Việc xây dựng thẻ

template <uint vmajor, uint vminor, uint build> 
struct build_token { 
    constexpr uintmax_t value= 
     vmajor*pow_struct<9>::value 
    + vminor*pow_struct<6>::value 
    + build_number 
    ; 
} 
+2

a. '0! = 1'. b. Chuyên môn cho '1!' Là thừa. – SomeWittyUsername

+0

@SomeWittyUsername Ok, sau đó 'thực tế' của tôi không thực sự tính toán biểu thức toán học của giai thừa. Nó vẫn là một ví dụ hợp lệ cho kỹ thuật, phải không? –

+0

Tôi hy vọng có những lựa chọn khác (hiện tại hoặc trong tương lai với constexpr), nhưng cảm ơn bạn đã trả lời! –

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