Skip to content

Commit d1ae89c

Browse files
authored
Short-term solution for issue 1009. (#1014)
* Short-term solution for issue 1009. * Corrected a slip.
1 parent a78bce7 commit d1ae89c

File tree

4 files changed

+113
-18
lines changed

4 files changed

+113
-18
lines changed

clang/include/clang/Sema/Sema.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5667,7 +5667,8 @@ class Sema final {
56675667
BoundsExpr *MakeMemberBoundsConcrete(Expr *MemberBase, bool IsArrow,
56685668
BoundsExpr *Bounds);
56695669
BoundsExpr *ConcretizeFromFunctionTypeWithArgs(BoundsExpr *Bounds, ArrayRef<Expr *> Args,
5670-
NonModifyingContext ErrorKind);
5670+
NonModifyingContext ErrorKind,
5671+
NonModifyingMessage Message);
56715672

56725673
/// ConvertToFullyCheckedType: convert an expression E to a fully checked type. This
56735674
/// is used to retype declrefs and member exprs in checked scopes with bounds-safe

clang/lib/Sema/SemaBounds.cpp

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -259,14 +259,17 @@ namespace {
259259
const ArrayRef<Expr *> Arguments;
260260
llvm::SmallBitVector VisitedArgs;
261261
Sema::NonModifyingContext ErrorKind;
262+
Sema::NonModifyingMessage Message;
262263
bool ModifyingArg;
263264
public:
264265
CheckForModifyingArgs(Sema &SemaRef, ArrayRef<Expr *> Args,
265-
Sema::NonModifyingContext ErrorKind) :
266+
Sema::NonModifyingContext ErrorKind,
267+
Sema::NonModifyingMessage Message) :
266268
SemaRef(SemaRef),
267269
Arguments(Args),
268270
VisitedArgs(Args.size()),
269271
ErrorKind(ErrorKind),
272+
Message(Message),
270273
ModifyingArg(false) {}
271274

272275
bool FoundModifyingArg() {
@@ -277,8 +280,7 @@ namespace {
277280
unsigned index = E->getIndex();
278281
if (index < Arguments.size() && !VisitedArgs[index]) {
279282
VisitedArgs.set(index);
280-
if (!SemaRef.CheckIsNonModifying(Arguments[index], ErrorKind,
281-
Sema::NonModifyingMessage::NMM_Error)) {
283+
if (!SemaRef.CheckIsNonModifying(Arguments[index], ErrorKind, Message)) {
282284
ModifyingArg = true;
283285
}
284286
}
@@ -313,11 +315,11 @@ namespace {
313315

314316
BoundsExpr *Sema::ConcretizeFromFunctionTypeWithArgs(
315317
BoundsExpr *Bounds, ArrayRef<Expr *> Args,
316-
NonModifyingContext ErrorKind) {
318+
NonModifyingContext ErrorKind, NonModifyingMessage Message) {
317319
if (!Bounds || Bounds->isInvalid())
318320
return Bounds;
319321

320-
auto CheckArgs = CheckForModifyingArgs(*this, Args, ErrorKind);
322+
auto CheckArgs = CheckForModifyingArgs(*this, Args, ErrorKind, Message);
321323
CheckArgs.TraverseStmt(Bounds);
322324
if (CheckArgs.FoundModifyingArg())
323325
return nullptr;
@@ -3279,7 +3281,7 @@ namespace {
32793281
BoundsExpr *CheckCallExpr(CallExpr *E, CheckedScopeSpecifier CSS,
32803282
CheckingState &State,
32813283
CHKCBindTemporaryExpr *Binding = nullptr) {
3282-
BoundsExpr *ResultBounds = CallExprBounds(E, Binding);
3284+
BoundsExpr *ResultBounds = CallExprBounds(E, Binding, CSS);
32833285

32843286
QualType CalleeType = E->getCallee()->getType();
32853287
// Extract the pointee type. The caller type could be a regular pointer
@@ -3367,7 +3369,8 @@ namespace {
33673369
S.ConcretizeFromFunctionTypeWithArgs(
33683370
const_cast<BoundsExpr *>(ParamBounds),
33693371
ArgExprs,
3370-
Sema::NonModifyingContext::NMC_Function_Parameter);
3372+
Sema::NonModifyingContext::NMC_Function_Parameter,
3373+
Sema::NonModifyingMessage::NMM_Error);
33713374

33723375
if (!SubstParamBounds)
33733376
continue;
@@ -5936,7 +5939,8 @@ namespace {
59365939
// If ResultName is non-null, it is a temporary variable where the result
59375940
// of the call expression is stored immediately upon return from the call.
59385941
BoundsExpr *CallExprBounds(const CallExpr *CE,
5939-
CHKCBindTemporaryExpr *ResultName) {
5942+
CHKCBindTemporaryExpr *ResultName,
5943+
CheckedScopeSpecifier CSS) {
59405944
BoundsExpr *ReturnBounds = nullptr;
59415945
if (CE->getType()->isCheckedPointerPtrType()) {
59425946
if (CE->getType()->isVoidPointerType())
@@ -5963,7 +5967,7 @@ namespace {
59635967
BoundsExpr *FunBounds = FunReturnAnnots.getBoundsExpr();
59645968
InteropTypeExpr *IType =FunReturnAnnots.getInteropTypeExpr();
59655969
// If there is no return bounds and there is an interop type
5966-
// annotation, use the bounds impied by the interop type
5970+
// annotation, use the bounds implied by the interop type
59675971
// annotation.
59685972
if (!FunBounds && IType)
59695973
FunBounds = CreateTypeBasedBounds(nullptr, IType->getType(),
@@ -5978,10 +5982,22 @@ namespace {
59785982
CE->getNumArgs());
59795983

59805984
// Concretize Call Bounds with argument expressions.
5981-
// We can only do this if the argument expressions are non-modifying
5985+
// We can only do this if the argument expressions are non-modifying.
5986+
// For argument expressions that are modifying, we issue an error
5987+
// message only in checked scope because the argument expressions may
5988+
// be re-evaluated during bounds validation.
5989+
// TODO: The long-term solution is to introduce temporaries for
5990+
// modifying argument expressions whose corresponding formals are used
5991+
// in return or parameter bounds expressions.
5992+
// Equality between the value computed by an argument expression and its
5993+
// associated temporary would also need to be recorded.
5994+
Sema::NonModifyingMessage Message =
5995+
(CSS == CheckedScopeSpecifier::CSS_Unchecked) ?
5996+
Sema::NonModifyingMessage::NMM_None :
5997+
Sema::NonModifyingMessage::NMM_Error;
59825998
ReturnBounds =
59835999
S.ConcretizeFromFunctionTypeWithArgs(FunBounds, ArgExprs,
5984-
Sema::NonModifyingContext::NMC_Function_Return);
6000+
Sema::NonModifyingContext::NMC_Function_Return, Message);
59856001
// If concretization failed, this means we tried to substitute with
59866002
// a non-modifying expression, which is not allowed by the
59876003
// specification.

clang/test/CheckedC/inferred-bounds/calls.c

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,6 @@ void f10(_Array_ptr<int> a, _Array_ptr<int> b) {
169169

170170
void f11(_Array_ptr<int> a, _Array_ptr<int> b) {
171171
_Array_ptr<int> c : bounds(a, a+1) = f_bounds(b++, a); // \
172-
// expected-error {{expression not allowed in argument for parameter used in function return bounds}} \
173172
// expected-error {{inferred bounds for 'c' are unknown after initialization}} \
174173
// expected-note {{(expanded) declared bounds are 'bounds(a, a + 1)'}}
175174
}
@@ -230,7 +229,6 @@ void f12(int i, int j) {
230229

231230
void f13(int i, int j) {
232231
_Array_ptr<int> b : count(i) = f_count(j++, i); // \
233-
// expected-error {{expression not allowed in argument for parameter used in function return bounds}} \
234232
// expected-error {{inferred bounds for 'b' are unknown after initialization}} \
235233
// expected-note {{(expanded) declared bounds are 'bounds(b, b + i)'}}
236234
}
@@ -285,7 +283,6 @@ void f14(int i, int j) {
285283

286284
void f15(int i, int j) {
287285
_Array_ptr<int> b : byte_count(i) = f_byte(j++, i); // \
288-
// expected-error {{expression not allowed in argument for parameter used in function return bounds}} \
289286
// expected-error {{inferred bounds for 'b' are unknown after initialization}} \
290287
// expected-note {{(expanded) declared bounds are 'bounds((_Array_ptr<char>)b, (_Array_ptr<char>)b + i)'}}
291288
}
@@ -349,7 +346,6 @@ void f20(int* a, int* b) {
349346

350347
void f21(int* a, int* b) {
351348
_Array_ptr<int> c : bounds(a, a+1) = f_boundsi(b++, a); // \
352-
// expected-error {{expression not allowed in argument for parameter used in function return bounds}} \
353349
// expected-error {{inferred bounds for 'c' are unknown after initialization}} \
354350
// expected-note {{(expanded) declared bounds are 'bounds(a, a + 1)'}}
355351
}
@@ -412,7 +408,6 @@ void f22(int i, int j) {
412408

413409
void f23(int i, int j) {
414410
_Array_ptr<int> b : count(i) = f_counti(j++, i); // \
415-
// expected-error {{expression not allowed in argument for parameter used in function return bounds}} \
416411
// expected-error {{inferred bounds for 'b' are unknown after initialization}} \
417412
// expected-note {{(expanded) declared bounds are 'bounds(b, b + i)'}}
418413
}
@@ -469,7 +464,6 @@ void f24(int i, int j) {
469464

470465
void f25(int i, int j) {
471466
_Array_ptr<int> b : byte_count(i) = f_bytei(j++, i); // \
472-
// expected-error {{expression not allowed in argument for parameter used in function return bounds}} \
473467
// expected-error {{inferred bounds for 'b' are unknown after initialization}} \
474468
// expected-note {{(expanded) declared bounds are 'bounds((_Array_ptr<char>)b, (_Array_ptr<char>)b + i)'}}
475469
}

clang/test/CheckedC/static-checking/bounds-side-effects.c

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,3 +227,87 @@ void f105(int len, _Array_ptr<int> p : count(len), int i) {
227227
len += 1, p = alloc(len * sizeof(int));
228228
}
229229

230+
extern int memcmp_test(const void *src1 : byte_count(n),
231+
const void *src2 :byte_count(n), unsigned int n);
232+
extern void *memchr_test(const void *s : byte_count(n), int c, unsigned int n) :
233+
bounds(s, (_Array_ptr<char>) s + n);
234+
extern _Itype_for_any(T) void *malloc_test(unsigned int size) :
235+
itype(_Array_ptr<T>) byte_count(size);
236+
237+
// Checked pointers in checked scope
238+
void f106()
239+
_Checked
240+
{
241+
int len = 4;
242+
_Nt_array_ptr<char> p : count(5) = "hello";
243+
int i = memcmp_test(p, "hello", ++len); // expected-error {{increment expression not allowed in argument for parameter used in function parameter bounds expression}} \
244+
// expected-error {{increment expression not allowed in argument for parameter used in function parameter bounds expression}}
245+
}
246+
247+
// Checked pointers in unchecked scope
248+
void f106_u1()
249+
{
250+
int len = 4;
251+
_Nt_array_ptr<char> p : count(5) = "hello";
252+
int i = memcmp_test(p, "hello", ++len); // expected-error {{increment expression not allowed in argument for parameter used in function parameter bounds expression}}
253+
}
254+
255+
// Unchecked pointers in unchecked scope
256+
void f106_u2()
257+
{
258+
int len = 4;
259+
char *p = "hello";
260+
int i = memcmp_test(p, "hello", ++len);
261+
}
262+
263+
// Checked pointers in checked scope
264+
void f107()
265+
_Checked
266+
{
267+
int len = 4;
268+
int p _Checked [5] = {'h', 'e', 'l', 'l', 'o'};
269+
_Array_ptr<int> pos = memchr_test(p, 'l', ++len); // expected-error {{increment expression not allowed in argument for parameter used in function return bounds expression}} \
270+
// expected-error {{increment expression not allowed in argument for parameter used in function parameter bounds expression}}
271+
}
272+
273+
// Checked pointers in unchecked scope
274+
void f107_u1()
275+
{
276+
int len = 4;
277+
int p _Checked [5] = {'h', 'e', 'l', 'l', 'o'};
278+
// Ideally, there should be an error for modifying expressions
279+
// used in the return bounds expression also.
280+
_Array_ptr<int> pos = memchr_test(p, 'l', ++len); // expected-error {{increment expression not allowed in argument for parameter used in function parameter bounds expression}}
281+
}
282+
283+
// Unchecked pointers in unchecked scope
284+
void f107_u2()
285+
{
286+
int len = 4;
287+
int p[5] = {'h', 'e', 'l', 'l', 'o'};
288+
int *pos = memchr_test(p, 'l', ++len);
289+
}
290+
291+
// Checked pointers in checked scope
292+
void f108()
293+
_Checked
294+
{
295+
int len = 5;
296+
_Array_ptr<char> p = malloc_test<char>(++len); // expected-error {{increment expression not allowed in argument for parameter used in function return bounds expression}}
297+
}
298+
299+
// Checked pointers in unchecked scope
300+
void f108_u1()
301+
{
302+
int len = 5;
303+
// Ideally, there should be an error for modifying expressions
304+
// used in the return bounds expression also.
305+
_Array_ptr<char> p = malloc_test<char>(++len);
306+
}
307+
308+
// Unchecked pointers in unchecked scope
309+
void f108_u2()
310+
{
311+
int len = 5;
312+
char *p = malloc_test(++len);
313+
}

0 commit comments

Comments
 (0)