fortify: rewrite strlen to fold to a constant
This new spelling allows Clang, when parsing C, to fold `strlen("foo")`
into a constant in many more places.
This shouldn't be much of a performance diff, since LLVM is already
fully capable of folding `@__strlen_chk` into `@strlen` or a constant as
appropriate. Mostly it matters for places where constants may be
required, or may result in materially different codegen (e.g., static
initializers, array bounds, ...)
Bug: 139143453
Test: mma
Change-Id: Ib1636402a11338f6e05a731cc5a59c919cca09e8
diff --git a/tests/clang_fortify_tests.cpp b/tests/clang_fortify_tests.cpp
index f08fd1f..105c261 100644
--- a/tests/clang_fortify_tests.cpp
+++ b/tests/clang_fortify_tests.cpp
@@ -89,6 +89,8 @@
#include <unistd.h>
#include <wchar.h>
+#include <array>
+
#ifndef COMPILATION_TESTS
#include <android-base/silent_death_test.h>
#include <gtest/gtest.h>
@@ -133,6 +135,25 @@
const static int kBogusFD = -1;
+FORTIFY_TEST(strlen) {
+ auto run_strlen_with_contents = [&](std::array<char, 3> contents) {
+ // A lot of cruft is necessary to make this test DTRT. LLVM and Clang love to fold/optimize
+ // strlen calls, and that's the opposite of what we want to happen.
+
+ // Loop to convince LLVM that `contents` can never be known (since `xor volatile_value` can flip
+ // any bit in each elem of `contents`).
+ volatile char always_zero = 0;
+ for (char& c : contents) {
+ c ^= always_zero;
+ }
+ // Store in a volatile, so the strlen itself cannot be optimized out.
+ volatile size_t _strlen_result = strlen(&contents.front());
+ };
+
+ EXPECT_NO_DEATH(run_strlen_with_contents({'f', 'o', '\0'}));
+ EXPECT_FORTIFY_DEATH(run_strlen_with_contents({'f', 'o', 'o'}));
+}
+
FORTIFY_TEST(string) {
char small_buffer[8] = {};