Do not make assumptions about the sign of the resulting value from the remainder %
operator.
The meaning of the remainder operator for negative arguments was defined to be implementation defined in 1989 ISO C (and was so in historical K&R implementations), but that was fixed in the 1999 Standard.
Because not all C-compilers are strictly C99-conforming, you can not rely on the behavior of the %
operator if you need to run on a wide range of platforms with many different compilers.
The div() function provides the same result as the remainder % operator.
According to C99:
The result of the / operator is the quotient from the division of the first operand by the second; the result of the % operator is the remainder. In both operations, if the value of the second operand is zero, the behavior is undefined.
When integers are divided, the result of the / operator is the algebraic quotient with any fractional part discarded. If the quotient a/b is representable, the expression (a/b)*b + a%b shall equal a.
Discarding the fractional part of the remainder is often called "truncation toward zero".
The C99 definition of % operator implies the following behavior:
17 % 3 -> 2 17 % -3 -> 2 -17 % 3 -> -2 -17 % -3 -> -2 |
The result has the same sign as the dividend (the first operand in the expression).
i % j |
In division where either operand is negative, the direction of truncation is toward 0.
If either operation is negative in division with the remainder operator, the result has the same sign as the dividend (the first operand in the expression). For example:
50 % -6 = 2 -50 % 6 = -2 |
In each case, 50 and 2 have the same sign.
The result is the same sign as the dividend; thus, the remainder of -23/4 is -3.
GCC always follows the C99 requirement that the result of division is truncated towards zero.
To provide a true (never negative) modulo operation, use the IMOD ("integer modulo") macro:
/* modulo macro giving non-negative result */ #define IMOD(i, j) (((i) % (j)) < 0 ? ((i) % (j)) + (j) : ((i) % (j))) /* if i % j is never negative, replace with the following line: */ /* #define IMOD(i, j) ((i) % (j)) */ |
Rule |
Severity |
Likelihood |
Remediation Cost |
Priority |
Level |
---|---|---|---|---|---|
STR07-A |
1 (low) |
1 (unlikely) |
2 (medium) |
P2 |
L3 |
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
\[[Beebe 05|AA. C References#Beebe 05]\] Nelson H. F. Beebe [Re: Remainder ( % ) operator and GCC|http://gcc.gnu.org/ml/gcc-help/2005-11/msg00141.html] 2005. \[[ISO/IEC 9899-1999|AA. C References#ISO/IEC 9899-1999]\] Section 6.5.5, "Multiplicative operators" \[[Microsoft 07|AA. C References#Microsoft 07]\] [C Multiplicative Operators|http://msdn2.microsoft.com/en-us/library/efa0csed(VS.80).aspx] \[[Sun 05|AA. C References#Sun 05]\] C User's Guide Sun Studio 11 819-3688-10 http://docs.sun.com/source/819-3688/. 2005. [Appendix E, "Implementation-Defined ISO/IEC C90 Behavior"|http://docs.sun.com/source/819-3688/c90.implementation.app.html] |