Skip to content

Commit 089723d

Browse files
[clang] Implement -fstrict-bool
``bool`` values are stored as i8 in memory, and it is undefined behavior for a ``bool`` value to be any value other than 0 or 1. Clang exploits this with range metadata: ``bool`` load instructions at any optimization level above -O0 are assumed to only have their lowest bit set. This can create memory safety problems when other bits are set, for instance through ``memcpy``. This change adds a ``-f[no-]strict-bool`` option that controls this behavior. It is enabled by default in order to not upset the status quo, except in the Darwin driver when passing -mkernel. Radar-ID: 139397212
1 parent da032a6 commit 089723d

File tree

6 files changed

+44
-4
lines changed

6 files changed

+44
-4
lines changed

clang/docs/UsersManual.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2179,6 +2179,11 @@ are listed below.
21792179

21802180
This option is currently experimental.
21812181

2182+
.. option:: -f[no-]strict-bool
2183+
2184+
Enable optimizations based on the assumption that all ``bool`` values have
2185+
a bit pattern of either 0 or 1. Enabled by default.
2186+
21822187
.. option:: -fstrict-vtable-pointers
21832188

21842189
Enable optimizations based on the strict rules for overwriting polymorphic

clang/include/clang/Basic/CodeGenOptions.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,7 @@ CODEGENOPT(SimplifyLibCalls , 1, 1) ///< Set when -fbuiltin is enabled.
311311
CODEGENOPT(SoftFloat , 1, 0) ///< -soft-float.
312312
CODEGENOPT(SpeculativeLoadHardening, 1, 0) ///< Enable speculative load hardening.
313313
CODEGENOPT(FineGrainedBitfieldAccesses, 1, 0) ///< Enable fine-grained bitfield accesses.
314+
CODEGENOPT(StrictBool , 1, 1) ///< Optimize based on bool bit patterns being either 0 or 1.
314315
CODEGENOPT(StrictEnums , 1, 0) ///< Optimize based on strict enum definition.
315316
CODEGENOPT(StrictVTablePointers, 1, 0) ///< Optimize based on the strict vtable pointers
316317
CODEGENOPT(TimePasses , 1, 0) ///< Set when -ftime-report or -ftime-report= is enabled.

clang/include/clang/Driver/Options.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3970,6 +3970,12 @@ def fno_debug_macro : Flag<["-"], "fno-debug-macro">, Group<f_Group>,
39703970
def fstrict_aliasing : Flag<["-"], "fstrict-aliasing">, Group<f_Group>,
39713971
Visibility<[ClangOption, CLOption, DXCOption]>,
39723972
HelpText<"Enable optimizations based on strict aliasing rules">;
3973+
defm strict_bool : BoolFOption<"strict-bool",
3974+
CodeGenOpts<"StrictBool">, DefaultTrue,
3975+
PosFlag<SetTrue, [], [ClangOption, CC1Option], "Enable ">,
3976+
NegFlag<SetFalse, [], [ClangOption, CC1Option], "Disable ">,
3977+
BothFlags<[], [ClangOption], "optimizations based on bool bit patterns never "
3978+
"being anything other than 0 or 1">>;
39733979
def fstrict_enums : Flag<["-"], "fstrict-enums">, Group<f_Group>,
39743980
Visibility<[ClangOption, CC1Option]>,
39753981
HelpText<"Enable optimizations based on the strict definition of an enum's "

clang/lib/CodeGen/CGExpr.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1896,16 +1896,18 @@ static bool hasBooleanRepresentation(QualType Ty) {
18961896
return false;
18971897
}
18981898

