当前位置: 首页 > 知识库问答 >
问题:

如何使我的类在C++中免受“自动值=代理副本”地雷的攻击?

贺皓
2023-03-14

我有一个相当复杂的数学库,我正在工作,我发现当客户端代码使用Auto时有一个讨厌的bug。在创建一个最小的繁殖案例来问一个关于它的问题的中途,我意识到我可以单独使用标准库复制类似的东西。请参见这个简单的测试用例:

#include <vector>
#include <assert.h>

int main()
{
    std::vector<bool> allTheData = {true, false, true};

    auto boolValue = allTheData[1]; // This should be false - we just declared it.
    assert(boolValue == false);
    boolValue = !boolValue;
    assert(boolValue == true);

    assert(allTheData[1] == false); // Huh? But we never changed the source data! Only our local copy.
}

住在Godbolt上。(有趣的事实:Clang实际上将其优化为写入“7”--3个真位--并调用__assert_fail。)

(是的,我知道std::vector 很糟糕--但在这种情况下,创建一个最小可复制的仅有几行长的示例是很方便的)这里有一个较长的示例,它没有使用std::vector ,而是使用了自定义容器类型,删除了赋值和复制/移动,但仍然显示了问题。

代码做了程序员让它做的事情,而不是程序员的意思。

如果程序员希望boolValue的更改来更新源数据,他们会执行auto&boolValue=...,这与返回T&操作符[]实现一起工作,但不需要自定义代理来伪造类似引用的行为。

代理的所有copy和move构造函数以及两个赋值操作符都被声明为私有(也尝试过=delete),但是在编译时没有发现这个bug。无论复制构造函数是否被删除,都将复制代理。

我宁愿清除地雷,而不是一直绕过它,挂一个牌子说“不要使用自动”,或“永远使用常量”,只是标记雷区,它不能清除它。

  • 第一个首选项是代码按写的方式工作-assert(Allthedata[1]==false)传递
    • 当代理写入Auto时定义代理衰减类型的一种方法。那么decltype(boolValue)bool
    • 优先于复制的隐式转换运算符?
    • 是否有其他方法在不更改上面的代码段的情况下完成此操作?
    • 我将copy和move构造函数声明为delete,将move和copy赋值运算符声明为delete。仍在编译。
    • 是否存在将类声明为无法成为lvalue的情况?
    std::vector<bool> ReadFlags();
    ... later ...
    auto databaseIsLockedFlag = ReadFlags()[FLAG_DB_LOCKED];
    if (databaseIsLockedFlag) <-- Crash here. Proxy has outlived temporary vector.
    

    奇怪的是,MSVC的Intellisense引擎有时会将复制no-move-no-copy代理类型报告为编译错误,但随后仍将其编译得很好:

共有1个答案

周瀚
2023-03-14

(与运算符+=、-=等)

我做了很多实验,但我最终找到了一种方法来缓解最常见的问题,这使得您仍然可以复制代理,但是一旦您将它复制到堆栈变量中,您就不能修改它,并且无意中损坏了源容器。

#include <cstdio>
#include <utility>

auto someComplexMethod()
{
  struct s
  {
    void operator=(int A)&& {std::printf("Setting A to %i", A);}
  };
  return s();
}

int main()
{
  someComplexMethod() = 4; // Compiles. Yay

  auto b = someComplexMethod(); 
  // Unfortunately that still compiles, and it's still taking a 
  // copy of the proxy, but no damage is done yet.

  b = 5; 
  // That doesn't compile. Error given is: 
  //   No overload for '='  note: candidate function not viable: 
  //   expects an rvalue for object argument

  std::move(b) = 6; 
  // That compiles, but is basically casting around the 
  // protections, aka shooting yourself in the foot.
}
 类似资料:
  • 我有一个相当复杂的数学库我正在工作,我发现了一个令人讨厌的bug当客户端代码使用auto。在创建一个最小再生案例来询问有关它的问题的过程中,我意识到我可以单独使用标准库来再生类似的东西。请参阅这个简单的测试用例: 靠神锚生活。(有趣的事实:Clang实际上将其优化为写入“7”--3个真位--并调用__ASSERT_FAIL。) (是的,我知道std::vector 很糟糕--但在本例中,创建一个只

  • 我希望我可以通过HTTPS保护我的应用程序免受MITM攻击,我知道我可以使用HPKP来保护应用程序。 可以从react native执行此操作吗?

  • 嘿,我是c的新手,我正在尝试创建一个可以存储多种类型的地图: Wich显然给我带来了一些错误。 我在网上查了一下,发现了一些有趣的东西,但没有答案。也许我漏掉了一点c语言词汇。 我也会尝试一些关于任何类型的一流三明治商店,我不知道它是否有效。 谢谢你的帮助!

  • 问题内容: 如何保护我们的Web应用程序免受XSS攻击?如果一个应用程序不进行任何特殊字符转换,就很容易受到攻击。 问题答案: 您应该先将所有输入转回HTML,然后再将其输出回给用户。一些参考: OWASP XSS(跨站点脚本)预防备忘单 考虑从Apache Commons Lang使用 或从Spring使用 JSP / Servlet Web应用程序中的XSS预防

  • 按ID找到一个有评论和链接属于它的帖子: 如何使用Promise(http://mongoosejs.com/docs/promissies.html)避免回拨地狱? 好像不好......

  • 为了防止我们的网络在预连接攻击和获取访问部分中解释的先前攻击破解方法,我们需要访问路由器的设置页面。每个路由器都有一个web页面,我们可以在页面中修改路由器的设置,它通常位于路由器的IP上。首先,获得我们自己的计算机的IP,为此运行命令。如下面的屏幕截图所示,突出显示的部分是计算机的IP: 现在打开浏览器并访问:。对于此示例,计算机的IP为。通常,路由器的IP是子网的第一个IP。目前,它是,我们只