Skip to content

Commit 708c8cd

Browse files
Zonotoravitalybuka
andauthored
Fix "[clang][UBSan] Add implicit conversion check for bitfields" (#87761)
Fix since #75481 got reverted. - Explicitly set BitfieldBits to 0 to avoid uninitialized field member for the integer checks: ```diff - llvm::ConstantInt::get(Builder.getInt8Ty(), Check.first)}; + llvm::ConstantInt::get(Builder.getInt8Ty(), Check.first), + llvm::ConstantInt::get(Builder.getInt32Ty(), 0)}; ``` - `Value **Previous` was erroneously `Value *Previous` in `CodeGenFunction::EmitWithOriginalRHSBitfieldAssignment`, fixed now. - Update following: ```diff - if (Kind == CK_IntegralCast) { + if (Kind == CK_IntegralCast || Kind == CK_LValueToRValue) { ``` CK_LValueToRValue when going from, e.g., char to char, and CK_IntegralCast otherwise. - Make sure that `Value *Previous = nullptr;` is initialized (see 1189e87) - Add another extensive testcase `ubsan/TestCases/ImplicitConversion/bitfield-conversion.c` --------- Co-authored-by: Vitaly Buka <[email protected]>
1 parent 89eb1a5 commit 708c8cd

File tree

36 files changed

+1578
-506
lines changed

36 files changed

+1578
-506
lines changed

clang/docs/ReleaseNotes.rst

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

199199
New Compiler Flags
200200
------------------
201+
- ``-fsanitize=implicit-bitfield-conversion`` checks implicit truncation and
202+
sign change.
203+
- ``-fsanitize=implicit-integer-conversion`` a group that replaces the previous
204+
group ``-fsanitize=implicit-conversion``.
201205

202206
- ``-Wmissing-designated-field-initializers``, grouped under ``-Wmissing-field-initializers``.
203207
This diagnostic can be disabled to make ``-Wmissing-field-initializers`` behave
@@ -211,6 +215,9 @@ Modified Compiler Flags
211215
- Added a new diagnostic flag ``-Wreturn-mismatch`` which is grouped under
212216
``-Wreturn-type``, and moved some of the diagnostics previously controlled by
213217
``-Wreturn-type`` under this new flag. Fixes #GH72116.
218+
- ``-fsanitize=implicit-conversion`` is now a group for both
219+
``-fsanitize=implicit-integer-conversion`` and
220+
``-fsanitize=implicit-bitfield-conversion``.
214221

215222
- Added ``-Wcast-function-type-mismatch`` under the ``-Wcast-function-type``
216223
warning group. Moved the diagnostic previously controlled by

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
@@ -5597,11 +5597,44 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) {
55975597
break;
55985598
}
55995599

5600-
RValue RV = EmitAnyExpr(E->getRHS());
5600+
// TODO: Can we de-duplicate this code with the corresponding code in
5601+
// CGExprScalar, similar to the way EmitCompoundAssignmentLValue works?
5602+
RValue RV;
5603+
llvm::Value *Previous = nullptr;
5604+
QualType SrcType = E->getRHS()->getType();
5605+
// Check if LHS is a bitfield, if RHS contains an implicit cast expression
5606+
// we want to extract that value and potentially (if the bitfield sanitizer
5607+
// is enabled) use it to check for an implicit conversion.
5608+
if (E->getLHS()->refersToBitField()) {
5609+
llvm::Value *RHS =
5610+
EmitWithOriginalRHSBitfieldAssignment(E, &Previous, &SrcType);
5611+
RV = RValue::get(RHS);
5612+
} else
5613+
RV = EmitAnyExpr(E->getRHS());
5614+
56015615
LValue LV = EmitCheckedLValue(E->getLHS(), TCK_Store);
5616+
56025617
if (RV.isScalar())
56035618
EmitNullabilityCheck(LV, RV.getScalarVal(), E->getExprLoc());
5604-
EmitStoreThroughLValue(RV, LV);
5619+
5620+
if (LV.isBitField()) {
5621+
llvm::Value *Result = nullptr;
5622+
// If bitfield sanitizers are enabled we want to use the result
5623+
// to check whether a truncation or sign change has occurred.
5624+
if (SanOpts.has(SanitizerKind::ImplicitBitfieldConversion))
5625+
EmitStoreThroughBitfieldLValue(RV, LV, &Result);
5626+
else
5627+
EmitStoreThroughBitfieldLValue(RV, LV);
5628+
5629+
// If the expression contained an implicit conversion, make sure
5630+
// to use the value before the scalar conversion.
5631+
llvm::Value *Src = Previous ? Previous : RV.getScalarVal();
5632+
QualType DstType = E->getLHS()->getType();
5633+
EmitBitfieldConversionCheck(Src, SrcType, Result, DstType,
5634+
LV.getBitFieldInfo(), E->getExprLoc());
5635+
} else
5636+
EmitStoreThroughLValue(RV, LV);
5637+
56055638
if (getLangOpts().OpenMP)
56065639
CGM.getOpenMPRuntime().checkAndEmitLastprivateConditional(*this,
56075640
E->getLHS());

0 commit comments

Comments
 (0)