Skip to content

Commit 0cf83f5

Browse files
committed
[clang][UBSan] Add implicit conversion check for bitfields
This patch implements the implicit truncation and implicit sign change checks for bitfields.
1 parent 3213a5d commit 0cf83f5

File tree

10 files changed

+461
-38
lines changed

10 files changed

+461
-38
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,10 @@ Non-comprehensive list of changes in this release
173173

174174
New Compiler Flags
175175
------------------
176+
- ``-fsanitize=implicit-bitfield-conversion`` checks implicit truncation and
177+
sign change.
178+
- ``-fsanitize=implicit-integer-conversion`` a group that replaces the previous
179+
group ``-fsanitize=implicit-conversion``.
176180

177181
- ``-Wmissing-designated-field-initializers``, grouped under ``-Wmissing-field-initializers``.
178182
This diagnostic can be disabled to make ``-Wmissing-field-initializers`` behave
@@ -186,6 +190,9 @@ Modified Compiler Flags
186190
- Added a new diagnostic flag ``-Wreturn-mismatch`` which is grouped under
187191
``-Wreturn-type``, and moved some of the diagnostics previously controlled by
188192
``-Wreturn-type`` under this new flag. Fixes #GH72116.
193+
- ``-fsanitize=implicit-conversion`` is now a group for both
194+
``-fsanitize=implicit-integer-conversion`` and
195+
``-fsanitize=implicit-bitfield-conversion``.
189196

190197
Removed Compiler Flags
191198
-------------------------

clang/docs/UndefinedBehaviorSanitizer.rst

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,11 @@ Available checks are:
148148
Issues caught by this sanitizer are not undefined behavior,
149149
but are often unintentional.
150150
- ``-fsanitize=integer-divide-by-zero``: Integer division by zero.
151+
- ``-fsanitize=implicit-bitfield-conversion``: Implicit conversion from
152+
integer of larger bit width to smaller bitfield, if that results in data
153+
loss. This includes unsigned/signed truncations and sign changes, similarly
154+
to how the ``-fsanitize=implicit-integer-conversion`` group works, but
155+
explicitly for bitfields.
151156
- ``-fsanitize=nonnull-attribute``: Passing null pointer as a function
152157
parameter which is declared to never be null.
153158
- ``-fsanitize=null``: Use of a null pointer or creation of a null
@@ -193,16 +198,16 @@ Available checks are:
193198
signed division overflow (``INT_MIN/-1``). Note that checks are still
194199
added even when ``-fwrapv`` is enabled. This sanitizer does not check for
195200
lossy implicit conversions performed before the computation (see
196-
``-fsanitize=implicit-conversion``). Both of these two issues are handled
197-
by ``-fsanitize=implicit-conversion`` group of checks.
201+
``-fsanitize=implicit-integer-conversion``). Both of these two issues are handled
202+
by ``-fsanitize=implicit-integer-conversion`` group of checks.
198203
- ``-fsanitize=unreachable``: If control flow reaches an unreachable
199204
program point.
200205
- ``-fsanitize=unsigned-integer-overflow``: Unsigned integer overflow, where
201206
the result of an unsigned integer computation cannot be represented in its
202207
type. Unlike signed integer overflow, this is not undefined behavior, but
203208
it is often unintentional. This sanitizer does not check for lossy implicit
204209
conversions performed before such a computation
205-
(see ``-fsanitize=implicit-conversion``).
210+
(see ``-fsanitize=implicit-integer-conversion``).
206211
- ``-fsanitize=vla-bound``: A variable-length array whose bound
207212
does not evaluate to a positive value.
208213
- ``-fsanitize=vptr``: Use of an object whose vptr indicates that it is of
@@ -224,11 +229,15 @@ You can also use the following check groups:
224229
- ``-fsanitize=implicit-integer-arithmetic-value-change``: Catches implicit
225230
conversions that change the arithmetic value of the integer. Enables
226231
``implicit-signed-integer-truncation`` and ``implicit-integer-sign-change``.
227-
- ``-fsanitize=implicit-conversion``: Checks for suspicious
228-
behavior of implicit conversions. Enables
232+
- ``-fsanitize=implicit-integer-conversion``: Checks for suspicious
233+
behavior of implicit integer conversions. Enables
229234
``implicit-unsigned-integer-truncation``,
230235
``implicit-signed-integer-truncation``, and
231236
``implicit-integer-sign-change``.
237+
- ``-fsanitize=implicit-conversion``: Checks for suspicious
238+
behavior of implicit conversions. Enables
239+
``implicit-integer-conversion``, and
240+
``implicit-bitfield-conversion``.
232241
- ``-fsanitize=integer``: Checks for undefined or suspicious integer
233242
behavior (e.g. unsigned integer overflow).
234243
Enables ``signed-integer-overflow``, ``unsigned-integer-overflow``,

