On 8/27/13 1:33 AM, Dave Thompson wrote:
From: owner-openssl-...@openssl.org On Behalf Of Yuan Kang
Sent: Tuesday, 27 August, 2013 00:54
I don't think that it is true that "(signed char)(*p) >= 0"
is always true, <snip>
Mr Weimer didn't say it IS always true, he said a compiler
IS ALLOWED TO ASSUME it is. As I adjusted, the compiler does
have to document that it does this.
I don't know who would issue such rules, or who would enforce them.
Whether a given compiler
does it depends on the writers of that compiler, and quite
likely on the target architecture, and quite possibly on
the optimizations implemented by the compiler and used.
As I added, gcc (at least the versions I have) documents
that it doesn't do so.
I really doubt that.
Here is (from memory) a code snippet I tested on gcc a year or so ago
void
testint(int a, int b)
{
int c;
if (a < 0) return;
if (b < 0) return;
c = a+b;
if (c < 0) {
printf("a+b = %d, which is negative\n", c);
} else {
printf(a+b = %d, which is positive\n", c);
}
}
when compiled with optimization -O2 or higher and with and a and b both
2000000000, it prints
"a+b = -294967296 which is positive".
The fact that the value of an operation with signed arithmetic that
overflows (the + operator) is undefined, and the result of and
operation where at least one operand is undefined (the < operator), is
undefined. That allows the compiler to reason using ordinary
mathematical operations rather than computer operations. If there is no
overflow, computer arithmetic and mathematical arithmetic are the same,
and it is okay. If overflow occurs, the result is undefined, so
anything they do is okay. So they reason that a is non-negative and b
is non-negative, and hence a+b must be non-negative, and hence, c is
non-negative, and c<0 if false, and optimize away the test and the true
branch.
The -fwrapv flag tells the optimizer to make the result of signed
arithmetic defined and take into account the wrapping behavior of
computer arithmetic. When compiled with -fwrapv, the output is as expected.
--David
What you need to check (or test) is
all versions of all other compilers used on all platforms
OpenSSL supports, with all optimization settings. Preferably
also all versions or replacements that will be released in
the next several years; people often are seen staying on
old OpenSSL versions 5 years or more, so that seems a good
minimum. It's a lot easier to support code that just works.
I think the optimization that PMHager was thinking about
(based on what I see in the x86_64 assembly from gcc) is
that the compiler could (but apparently not every compiler
does this) use the instruction for checking the sign, like this:
9: 84 c9 test %cl,%cl
b: 78 1b js 28 <UTF8_getc+0x28>
This is most likely faster than having to do a logical and instruction
first.
It may be faster but that's far from certain, and I'm very
confident it's not usefully faster; nearly all of the time
will be in the memory references (which don't change)
and the branch if mispredicted (which doesn't change).
And not all CPUs work the same as x64, or x86. Where
speed really matters, like in some of the cipher and
hash cores, OpenSSL has assembler -- separate for each
CPU (more or less), and reliably producing the desired
instructions no matter what the C code generator does.
That's better (though more work) than nonportable C,
which soon needs #ifdef hell to keep working.
______________________________________________________________________
OpenSSL Project http://www.openssl.org
Development Mailing List openssl-dev@openssl.org
Automated List Manager majord...@openssl.org
______________________________________________________________________
OpenSSL Project http://www.openssl.org
Development Mailing List openssl-dev@openssl.org
Automated List Manager majord...@openssl.org