Skip to content

Commit 49e3c6b

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 3b0af99 commit 49e3c6b

File tree

10 files changed

+553
-40
lines changed

10 files changed

+553
-40
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,26 @@ Non-comprehensive list of changes in this release
119119

120120
New Compiler Flags
121121
------------------
122+
- ``-fsanitize=implicit-unsigned-bitfield-truncation`` catches implicit
123+
unsigned conversions involving bitfields.
124+
- ``-fsanitize=implicit-signed-bitfield-truncation`` catches implicit
125+
signed conversions involving bitfields.
126+
- ``-fsanitize=implicit-bitfield-sign-change`` catches implicit
127+
conversions involving bitfields that result in a sign change.
128+
- ``-fsanitize=implicit-bitfield-truncation`` a group to include both
129+
``-fsanitize=implicit-unsigned-bitfield-truncation`` and
130+
``-fsanitize=implicit-signed-bitfield-truncation``.
131+
- ``-fsanitize=implicit-bitfield-arithmetic-value-change`` a group to
132+
include both ``implicit-signed-bitfield-truncation`` and
133+
``implicit-bitfield-sign-change``.
134+
- ``-fsanitize=implicit-bitfield-conversion`` a group to include
135+
``-fsanitize=implicit-unsigned-bitfield-truncation``,
136+
``-fsanitize=implicit-signed-bitfield-truncation`` and
137+
``implicit-bitfield-sign-change``.
138+
- ``-fsanitize=implicit-integer-conversion`` a group to include
139+
``-fsanitize=implicit-unsigned-integer-truncation``,
140+
``-fsanitize=implicit-signed-integer-truncation`` and
141+
``implicit-integer-sign-change``.
122142

123143
.. _target_os_detail:
124144

@@ -136,6 +156,11 @@ Deprecated Compiler Flags
136156

137157
Modified Compiler Flags
138158
-----------------------
159+
- ``-fsanitize=implicit-conversion`` is now a group for both
160+
``-fsanitize=implicit-integer-conversion`` and
161+
``-fsanitize=implicit-bitfield-conversion``. Hence,
162+
``-fsanitize=implicit-integer-conversion`` has replaced what previously
163+
was ``-fsanitize=implicit-conversion``.
139164

140165
Removed Compiler Flags
141166
-------------------------

