2016-09-22 28 views
13

可以說你有一個函數可以爲你的應用程序產生一些安全令牌,比如一些散列鹽,或者可能是對稱密鑰或非對稱密鑰。如何確保在運行時永不調用constexpr函數?

現在讓我們說,你在你的C++爲constexpr有這個功能,你基於部分信息,供您構建功能鍵(比如,內部版本號,時間戳,別的東西)。

你是一個勤奮的程序員確保,並在適當的方式把這種以確保它只是被稱爲在編譯的時候,這樣的死脫去除最終的可執行代碼。

但是,你永遠不能肯定,別人是不會調用它以不安全的方式,或者,也許編譯器將不剝離的功能出來,然後你的安全令牌算法將成爲大衆知識,使攻擊者更容易猜測未來的令牌。

或者,安全之餘,讓我們說的功能需要很長的時間來執行,並要確保它在運行時不會發生,並導致了最終用戶一個不好的用戶體驗。

有什麼方法來確保constexpr函數不能在運行時調用?或者,在運行時拋出一個斷言或類似的東西是可以的,但不像編譯錯誤那樣理想。

我聽說有一些方法涉及拋出一個不存在的異常類型,所以如果constexpr函數沒有被解除阻塞,你會得到一個鏈接器錯誤,但聽說這隻能工作在一些編譯器上。

遠親問題:Force constexpr to be evaluated at compile time

+0

一個可能的解決方案:你嚴格按照模板實現那個函數結構xyz {static constexpr long long value = ...; }'。不,實際上,我的意思是不要使用'constexpr函數',而是嚴格在結構模板中實現計算。 –

+3

請注意,人們普遍認爲,如果知道你的算法足夠讓它被破壞,那麼你的算法就是廢話。 – immibis

+0

對於可能遇到此問題並想嘗試的人來說,這是一個很好的一般性評論,但FWIW我的需求與安全無關。 –

回答

11

可以強制在一個常量表達式使用它:

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

通過使用功能模板參數的結果,你得到一個錯誤,如果它不能在編譯時得到解決。

+1

這是一個不錯的訣竅!這很有用,但是你知道是否有辦法使它在運行時不能被調用? –

+1

@AlanWolfe這樣,它不能在運行時調用,你會在編譯時產生錯誤。當然,您只需在隱藏的界面背後隱藏細節。 – skypjack

+2

ct可以用C++ 11中的std :: integral_constant替換。見http://en.cppreference.com/w/cpp/types/integral_constant – mabraham

5

一個理論解決方案(如模板應圖靈完整) - 不使用constexpr功能,回落到好老std=c++0x風格僅僅使用struct template with values計算的。例如,不要做

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

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; 
} 

struct方法是保證在編譯時專門評估。

事實上,在提升的人設法做到compile time parser是一個強烈的信號,儘管乏味,這種方法應該是可行的 - 這是一次性成本,也許人們可以認爲它是一種投資。


例如:

電源結構:

// ***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; 
}; 

構建令牌

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'。灣'1!'的專長是多餘的。 – SomeWittyUsername

+0

@SomeWittyUsername好吧,那麼我的「事實」實際上並不計算階乘的數學表達式。它仍然是該技術的一個有效例子,不是嗎? –

+0

我希望有其他選擇(現在或將來與constexpr),但謝謝你的答案! –

相關問題