6.23 Operator Precedence and Associativity [JCW]
Each language provides rules of precedence and associativity, for each expression that operands bind to which operators. These rules are also known as “grouping” or “binding”.
Experience and experimental evidence shows that developers can have incorrect beliefs about the relative precedence of many binary operators. See, Developer beliefs about binary operator precedence. C Vu, 18(4):14-21, August 2006
6.23.2 Cross reference
JSF AV Rules: 204 and 213
MISRA C 2012: 10.1, 12.1, 13.2, 14.4, 20.7, 20.10, and 20.11
MISRA C++ 2008: 4-5-1, 4-5-2, 4-5-3, 5-0-1, 5-0-2, 5-2-1, 5-3-1, 16-0-6, 16-3-1, and 16-3-2
CERT C guidelines: EXP00-C
Ada Quality and Style Guide: 7.1.8 and 7.1.9
In C and C++, the bitwise operators (bitwise logical and bitwise shift) are sometimes thought of by the programmer having similar precedence to arithmetic operations, so just as one might correctly write “x – 1 == 0” (“x minus one is equal to zero”), a programmer might erroneously write “x & 1 == 0”, mentally meaning “x and-ed with 1 is equal to zero”, whereas the operator precedence rules of C and C++ actually bind the expression as “compute 1==0, producing ‘false’ interpreted as zero, then bitwise-and the result with x”, producing (a constant) zero, contrary to the programmer’s intent.
Examples from an opposite extreme can be found in programs written in APL, which is noteworthy for the absence of any distinctions of precedence. One commonly made mistake is to write “a * b + c”, intending to produce “a times b plus c”, whereas APL’s uniform right-to-left associativity produces “b plus c, times a”.
6.23.4 Applicable language characteristics
This vulnerability description is intended to be applicable to languages with the following characteristics:
-
Languages whose precedence and associativity rules are sufficiently complex that developers may not fully remember them.
Software developers can avoid the vulnerability or mitigate its ill effects in the following ways:
-
Adopt programming guidelines (preferably augmented by static analysis). For example, use the language-specific rules cross-referenced in 6.24.2.
-
Use parentheses around binary operator combinations that are known to be a source of error (for example, mixed arithmetic/bitwise and bitwise/relational operator combinations).
-
Break up complex expressions and use temporary variables to make the intended order clearer.
6.23.6 Implications for standardization
In future standardization activities, the following items should be considered:
-
Language definitions should avoid providing precedence or a particular associativity for operators that are not typically ordered with respect to one another in arithmetic, and instead require full parenthesization to avoid misinterpretation.
6.24 Side-effects and Order of Evaluation of Operands [SAM] 6.24.1 Description of application vulnerability
Some programming languages allow subexpressions to cause side-effects (such as assignment, increment, or decrement). For example, some programming languages permit such side-effects, and if, within one expression (such as “i = v[i++]”), two or more side-effects modify the same object, undefined behaviour results.
Some languages allow subexpressions to be evaluated in an unspecified ordering, or even removed during optimization. If these subexpressions contain side-effects, then the value of the full expression can be dependent upon the order of evaluation. Furthermore, the objects that are modified by the side-effects can receive values that are dependent upon the order of evaluation.
If a program contains these unspecified or undefined behaviours, testing the program and seeing that it yields the expected results may give the false impression that the expression will always yield the expected result.
6.24.2 Cross reference
JSF AV Rules: 157, 158, 204, 204.1, and 213
MISRA C 2012: 12.1, 13.2, 13.5 and 13.6
MISRA C++ 2008: 5-0-1
CERT C guidelines: EXP10-C, EXP30-C
Ada Quality and Style Guide: 7.1.8 and 7.1.9
6.24.3 Mechanism of failure
When subexpressions with side effects are used within an expression, the unspecified order of evaluation can result in a program producing different results on different platforms, or even at different times on the same platform.
(All examples here use the syntax of C or Java for brevity; the effects can be created in any language that allows functions with side-effects in the places where C allows the increment operations.)
Consider
a = f(b) + g(b);
where f and g both modify b. If f(b) is evaluated first, then the b used as a parameter to g(b) may be a different value than if g(b) is performed first. Likewise, if g(b) is performed first, f(b) may be called with a different value of b.
Other examples of unspecified order, or even undefined behaviour, can be manifested, such as
a = f(i) + i++;
or
a[i++] = b[i++];
Parentheses around expressions can assist in removing ambiguity about grouping, but the issues regarding side-effects and order of evaluation are not changed by the presence of parentheses. Consider
j = i++ * i++;
where even if parentheses are placed around the i++ subexpressions: undefined behaviour still remains.
The unpredictable nature of the calculation means that the program cannot be tested adequately to any degree of confidence. A knowledgeable attacker can take advantage of this characteristic to manipulate data values triggering execution that was not anticipated by the developer.
6.24.4 Applicable language characteristics
This vulnerability description is intended to be applicable to languages with the following characteristics:
-
Languages that permit expressions to contain subexpressions with side effects.
-
Languages whose subexpressions are computed in an unspecified ordering.
6.24.5 Avoiding the vulnerability or mitigating its effects
Software developers can avoid the vulnerability or mitigate its ill effects in the following ways:
-
Make use of one or more programming guidelines, which (a) prohibit these unspecified or undefined behaviours, and (b) can be enforced by static analysis. (See JSF AV and MISRA rules in Cross reference clause [SAM])
-
Keep expressions simple. Complicated code is prone to error and difficult to maintain.
-
Ensure that each expression results in the same value, regardless of the order of evaluation or execution of terms of the expression.
6.24.6 Implications for standardization
In future standardization activities, the following items should be considered:
-
In developing new or revised languages, give consideration to language features that will eliminate or mitigate this vulnerability, such as pure functions.
Dostları ilə paylaş: |