I have been working on refactoring a software called XPPAUT for a while now. Whenever I run it with Valgrind, there is a warning about a conditional based on an uninitialized value. It has been working well anyway, and it is in a part of the code I have not refactored yet, so I have been ignoring it. Today, I got tired of seeing this noise, so took the time to fix it. What I found was surprising, to say the least.
Running Valgrind and opening the ode/doubpend.ode
sample file, I
see
Conditional jump or move depends on uninitialised value(s)
at 0x42A6AA: do_new_parser (form_ode.c:1337)
by 0x42C250: get_eqn (form_ode.c:360)
by 0x42C63C: form_ode_load (form_ode.c:145)
by 0x4049CA: main (main.c:178)
during start. The offending line is
src/form_ode.c:1337
,
and I note it is a rather boring pair of lines:
But, it does indeed seem to be a conditional worthy of our
attention. Note the array indices, jumping from 1 to 5 suddenly. That
cannot be good. Add a printf
and notice there is no statement that
starts in SP
. In fact, the warning is emitted when
lhs
is PAR
. So,
why is the program looking at index 1 when not even the first
character is right? Have I been wrong about logical-and
short-circuit evaluation
this whole time?
Looking through the Internet, I find the C99 specification, which also happens to be linked from the Wikipedia article on short-circuit evaluation. Section 6.5.13, paragraph 4, talks about the logical-and operator:
Unlike the bitwise binary
&
operator, the&&
operator guarantees left-to-right evaluation; there is a sequence point after the evaluation of the first operand. If the first operand compares equal to 0, the second operand is not evaluated.
This all sounds excellent, but certainly does not help our search. At least now I know my understanding of C is not to blame in this case. Next step is a disassembly of the portion around this line:
And everything becomes obvious, because the result reaching my eyes is:
Apparently, gcc -std=c99 -O2
(GCC 5.2.0) has transformed the
if-statement into
which the specification clearly says is not an equivalent form. The
first term has probably been optimized away from here since multiple
if-statements use it. Compiling with GCC 4.8.3 on another x86-64
machine seems to cause three cmpb
instructions to be output, so I
wonder if this is new behavior in GCC 5.
In the end, this is likely benign. The address looks properly aligned. Note this is on a 64-bit machine, so it is even unlikely to cause a page-fault. Especially with the string located on the stack. It seems equivalent in terms of processing results, but means I will need to create a Valgrind supressions file for bad-ass GCC optimizations.