clang/include/clang/Basic/Sanitizers.def

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -163,24 +163,24 @@ SANITIZER_GROUP("implicit-integer-arithmetic-value-change",
163163
ImplicitIntegerArithmeticValueChange,
164164
ImplicitIntegerSignChange | ImplicitSignedIntegerTruncation)
165165

166-
SANITIZER("objc-cast", ObjCCast)
166+
SANITIZER_GROUP("implicit-integer-conversion", ImplicitIntegerConversion,
167+
ImplicitIntegerArithmeticValueChange |
168+
ImplicitUnsignedIntegerTruncation)
167169

168-
// FIXME:
169-
//SANITIZER_GROUP("implicit-integer-conversion", ImplicitIntegerConversion,
170-
// ImplicitIntegerArithmeticValueChange |
171-
// ImplicitUnsignedIntegerTruncation)
172-
//SANITIZER_GROUP("implicit-conversion", ImplicitConversion,
173-
// ImplicitIntegerConversion)
170+
// Implicit bitfield sanitizers
171+
SANITIZER("implicit-bitfield-conversion", ImplicitBitfieldConversion)
174172

175173
SANITIZER_GROUP("implicit-conversion", ImplicitConversion,
176-
ImplicitIntegerArithmeticValueChange |
177-
ImplicitUnsignedIntegerTruncation)
174+
ImplicitIntegerConversion |
175+
ImplicitBitfieldConversion)
178176

179177
SANITIZER_GROUP("integer", Integer,
180-
ImplicitConversion | IntegerDivideByZero | Shift |
178+
ImplicitIntegerConversion | IntegerDivideByZero | Shift |
181179
SignedIntegerOverflow | UnsignedIntegerOverflow |
182180
UnsignedShiftBase)
183181

182+
SANITIZER("objc-cast", ObjCCast)
183+
184184
SANITIZER("local-bounds", LocalBounds)
185185
SANITIZER_GROUP("bounds", Bounds, ArrayBounds | LocalBounds)
186186

clang/lib/CodeGen/CGExpr.cpp

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5571,11 +5571,44 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) {
55715571
break;
55725572
}
55735573

5574-
RValue RV = EmitAnyExpr(E->getRHS());
5574+
// TODO: Can we de-duplicate this code with the corresponding code in
5575+
// CGExprScalar, similar to the way EmitCompoundAssignmentLValue works?
5576+
RValue RV;
5577+
llvm::Value *Previous = nullptr;
5578+
QualType SrcType = E->getRHS()->getType();
5579+
// Check if LHS is a bitfield, if RHS contains an implicit cast expression
5580+
// we want to extract that value and potentially (if the bitfield sanitizer
5581+
// is enabled) use it to check for an implicit conversion.
5582+
if (E->getLHS()->refersToBitField()) {
5583+
llvm::Value *RHS =
5584+
EmitWithOriginalRHSBitfieldAssignment(E, Previous, &SrcType);
5585+
RV = RValue::get(RHS);
5586+
} else
5587+
RV = EmitAnyExpr(E->getRHS());
5588+
55755589
LValue LV = EmitCheckedLValue(E->getLHS(), TCK_Store);
5590+
55765591
if (RV.isScalar())
55775592
EmitNullabilityCheck(LV, RV.getScalarVal(), E->getExprLoc());
5578-
EmitStoreThroughLValue(RV, LV);
5593+
5594+
if (LV.isBitField()) {
5595+
llvm::Value *Result;
5596+
// If bitfield sanitizers are enabled we want to use the result
5597+
// to check whether a truncation or sign change has occurred.
5598+
if (SanOpts.has(SanitizerKind::ImplicitBitfieldConversion))
5599+
EmitStoreThroughBitfieldLValue(RV, LV, &Result);
5600+
else
5601+
EmitStoreThroughBitfieldLValue(RV, LV);
5602+
5603+
// If the expression contained an implicit conversion, make sure
5604+
// to use the value before the scalar conversion.
5605+
llvm::Value *Src = Previous ? Previous : RV.getScalarVal();
5606+
QualType DstType = E->getLHS()->getType();
5607+
EmitBitfieldConversionCheck(Src, SrcType, Result, DstType,
5608+
LV.getBitFieldInfo(), E->getExprLoc());
5609+
} else
5610+
EmitStoreThroughLValue(RV, LV);
5611+
55795612
if (getLangOpts().OpenMP)
55805613
CGM.getOpenMPRuntime().checkAndEmitLastprivateConditional(*this,
55815614
E->getLHS());

0 commit comments

Comments
 (0)