clang/docs/UndefinedBehaviorSanitizer.rst

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,23 @@ 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-unsigned-bitfield-truncation``,
152+
``-fsanitize=implicit-signed-bitfield-truncation``: Implicit conversion from
153+
integer of larger bit width to smaller bitfield, if that results in data
154+
loss. That is, if the demoted value, after casting back to the original
155+
width, is not equal to the original value before the downcast.
156+
The ``-fsanitize=implicit-unsigned-bitfield-truncation`` handles conversions
157+
between two ``unsigned`` types, while
158+
``-fsanitize=implicit-signed-bitfield-truncation`` handles the rest of the
159+
conversions - when either one, or both of the types are signed.
160+
Issues caught by these sanitizers are not undefined behavior,
161+
but are often unintentional.
162+
- ``-fsanitize=implicit-bitfield-sign-change``: Implicit conversion from
163+
integer of larger bit width to smaller bitfield, if that changes the
164+
sign of the value. That is, if the original value was negative and the
165+
new value is positive (or zero), or the original value was positive,
166+
and the new value is negative. Issues caught by this sanitizer are not
167+
undefined behavior, but are often unintentional.
151168
- ``-fsanitize=nonnull-attribute``: Passing null pointer as a function
152169
parameter which is declared to never be null.
153170
- ``-fsanitize=null``: Use of a null pointer or creation of a null
@@ -192,16 +209,16 @@ Available checks are:
192209
This includes all the checks covered by ``-ftrapv``, as well as checks for
193210
signed division overflow (``INT_MIN/-1``), but not checks for
194211
lossy implicit conversions performed before the computation
195-
(see ``-fsanitize=implicit-conversion``). Both of these two issues are
196-
handled by ``-fsanitize=implicit-conversion`` group of checks.
212+
(see ``-fsanitize=implicit-integer-conversion``). Both of these two issues are
213+
handled by ``-fsanitize=implicit-integer-conversion`` group of checks.
197214
- ``-fsanitize=unreachable``: If control flow reaches an unreachable
198215
program point.
199216
- ``-fsanitize=unsigned-integer-overflow``: Unsigned integer overflow, where
200217
the result of an unsigned integer computation cannot be represented in its
201218
type. Unlike signed integer overflow, this is not undefined behavior, but
202219
it is often unintentional. This sanitizer does not check for lossy implicit
203220
conversions performed before such a computation
204-
(see ``-fsanitize=implicit-conversion``).
221+
(see ``-fsanitize=implicit-integer-conversion``).
205222
- ``-fsanitize=vla-bound``: A variable-length array whose bound
206223
does not evaluate to a positive value.
207224
- ``-fsanitize=vptr``: Use of an object whose vptr indicates that it is of
@@ -213,8 +230,9 @@ Available checks are:
213230
You can also use the following check groups:
214231
- ``-fsanitize=undefined``: All of the checks listed above other than
215232
``float-divide-by-zero``, ``unsigned-integer-overflow``,
216-
``implicit-conversion``, ``local-bounds`` and the ``nullability-*`` group
217-
of checks.
233+
``implicit-integer-conversion``, ``implicit-bitfield-conversion``,
234+
``implicit-conversion``, ``local-bounds`` and the ``nullability-*``
235+
group of checks.
218236
- ``-fsanitize=undefined-trap``: Deprecated alias of
219237
``-fsanitize=undefined``.
220238
- ``-fsanitize=implicit-integer-truncation``: Catches lossy integral
@@ -223,11 +241,26 @@ You can also use the following check groups:
223241
- ``-fsanitize=implicit-integer-arithmetic-value-change``: Catches implicit
224242
conversions that change the arithmetic value of the integer. Enables
225243
``implicit-signed-integer-truncation`` and ``implicit-integer-sign-change``.
226-
- ``-fsanitize=implicit-conversion``: Checks for suspicious
227-
behavior of implicit conversions. Enables
244+
- ``-fsanitize=implicit-integer-conversion``: Checks for suspicious
245+
behavior of implicit integer conversions. Enables
228246
``implicit-unsigned-integer-truncation``,
229247
``implicit-signed-integer-truncation``, and
230248
``implicit-integer-sign-change``.
249+
- ``-fsanitize=implicit-bitfield-truncation``: Catches lossy bitfield
250+
conversions. Enables ``implicit-signed-bitfield-truncation`` and
251+
``implicit-unsigned-bitfield-truncation``.
252+
- ``-fsanitize=implicit-bitfield-arithmetic-value-change``: Catches implicit
253+
conversions that change the arithmetic value of the bitfield. Enables
254+
``implicit-signed-bitfield-truncation`` and ``implicit-bitfield-sign-change``.
255+
- ``-fsanitize=implicit-bitfield-conversion``: Checks for suspicious
256+
behavior of implicit bitfield conversions. Enables
257+
``implicit-unsigned-bitfield-truncation``,
258+
``implicit-signed-bitfield-truncation``, and
259+
``implicit-bitfield-sign-change``.
260+
- ``-fsanitize=implicit-conversion``: Checks for suspicious
261+
behavior of implicit conversions. Enables
262+
``implicit-integer-conversion``, and
263+
``implicit-bitfield-conversion``.
231264
- ``-fsanitize=integer``: Checks for undefined or suspicious integer
232265
behavior (e.g. unsigned integer overflow).
233266
Enables ``signed-integer-overflow``, ``unsigned-integer-overflow``,

clang/include/clang/Basic/Sanitizers.def

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -163,24 +163,38 @@ 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)
169+
170+
// Implicit bitfield sanitizers
171+
SANITIZER("implicit-unsigned-bitfield-truncation", ImplicitUnsignedBitfieldTruncation)
172+
SANITIZER("implicit-signed-bitfield-truncation", ImplicitSignedBitfieldTruncation)
173+
SANITIZER_GROUP("implicit-bitfield-truncation", ImplicitBitfieldTruncation,
174+
ImplicitUnsignedBitfieldTruncation |
175+
ImplicitSignedBitfieldTruncation)
176+
177+
SANITIZER("implicit-bitfield-sign-change", ImplicitBitfieldSignChange)
167178

