2016-09-22 5 views
13

は、あなたがそのようないくつかのハッシュ塩、または多分対称型または非対称キーとして、あなたのアプリケーションのためのいくつかのセキュリティトークンを生成する関数を持っていると言うことができます。実行時にconstexpr関数が決して呼び出されないようにする方法は?

ここでは、C++でconstexprとしてこの関数を使用し、ビルド番号、タイムスタンプなど何らかの情報に基づいてビルド用のキーを生成するとします。

あなたは勤勉プログラマであることを確認して、それが唯一のコンパイル時に呼ばれています確保するための適切な方法でこれを呼び出すので、死んだストリッパーは、最終的な実行可能ファイルからコードを削除します。

しかし、あなたが他の誰かが危険な方法でそれを呼び出すするつもりはない、またはそれは多分、コンパイラが関数を取り除くしませんし、お使いのセキュリティトークンアルゴリズムは、公開になることを確認することはできません知識があれば、攻撃者は将来のトークンを推測することがより簡単になります。

あるいは、セキュリティはさておき、の機能の実行に時間がかかるし、あなたは必ずそれが実行時に起こることがないようにしたいとエンドユーザーのための悪いユーザーエクスペリエンスを起こしましょう。

constexprの関数は、実行時に呼び出されることは決してできないことを確実にする任意の方法はありますか?あるいは、実行時にアサートなどを投げてもOKですが、コンパイルエラーと同じように理想的ではありません。

存在しない例外タイプをスローする方法がいくつかあると聞いています。そのため、constexpr関数がデッドストリップされていないと、リンカーエラーが発生しますが、いくつかのコンパイラで。

遠縁の質問:Force constexpr to be evaluated at compile time

+0

可能な解決策の1つ:可能な解決策の1つは、テンプレート<...> struct xyz {static constexpr long long value = ...; } '。いいえ、実際には、私は 'constexpr関数 'を使わずに厳密に構造体テンプレートに計算を実装することを意味します。 –

+3

あなたのアルゴリズムが壊れていると分かっていれば、あなたのアルゴリズムは駄目だということは一般的には同意しています。 – immibis

+0

これは、この質問に遭遇し、試してみたい人のための良い一般的なコメントですが、私の必要性はセキュリティ関連ではありません。 –

答えて

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の機能を使用し、独占的にstruct template with valuesを使用して、コンピューティングの良い古いstd=c++0xスタイルに戻って落ちることはありません。例えば、

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を行うために管理事実は退屈とはいえ、このアプローチは実行可能でなければならない、という強いシグナルである - それは多分1が投資を検討することができ、一回限りのコストです。

パワー構造体へ:

// ***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'。 b。 '1!'の特化は冗長です。 – SomeWittyUsername

+0

@SomeWittyUsernameさて、私の 'fact'は実際に階乗の数学的表現を計算しません。それはまだ技術のための有効な例です、それはありませんか? –

+0

私は他のオプションがあることを望みます(現在または将来constexprで)が、答えてくれてありがとう! –

関連する問題