简体   繁体   English

短路评估是否可以触发竞争条件?

[英]Can short-circuit evaluation trigger a race condition?

I like code golf. 我喜欢打高尔夫球。 In light of CVE-2016-5195 , I was wondering if any of my "golfed" code can trigger race conditions. 鉴于CVE-2016-5195 ,我想知道我的任何“ golf”代码是否都可以触发竞争条件。

Let's say we have two functions, both of which return a boolean value, and we are initializing a boolean variable called result : 假设我们有两个函数,两个函数都返回一个布尔值,并且我们正在初始化一个名为result的布尔变量:

result = foo() || bar();

In an ideal world, we have two scenarios: 在理想的世界中,我们有两种情况:

  1. foo returns true . foo返回true Do not call bar . 不要打电话bar result equals true . result等于true [short-circuit scenario] [短路情况]
  2. foo returns false . foo返回false Do call bar() . 致电bar() result equals what bar returns. result等于bar返回的值。

My question: Will there ever be a time when short-circuit evaluation is violated, and bar is called despite foo returning true , or even worse, bar is called before foo is called, perhaps because of multi-threading? 我的问题是:是否会有一段时间违反短路评估,并且尽管foo返回true foo调用bar ,或更糟糕的是,可能是由于多线程而在foo被调用之前先调用bar吗? If so, can you provide a piece of code that would trigger such behavior? 如果是这样,您是否可以提供一段代码来触发这种行为?

Your answer may be about any language(s) in which this syntax is valid, although I suppose some languages will be more strict about this kind of thing than others. 您的答案可能是关于使用该语法有效的任何一种或多种语言的,尽管我认为某些语言对这种语言的要求会比其他语言更为严格。

Race conditions occur when the outcome of a series of operations depends on the sequence upon which they are executed. 当一系列操作的结果取决于执行这些操作的顺序时,就会发生竞争条件。

The && and || &&|| operators in C++ guarantee left-to-right evaluation and to not evaluate the second operator if the first one is false / true, respectively. C ++中的运算符保证从左到右求值,并且如果第一个运算符为false / true则不对第二个运算符进行求值。 Since the sequence of operations is guaranteed, there is no race condition between operations of foo and operations of bar . 由于操作顺序是有保证的,因此foo操作和bar操作之间没有竞争条件。 There can still be race conditions between the operations in each one , though. 但是,每个操作之间仍然存在竞争条件。

Code that violates the aforementioned guarantees is not C++ code, and likewise conforming C++ compilers will never emit code that violates those guarantees. 违反上述保证的代码不是C ++代码,同样,符合要求的C ++编译器也永远不会发出违反那些保证的代码。

The case you are referring to is not a race condition. 您所指的情况不是竞争条件。 Let's get back again your question: 让我们再次回到您的问题:

Will there ever be a time when short-circuit evaluation is violated, and bar is called despite foo returning true, or even worse, bar is called before foo is called, perhaps because of multi-threading? 是否会有一段时间违反短路评估,尽管foo返回true仍会调用bar,或者更糟糕的是,可能由于多线程而在调用foo之前先调用bar吗?

I guess the right question would be: 我猜正确的问题是:

Will there ever be a time when bar is called AFTER foo is called with false result, but while it's called foo will return true if will be called again ? 将永远是一个有酒吧时被调用调用函数foo使用假的结果的时间,但同时它被称为foo将返回true,如果将被再次叫什么名字?

Ok, let's do some code with potential race condition state. 好的,让我们用潜在的race condition状态编写一些代码。

#define BUFFER_SIZE 0x1000
char globalBuffer[BUFFER_SIZE];

bool foo() { // have user an access to the path_to_file file?
   return access(path_to_file, 0666) != 0; // path_to_file declared somewhere
}

bool bar() {
    FILE *file = fopen(path_to_file, "r");
    if (file == NULL) return false;
    char *ptr = gfets(globalBuffer, BUFFER_SIZE, file);
    if (ptr == NULL) return false;
    return true;
}
...
result = foo() || bar(); // if foo is false, then user have an access
printf("%s", globalBuffer);

Let's imagine that we can control path_to_file. 假设我们可以控制path_to_file。

Race condition will be occuried, if we make an infinite loop like this 如果我们像这样做一个无限循环,就会出现竞争条件

#!/bin/bash

while :
do
    ln -s /path/to/good/access/file /path/to/file
    rm -f /path/to/file
    ln -s /etc/shadow /path/to/file
done

After some attempts, if your application has suid bit - I will read contents of the /etc/shadow 经过一些尝试,如果您的应用程序具有suid位-我将读取/ etc / shadow的内容

But let's return back to your question: 但是,让我们回到您的问题:

No, no way. 不行不行 If foo will return true, bar not will be called. 如果foo返回true,则不会调用bar Even from other thread, if you have multi-threading. 即使您来自其他线程,如果您有多线程。 Each thread has its own registers, own stack. 每个线程都有自己的寄存器和堆栈。 So, in case of two function calls in the same expression you should beleive to the c++ standard. 因此,在同一个表达式中调用两个函数的情况下,您应该相信c ++标准。 But it doesn't mean that you code is safe. 但这并不意味着您的代码是安全的。 And race condition one of 100 possible problems. 种族状况是100种可能出现的问题之一。

Note that C++ supports operator overloading, but that short circuiting is a feature only of builtin operators (pre c++17), not user provided overloads. 请注意,C ++支持运算符重载,但短路仅是内置运算符(c ++ 17之前)的功能,而不是用户提供的重载。

Ie in all current versions of C++ it is unsafe to assume that short circuiting will occur unless you know both types and know that no free function operator|| 也就是说,在所有当前版本的C ++中,除非您同时知道这两种类型并且知道没有自由函数运算符,否则不能假定会发生短路。 is shadowing. 正在阴影中。

See for p0145 for how this is changing in c++17. 有关p0145的信息 ,请参见c ++ 17中的变化。

(bold is additions, italics removal) (粗体是加法,斜体去除)

Change paragraph 5/2 as follows: [ Note: Operators can be overloaded, that is, given meaning when applied to expressions of class type (Clause 9) or enumeration type (7.2). 更改第5/2段,如下所示:[注意:运算符可以重载,即在应用于类类型(条款9)或枚举类型(7.2)的表达式时具有特定含义。 Uses of overloaded operators are transformed into function calls as described in 13.5. 重载运算符的使用将转换为函数调用,如13.5中所述。 Overloaded operators obey the rules for syntax and evaluation order specified in Clause 5, but the requirements of operand type*,* and value category, and evaluation order are replaced by the rules for function call. 重载的运算符遵循第5章中指定的语法和评估顺序规则,但操作数类型*,* 值类别以及评估顺序的要求已由函数调用规则取代。 Relations between operators, such as ++a meaning a+=1, are not guaranteed for overloaded operators (13.5), and are not guaranteed for operands of type bool. 对于重载的运算符(13.5),不能保证运算符之间的关系(例如++ a表示a + = 1),对于布尔类型的操作数也不保证。 —end note ] —尾注]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM