Skip to content

Commit

Permalink
tests: Rewrite code to circument potential bug in clang
Browse files Browse the repository at this point in the history
clang 7 to 11 (and maybe earlier versions) warn about recid being
potentially unitiliazed in "CHECK(recid >= 0 [...]", which was mitigated
in commit 3d2cf6c by initializing recid
to make clang happy but VG_UNDEF'ing the variable after initializiation
in order to ensure valgrind's memcheck analysis will still be sound and
complain if recid is not actually written to when creating a signature.

However, it turns out that at least for binaries produced by clang 11
(but not clang 7), valgrind complains about a branch on unitialized data
in the recid variable in that line before *and* after the aforementioned
commit. While the complaint after the commit could be spurious (clang
knows that recid is initialized, so it's fine to access it even though
the access is stupid), the complaint before the commit indicates a real
problem: it might be the case that clang is performing a wrong
optimization that leads to a situation where recid is really not
guaranteed to be initialized when it's accessed. As a result, clang
warns about this and generates code that just accesses the variable.

I'm not going to bother with this further because this is fixed in
clang 12 and the problem is just in our test code, not in the tested
code.

This commit rewrites the code in a way that groups the signing together
with the CHECK such that it's very easy to figure out for clang that
recid will be initialized properly. This seems to circument the issue.
  • Loading branch information
real-or-random committed Aug 19, 2021
1 parent 3d2f492 commit 5d5c74a
Showing 1 changed file with 6 additions and 4 deletions.
10 changes: 6 additions & 4 deletions src/tests.c
Expand Up @@ -5262,17 +5262,19 @@ void test_ecdsa_sign_verify(void) {
secp256k1_scalar msg, key;
secp256k1_scalar sigr, sigs;
int getrec;
/* Initialize recid to suppress a false positive -Wconditional-uninitialized in clang.
VG_UNDEF ensures that valgrind will still treat the variable as uninitialized. */
int recid = -1; VG_UNDEF(&recid, sizeof(recid));
int recid;
random_scalar_order_test(&msg);
random_scalar_order_test(&key);
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pubj, &key);
secp256k1_ge_set_gej(&pub, &pubj);
getrec = secp256k1_testrand_bits(1);
random_sign(&sigr, &sigs, &key, &msg, getrec?&recid:NULL);
/* The specific way in which this conditional is written sidesteps a potential bug in clang.
See the commit messages of the commit that introduced this comment for details. */
if (getrec) {
random_sign(&sigr, &sigs, &key, &msg, &recid);
CHECK(recid >= 0 && recid < 4);
} else {
random_sign(&sigr, &sigs, &key, &msg, NULL);
}
CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sigr, &sigs, &pub, &msg));
secp256k1_scalar_set_int(&one, 1);
Expand Down

0 comments on commit 5d5c74a

Please sign in to comment.