2016-09-22 23 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),但谢谢你的答案! –

相关问题