Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/132.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 模板化运行时检查调用包装器,以检测输入参数或返回值中的强制转换溢出 问题_C++_Templates_C++17_Variadic Templates_Auto - Fatal编程技术网

C++ 模板化运行时检查调用包装器,以检测输入参数或返回值中的强制转换溢出 问题

C++ 模板化运行时检查调用包装器,以检测输入参数或返回值中的强制转换溢出 问题,c++,templates,c++17,variadic-templates,auto,C++,Templates,C++17,Variadic Templates,Auto,我需要一个checked\u cast\u调用函数的通用包装器,它将在运行时检查调用函数或获取值所涉及的任何转换 例如,在输入缓冲区大于2GB的情况下调用以下函数会导致一些问题(因为int inlinput size参数会溢出): int EVP_EncryptUpdate(EVP_CIPHER_CTX*CTX,unsigned char*out, int*outl,常量无符号字符*in,int-inl) 我的不完美解决方案 为了实现这一点,我使用了其他stackoverflow主题的有见地的帮

我需要一个
checked\u cast\u调用
函数的通用包装器,它将在运行时检查调用函数或获取值所涉及的任何转换

例如,在输入缓冲区大于2GB的情况下调用以下函数会导致一些问题(因为
int inl
input size参数会溢出):

int EVP_EncryptUpdate(EVP_CIPHER_CTX*CTX,unsigned char*out,
int*outl,常量无符号字符*in,int-inl)

我的不完美解决方案 为了实现这一点,我使用了其他stackoverflow主题的有见地的帮助,最终得到了以下解决方案,但不幸的是,这远远不够完美:

  • 首先,我编写了一个小模板来运行时检查强制转换(如果强制转换溢出,它将抛出
    std::runtime\u错误
  • 最后一个包装器,获取函数指针的
    decltype
    ,以及函数指针本身,用容器展开压缩参数,并将结果也放入容器中:
问题 可以改进此包装器,以便:

  • 您只需要一个模板参数(函数),而不需要函数的
    decltype
    (即直接
    checked\u cast\u调用(…)
  • 您可以使用推断的函数参数类型来运行时检查强制转换,而不依赖于容器包装器
可能有一些解决方案是将函数作为参数传递给包装器,而不是作为模板,但我想要一个纯模板解决方案。也许这根本不可行,或者太复杂了

亲爱的读者,提前感谢您提供的有用提示

⟾ 部分解 问题#1的解决方案感谢@kmdreko,通过:

模板
自动检查\u转换\u调用(Args…Args)
{
返回checked_cast_call_容器(fn(checked_cast_call_容器(std::forward(args))…);
}
const char b=checked\u cast\u调用(str,1,size,stdout);

允许直接使用sed-e的/my\u write/checked\u cast\u call/g'

一个可能的改进应该是停止将函数作为模板参数,而是将其作为函数参数,这样C++17演绎规则就可以猜测类型,而不需要提供模板参数

下面是一个快速而肮脏的版本:

模板
decltype(自动)已选中\u cast\u调用(F&&F,Args…Args)
{
返回选中的调用容器(std::forward(f)(选中的调用容器(std::forward)


它似乎与您的代码具有相同的行为,现在我需要检查我们是否有适当的内联(至少和您的一样好)。可能还有一些cv限定类型的细节,可能我们需要一个
std::decay
或任何其他模板类型的东西…

改进#1可以用@kmdreko完成谢谢!修改后的模板现在好多了:模板选中了\u cast\u调用了\u容器选中了\u cast\u调用(Args…Args)…谢谢!生成的代码似乎是严格等效的,也就是说,对于需要运行时检查的每种类型,只有额外的cmp+jne(对反汇编代码进行区分不会产生任何差异)
#include <stdexcept>
#include <type_traits>

/**
 * Runtime-checked cast to a target type.
 * @throw std::runtime_error If the cast overflowed (or underflowed).
 */
template <class Target, class Source>
Target inline checked_cast(Source v)
{
    if constexpr (std::is_pointer<Source>::value) {
        return v;
    } else if constexpr (std::is_same<Target, Source>::value) {
        return v;
    else {
        const auto r = static_cast<Target>(v);
        if (static_cast<Source>(r) != v) {
            throw std::runtime_error(std::string("cast failed: ") + std::string(__PRETTY_FUNCTION__));
        }
        return r;
    }
}
/**
 * Container holding a type, and allowing to return a cast runtime-checked casted value.
 * @example
 *     const size_t my_integer = foo();
 *     const checked_cast_call_container c(my_integer);
 *     int a = static_cast<int>(c);
 */
template <typename T>
class checked_cast_call_container {
public:
    inline checked_cast_call_container(T&& result)
        : _result(std::move(result))
    {
    }

    template <typename U>
    inline operator U() const
    {
        return checked_cast<U>(_result);
    }

private:
    const T _result;
};
/**
 * Wrapped call to a function, with runtime-checked casted input and output values.
 * @example checked_cast_call<decltype(&my_function), &my_function>(str, 1, size, output)
 */
template <typename Fn, Fn fn, typename... Args>
checked_cast_call_container<typename std::result_of<Fn(Args...)>::type>
checked_cast_call(Args... args)
{
    return checked_cast_call_container(fn(checked_cast_call_container(std::forward<Args>(args))...));
}
static char my_write(void* ptr, char size, char nmemb, FILE* stream)
{
    return fwrite(ptr, size, nmemb, stream);
}

int main(int argc, char** argv)
{
    // Input overflow: input argument nmemb is larger than 127
    try {
        char str[256] = "Hello!\n";
        volatile size_t size = sizeof(str);
        const char b = checked_cast_call<decltype(&my_write), &my_write>(str, 1, size, stdout);
        (void)b;
    } catch (const std::runtime_error& e) {
        std::cout << e.what() << "\n";
    }

    return 0;
}

--- old.S   2019-03-11 11:14:25.847240916 +0100
+++ new.S   2019-03-11 11:14:27.087238775 +0100
@@ -3 +3 @@
-lea    0x10(%rsp),%rbx
+lea    0x10(%rsp),%rdi
@@ -6 +5,0 @@
-mov    %rbx,%rdi
@@ -9 +8,4 @@
-mov    0x8(%rsp),%rax
+mov    0x8(%rsp),%rdx
+movsbq %dl,%rax
+cmp    %rdx,%rax
+jne    0xXXXXXX <_Z5test3v+82>
@@ -11 +13 @@
-movsbq %al,%rdx
+lea    0x10(%rsp),%rdi
@@ -13 +14,0 @@
-mov    %rbx,%rdi
template <auto fn, typename... Args>
auto checked_cast_call(Args... args)
{
    return checked_cast_call_container(fn(checked_cast_call_container(std::forward<Args>(args))...));
}
const char b = checked_cast_call<&my_write>(str, 1, size, stdout);