168-
// FIXME:
169-
//SANITIZER_GROUP("implicit-integer-conversion", ImplicitIntegerConversion,
170-
// ImplicitIntegerArithmeticValueChange |
171-
// ImplicitUnsignedIntegerTruncation)
172-
//SANITIZER_GROUP("implicit-conversion", ImplicitConversion,
173-
// ImplicitIntegerConversion)
179+
SANITIZER_GROUP("implicit-bitfield-arithmetic-value-change",
180+
ImplicitBitfieldArithmeticValueChange,
181+
ImplicitBitfieldSignChange | ImplicitSignedBitfieldTruncation)
182+
183+
SANITIZER_GROUP("implicit-bitfield-conversion", ImplicitBitfieldConversion,
184+
ImplicitBitfieldArithmeticValueChange |
185+
ImplicitUnsignedBitfieldTruncation)
174186

175187
SANITIZER_GROUP("implicit-conversion", ImplicitConversion,
176-
ImplicitIntegerArithmeticValueChange |
177-
ImplicitUnsignedIntegerTruncation)
188+
ImplicitIntegerConversion |
189+
ImplicitBitfieldConversion)
178190

179191
SANITIZER_GROUP("integer", Integer,
180192
ImplicitConversion | IntegerDivideByZero | Shift |
181193
SignedIntegerOverflow | UnsignedIntegerOverflow |
182194
UnsignedShiftBase)
183195

196+
SANITIZER("objc-cast", ObjCCast)
197+
184198
SANITIZER("local-bounds", LocalBounds)
185199
SANITIZER_GROUP("bounds", Bounds, ArrayBounds | LocalBounds)
186200

clang/lib/CodeGen/CGExpr.cpp

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

5573-
RValue RV = EmitAnyExpr(E->getRHS());
5573+
llvm::Value *Previous = nullptr;
5574+
RValue RV;
5575+
QualType SrcType = E->getRHS()->getType();
5576+
// If LHS refers to a bitfield we want to retrieve the value before
5577+
// implicit conversion between the bitfield type and the RHS type
5578+
// and evaluate RHS without integer sanitizer checks (if passed)
5579+
if (auto *ICE = RetrieveImplicitCastExprForBitfieldSanitizer(E)) {
5580+
SrcType = ICE->getSubExpr()->getType();
5581+
Previous = EmitScalarExpr(ICE->getSubExpr());
5582+
// Pass default ScalarConversionOpts so that sanitizer check is
5583+
// not emitted here
5584+
llvm::Value *RHS = EmitScalarConversion(Previous, SrcType, ICE->getType(),
5585+
ICE->getExprLoc());
5586+
RV = RValue::get(RHS);
5587+
}
5588+
5589+
if (!Previous)
5590+
RV = EmitAnyExpr(E->getRHS());
5591+
55745592
LValue LV = EmitCheckedLValue(E->getLHS(), TCK_Store);
5593+
55755594
if (RV.isScalar())
55765595
EmitNullabilityCheck(LV, RV.getScalarVal(), E->getExprLoc());
5577-
EmitStoreThroughLValue(RV, LV);
5596+
5597+
if (LV.isBitField() && RV.isScalar()) {
5598+
llvm::Value *Src = Previous ? Previous : RV.getScalarVal();
5599+
QualType DstType = E->getLHS()->getType();
5600+
llvm::Value *Result;
5601+
EmitStoreThroughBitfieldLValue(RV, LV, &Result);
5602+
EmitBitfieldConversionCheck(Src, SrcType, Result, DstType,
5603+
LV.getBitFieldInfo(), E->getExprLoc());
5604+
} else
5605+
EmitStoreThroughLValue(RV, LV);
5606+
55785607
if (getLangOpts().OpenMP)
55795608
CGM.getOpenMPRuntime().checkAndEmitLastprivateConditional(*this,
55805609
E->getLHS());

0 commit comments

Comments
 (0)