1899-
static bool getRangeForType(CodeGenFunction &CGF, QualType Ty,
1900-
llvm::APInt &Min, llvm::APInt &End,
1901-
bool StrictEnums, bool IsBool) {
1899+
static bool getRangeForType(CodeGenFunction &CGF, QualType Ty, llvm::APInt &Min,
1900+
llvm::APInt &End, bool StrictEnums, bool StrictBool,
1901+
bool IsBool) {
19021902
const EnumType *ET = Ty->getAs<EnumType>();
19031903
bool IsRegularCPlusPlusEnum = CGF.getLangOpts().CPlusPlus && StrictEnums &&
19041904
ET && !ET->getDecl()->isFixed();
19051905
if (!IsBool && !IsRegularCPlusPlusEnum)
19061906
return false;
19071907

19081908
if (IsBool) {
1909+
if (!StrictBool)
1910+
return false;
19091911
Min = llvm::APInt(CGF.getContext().getTypeSize(Ty), 0);
19101912
End = llvm::APInt(CGF.getContext().getTypeSize(Ty), 2);
19111913
} else {
@@ -1918,6 +1920,7 @@ static bool getRangeForType(CodeGenFunction &CGF, QualType Ty,
19181920
llvm::MDNode *CodeGenFunction::getRangeForLoadFromType(QualType Ty) {
19191921
llvm::APInt Min, End;
19201922
if (!getRangeForType(*this, Ty, Min, End, CGM.getCodeGenOpts().StrictEnums,
1923+
CGM.getCodeGenOpts().StrictBool,
19211924
hasBooleanRepresentation(Ty)))
19221925
return nullptr;
19231926

@@ -1951,7 +1954,8 @@ bool CodeGenFunction::EmitScalarRangeCheck(llvm::Value *Value, QualType Ty,
19511954
return false;
19521955

19531956
llvm::APInt Min, End;
1954-
if (!getRangeForType(*this, Ty, Min, End, /*StrictEnums=*/true, IsBool))
1957+
if (!getRangeForType(*this, Ty, Min, End, /*StrictEnums=*/true,
1958+
/*StrctBool=*/true, IsBool))
19551959
return true;
19561960

19571961
auto &Ctx = getLLVMContext();

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5938,6 +5938,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
59385938
if (!Args.hasFlag(options::OPT_fstruct_path_tbaa,
59395939
options::OPT_fno_struct_path_tbaa, true))
59405940
CmdArgs.push_back("-no-struct-path-tbaa");
5941+
Args.addOptOutFlag(CmdArgs, options::OPT_fstrict_bool,
5942+
options::OPT_fno_strict_bool);
59415943
Args.addOptInFlag(CmdArgs, options::OPT_fstrict_enums,
59425944
options::OPT_fno_strict_enums);
59435945
Args.addOptOutFlag(CmdArgs, options::OPT_fstrict_return,
@@ -6052,6 +6054,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
60526054
if (!RawTriple.isOSDarwin() && !RawTriple.isNVPTX())
60536055
CmdArgs.push_back("-mconstructor-aliases");
60546056

6057+
// Assume -fno-strict-bool in the Darwin kernel.
6058+
if (KernelOrKext)
6059+
CmdArgs.push_back("-fno-strict-bool");
6060+
60556061
// Darwin's kernel doesn't support guard variables; just die if we
60566062
// try to use them.
60576063
if (KernelOrKext && RawTriple.isOSDarwin())

clang/test/CodeGen/strict-bool.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// RUN: %clang_cc1 -triple armv7-apple-darwin -O1 -fstrict-bool -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK-STRICT
2+
// RUN: %clang_cc1 -triple armv7-apple-darwin -O1 -fno-strict-bool -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK-NO-STRICT
3+
// RUN: %clang -target armv7-apple-darwin -O1 -mkernel -S -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK-NO-STRICT
4+
5+
struct has_bool {
6+
_Bool b;
7+
};
8+
9+
int foo(struct has_bool *b) {
10+
// CHECK-STRICT: load i8, {{.*}}, !range ![[RANGE_BOOL:[0-9]+]]
11+
// CHECK-STRICT-NOT: and i8
12+
13+
// CHECK-NO-STRICT: [[BOOL:%.+]] = load i8
14+
// CHECK-NO-STRICT: and i8 [[BOOL]], 1
15+
return b->b;
16+
}
17+
18+
// CHECK_STRICT: ![[RANGE_BOOL]] = !{i8 0, i8 2}

0 commit comments

Comments
 (0)