Skip to content

Commit f18cc23

Browse files
Merge branch 'main' of github.com:correctcomputation/checkedc-clang into inline-struct-fixes
2 parents f7ae158 + 359b6a4 commit f18cc23

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+209
-179
lines changed

clang/include/clang/3C/ConstraintVariables.h

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,15 @@ typedef std::set<ConstraintKey> CVars;
4343
// Holds Atoms, one for each of the pointer (*) declared in the program.
4444
typedef std::vector<Atom *> CAtoms;
4545

46+
// Options for ConstraintVariable::mkString, using the code pattern described in
47+
// clang/include/clang/3C/OptionalParams.h. Use the MKSTRING_OPTS macro to
48+
// generate a MkStringOpts instance at a call site.
4649
struct MkStringOpts {
50+
// True when the generated string should include
51+
// the name of the variable, false for just the type.
4752
bool EmitName = true;
53+
// True when the generated string is expected
54+
// to be used inside an itype.
4855
bool ForItype = false;
4956
bool EmitPointee = false;
5057
bool UnmaskTypedef = false;
@@ -114,11 +121,12 @@ class ConstraintVariable {
114121
qtyToStr(QT, N == RETVAR ? "" : N)) {}
115122

116123
public:
117-
// Create a "for-rewriting" representation of this ConstraintVariable.
118-
// The 'emitName' parameter is true when the generated string should include
119-
// the name of the variable, false for just the type.
120-
// The 'forIType' parameter is true when the generated string is expected
121-
// to be used inside an itype.
124+
// Generate source code for the type and (in certain cases) the name of the
125+
// variable or function represented by this ConstraintVariable that reflects
126+
// any changes made by 3C and is suitable to insert during rewriting.
127+
//
128+
// This method is used in several contexts with special requirements, which
129+
// are addressed by the options in MkStringOpts; see the comments there.
122130
virtual std::string mkString(Constraints &CS,
123131
const MkStringOpts &Opts = {}) const = 0;
124132

clang/lib/3C/CastPlacement.cpp

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -172,33 +172,30 @@ CastPlacementVisitor::getCastString(ConstraintVariable *Dst,
172172
case CAST_TO_WILD:
173173
return std::make_pair("((" + Dst->getRewritableOriginalTy() + ")", ")");
174174
case CAST_TO_CHECKED: {
175+
// Needed as default to TypeVar branch below, reset otherwise.
176+
std::string Type = "_Ptr<";
175177
std::string Suffix = ")";
176178
if (const auto *DstPVC = dyn_cast<PVConstraint>(Dst)) {
177179
assert("Checked cast not to a pointer" && !DstPVC->getCvars().empty());
178180
ConstAtom *CA =
179181
Info.getConstraints().getAssignment(DstPVC->getCvars().at(0));
180182

181-
// Writing an _Assume_bounds_cast to an array type requires inserting
182-
// the bounds for destination array. These can come from the source
183-
// code or the infered bounds. If neither source is available, use empty
184-
// bounds.
185-
if (isa<ArrAtom>(CA) || isa<NTArrAtom>(CA)) {
186-
std::string Bounds = "";
187-
if (DstPVC->srcHasBounds())
188-
Bounds = DstPVC->getBoundsStr();
189-
else if (DstPVC->hasBoundsKey())
190-
Bounds = ABRewriter.getBoundsString(DstPVC, nullptr, true);
191-
if (Bounds.empty())
192-
Bounds = "byte_count(0)";
193-
194-
Suffix = ", " + Bounds + ")";
183+
// TODO: Writing an _Assume_bounds_cast to an array type requires
184+
// inserting the bounds for destination array. But the names used in src
185+
// and dest may be different, so we need more sophisticated code to
186+
// convert to local variable names. Use unknown bounds for now.
187+
if (isa<ArrAtom>(CA)) {
188+
Type = "_Array_ptr<";
189+
Suffix = ", bounds(unknown))";
190+
} else if (isa<NTArrAtom>(CA)) {
191+
Type = "_Nt_array_ptr<";
192+
Suffix = ", bounds(unknown))";
195193
}
196194
}
197195
// The destination's type may be generic, which would have an out-of-scope
198196
// type var, so use the already analysed local type var instead
199-
std::string Type;
200197
if (TypeVar != nullptr) {
201-
Type = "_Ptr<" +
198+
Type +=
202199
TypeVar->mkString(Info.getConstraints(),
203200
MKSTRING_OPTS(EmitName = false, EmitPointee = true)) +
204201
">";

clang/lib/3C/ConstraintVariables.cpp

Lines changed: 43 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -755,12 +755,19 @@ PointerVariableConstraint::mkString(Constraints &CS,
755755
UNPACK_OPTS(EmitName, ForItype, EmitPointee, UnmaskTypedef, UseName,
756756
ForItypeBase);
757757

758+
// This function has become pretty ad-hoc and has a number of known bugs: see
759+
// https://github.com/correctcomputation/checkedc-clang/issues/703. We hope to
760+
// overhaul it in the future.
761+
758762
// The name field encodes if this variable is the return type for a function.
759763
// TODO: store this information in a separate field.
760764
bool IsReturn = getName() == RETVAR;
761765

762-
if (UseName.empty())
766+
if (UseName.empty()) {
763767
UseName = getName();
768+
if (UseName.empty())
769+
EmitName = false;
770+
}
764771

765772
if (IsTypedef && !UnmaskTypedef) {
766773
std::string QualTypedef = gatherQualStrings() + TypedefString;
@@ -787,13 +794,9 @@ PointerVariableConstraint::mkString(Constraints &CS,
787794
bool EmittedBase = false;
788795
// Have we emitted the name of the variable yet?
789796
bool EmittedName = false;
790-
// Was the last variable an Array?
791-
bool PrevArr = false;
792-
// Is the entire type so far an array?
793-
bool AllArrays = true;
794797
if (!EmitName || IsReturn)
795798
EmittedName = true;
796-
uint32_t TypeIdx = 0;
799+
int TypeIdx = 0;
797800

798801
// If we've set a GenericIndex for void, it means we're converting it into
799802
// a generic function so give it the default generic type name.
@@ -807,16 +810,15 @@ PointerVariableConstraint::mkString(Constraints &CS,
807810
}
808811

809812
auto It = Vars.begin();
810-
auto I = 0;
811813
// Skip over first pointer level if only emitting pointee string.
812814
// This is needed when inserting type arguments.
813815
if (EmitPointee)
814816
++It;
815817
// Iterate through the vars(), but if we have an internal typedef, then stop
816818
// once you reach the typedef's level.
817819
for (; It != Vars.end() && IMPLIES(TypedefLevelInfo.HasTypedef,
818-
I < TypedefLevelInfo.TypedefLevel);
819-
++It, I++) {
820+
TypeIdx < TypedefLevelInfo.TypedefLevel);
821+
++It, TypeIdx++) {
820822
const auto &V = *It;
821823
ConstAtom *C = nullptr;
822824
if (ForItypeBase) {
@@ -838,21 +840,23 @@ PointerVariableConstraint::mkString(Constraints &CS,
838840
if (!ForItype && InferredGenericIndex == -1 && isVoidPtr())
839841
K = Atom::A_Wild;
840842

841-
if (PrevArr && ArrSizes.at(TypeIdx).first != O_SizedArray && !EmittedName) {
842-
EmittedName = true;
843+
// In a case like `_Ptr<TYPE> p[2]`, the ` p[2]` needs to end up _after_ the
844+
// `>`, so we need to push the ` p[2]` onto EndStrs _before_ the code below
845+
// pushes the `>`. In general, before we visit a checked pointer level (not
846+
// a checked array level), we need to transfer any pending array levels and
847+
// emit the name (if applicable).
848+
if (K != Atom::A_Wild && ArrSizes.at(TypeIdx).first != O_SizedArray) {
843849
addArrayAnnotations(ConstArrs, EndStrs);
844-
EndStrs.push_front(" " + UseName);
850+
if (!EmittedName) {
851+
EmittedName = true;
852+
EndStrs.push_front(" " + UseName);
853+
}
845854
}
846-
PrevArr = ArrSizes.at(TypeIdx).first == O_SizedArray;
847855

848856
switch (K) {
849857
case Atom::A_Ptr:
850858
getQualString(TypeIdx, Ss);
851859

852-
// We need to check and see if this level of variable
853-
// is constrained by a bounds safe interface. If it is,
854-
// then we shouldn't re-write it.
855-
AllArrays = false;
856860
EmittedBase = false;
857861
Ss << "_Ptr<";
858862
EndStrs.push_front(">");
@@ -866,38 +870,28 @@ PointerVariableConstraint::mkString(Constraints &CS,
866870
// we should substitute [K].
867871
if (emitArraySize(ConstArrs, TypeIdx, K))
868872
break;
869-
AllArrays = false;
870-
// We need to check and see if this level of variable
871-
// is constrained by a bounds safe interface. If it is,
872-
// then we shouldn't re-write it.
873873
EmittedBase = false;
874874
Ss << "_Array_ptr<";
875875
EndStrs.push_front(">");
876876
break;
877877
case Atom::A_NTArr:
878+
// If this is an NTArray.
879+
getQualString(TypeIdx, Ss);
878880
if (emitArraySize(ConstArrs, TypeIdx, K))
879881
break;
880-
AllArrays = false;
881-
// This additional check is to prevent fall-through from the array.
882-
if (K == Atom::A_NTArr) {
883-
// If this is an NTArray.
884-
getQualString(TypeIdx, Ss);
885882

886-
// We need to check and see if this level of variable
887-
// is constrained by a bounds safe interface. If it is,
888-
// then we shouldn't re-write it.
889-
EmittedBase = false;
890-
Ss << "_Nt_array_ptr<";
891-
EndStrs.push_front(">");
892-
break;
893-
}
894-
LLVM_FALLTHROUGH;
883+
EmittedBase = false;
884+
Ss << "_Nt_array_ptr<";
885+
EndStrs.push_front(">");
886+
break;
895887
// If there is no array in the original program, then we fall through to
896888
// the case where we write a pointer value.
897889
case Atom::A_Wild:
898890
if (emitArraySize(ConstArrs, TypeIdx, K))
899891
break;
900-
AllArrays = false;
892+
// FIXME: This code emits wild pointer levels with the outermost on the
893+
// left. The outermost should be on the right
894+
// (https://github.com/correctcomputation/checkedc-clang/issues/161).
901895
if (FV != nullptr) {
902896
FptrInner << "*";
903897
getQualString(TypeIdx, FptrInner);
@@ -917,35 +911,19 @@ PointerVariableConstraint::mkString(Constraints &CS,
917911
llvm_unreachable("impossible");
918912
break;
919913
}
920-
TypeIdx++;
921-
}
922-
923-
// If the previous variable was an array or
924-
// if we are leaving an array run, we need to emit the
925-
// annotation for a stack-array
926-
if (PrevArr && !ConstArrs.empty())
927-
addArrayAnnotations(ConstArrs, EndStrs);
928-
929-
// If the whole type is an array so far, and we haven't emitted
930-
// a name yet, then emit the name so that it appears before
931-
// the the stack array type.
932-
if (PrevArr && !EmittedName && AllArrays) {
933-
EmittedName = true;
934-
EndStrs.push_front(" " + UseName);
935914
}
936915

937916
if (!EmittedBase) {
938917
// If we have a FV pointer, then our "base" type is a function pointer type.
939918
if (FV) {
940-
if (Ss.str().empty()) {
941-
if (!EmittedName) {
942-
FptrInner << UseName;
943-
EmittedName = true;
944-
}
945-
for (std::string Str : EndStrs)
946-
FptrInner << Str;
947-
EndStrs.clear();
919+
if (!EmittedName) {
920+
FptrInner << UseName;
921+
EmittedName = true;
948922
}
923+
std::deque<std::string> FptrEndStrs;
924+
addArrayAnnotations(ConstArrs, FptrEndStrs);
925+
for (std::string Str : FptrEndStrs)
926+
FptrInner << Str;
949927
bool EmitFVName = !FptrInner.str().empty();
950928
if (EmitFVName)
951929
Ss << FV->mkString(CS, MKSTRING_OPTS(UseName = FptrInner.str(),
@@ -963,27 +941,20 @@ PointerVariableConstraint::mkString(Constraints &CS,
963941
}
964942
}
965943

966-
// Add closing elements to type
967-
for (std::string Str : EndStrs) {
968-
Ss << Str;
969-
}
970-
971944
// No space after itype.
972-
if (!EmittedName && !UseName.empty()) {
945+
if (!EmittedName) {
973946
if (!StringRef(Ss.str()).endswith("*"))
974947
Ss << " ";
975948
Ss << UseName;
976949
}
977950

978-
// Final array dropping.
979-
if (!ConstArrs.empty()) {
980-
std::deque<std::string> ArrStrs;
981-
addArrayAnnotations(ConstArrs, ArrStrs);
982-
for (std::string Str : ArrStrs)
983-
Ss << Str;
951+
// Add closing elements to type
952+
addArrayAnnotations(ConstArrs, EndStrs);
953+
for (std::string Str : EndStrs) {
954+
Ss << Str;
984955
}
985956

986-
if (IsReturn && !ForItype)
957+
if (IsReturn && !ForItype && !StringRef(Ss.str()).endswith("*"))
987958
Ss << " ";
988959

989960
return Ss.str();

clang/lib/3C/RewriteUtils.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -636,11 +636,10 @@ void RewriteConsumer::emitRootCauseDiagnostics(ASTContext &Context) {
636636
if (!File.getError()) {
637637
SourceLocation SL =
638638
SM.translateFileLineCol(*File, PSL.getLineNo(), PSL.getColSNo());
639-
// Limit emitted root causes to those that effect more than one pointer
640-
// or are in the main file of the TU. Alternatively, don't filter causes
641-
// if -warn-all-root-cause is passed.
639+
// Limit emitted root causes to those that effect at least one pointer.
640+
// Alternatively, don't filter causes if -warn-all-root-cause is passed.
642641
int PtrCount = I.getNumPtrsAffected(WReason.first);
643-
if (_3COpts.WarnAllRootCause || SM.isInMainFile(SL) || PtrCount > 1) {
642+
if (_3COpts.WarnAllRootCause || PtrCount > 0) {
644643
// SL is invalid when the File is not in the current translation unit.
645644
if (SL.isValid()) {
646645
EmittedDiagnostics.insert(PSL);

clang/test/3C/b_tests/b1_allsafe.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ int *foo() {
3131
//CHECK: _Ptr<int> y = &sy;
3232
int *z = sus(x, y);
3333
//CHECK_NOALL: _Ptr<int> z = sus(x, y);
34-
//CHECK_ALL: _Ptr<int> z = sus(_Assume_bounds_cast<_Array_ptr<int>>(x, byte_count(0)), y);
34+
//CHECK_ALL: _Ptr<int> z = sus(_Assume_bounds_cast<_Array_ptr<int>>(x, bounds(unknown)), y);
3535
*z = *z + 1;
3636
return z;
3737
}
@@ -47,6 +47,6 @@ int *bar() {
4747
//CHECK: _Ptr<int> y = &sy;
4848
int *z = (sus(x, y));
4949
//CHECK_NOALL: _Ptr<int> z = (sus(x, y));
50-
//CHECK_ALL: _Ptr<int> z = (sus(_Assume_bounds_cast<_Array_ptr<int>>(x, byte_count(0)), y));
50+
//CHECK_ALL: _Ptr<int> z = (sus(_Assume_bounds_cast<_Array_ptr<int>>(x, bounds(unknown)), y));
5151
return z;
5252
}

clang/test/3C/b_tests/b23_explicitunsafecast.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ int *foo() {
3030
//CHECK: _Ptr<int> y = &sy;
3131
int *z = (int *)sus(x, y);
3232
//CHECK_NOALL: _Ptr<int> z = (_Ptr<int>)sus(x, y);
33-
//CHECK_ALL: _Ptr<int> z = (_Ptr<int>)sus(_Assume_bounds_cast<_Array_ptr<int>>(x, byte_count(0)), y);
33+
//CHECK_ALL: _Ptr<int> z = (_Ptr<int>)sus(_Assume_bounds_cast<_Array_ptr<int>>(x, bounds(unknown)), y);
3434
*z = *z + 1;
3535
return z;
3636
}
@@ -45,6 +45,6 @@ char *bar() {
4545
//CHECK: _Ptr<int> y = &sy;
4646
char *z = (char *)(sus(x, y));
4747
//CHECK_NOALL: char *z = (char *)(((int *)sus(x, y)));
48-
//CHECK_ALL: char *z = (char *)(((int *)sus(_Assume_bounds_cast<_Array_ptr<int>>(x, byte_count(0)), y)));
48+
//CHECK_ALL: char *z = (char *)(((int *)sus(_Assume_bounds_cast<_Array_ptr<int>>(x, bounds(unknown)), y)));
4949
return z;
5050
}

clang/test/3C/b_tests/b23_retswitchexplicit.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ char *foo() {
3030
//CHECK: _Ptr<int> y = &sy;
3131
char *z = (int *)sus(x, y);
3232
//CHECK_NOALL: char *z = (int *)sus(x, y);
33-
//CHECK_ALL: char *z = (int *)sus(_Assume_bounds_cast<_Array_ptr<int>>(x, byte_count(0)), y);
33+
//CHECK_ALL: char *z = (int *)sus(_Assume_bounds_cast<_Array_ptr<int>>(x, bounds(unknown)), y);
3434
*z = *z + 1;
3535
return z;
3636
}
@@ -45,6 +45,6 @@ int *bar() {
4545
//CHECK: _Ptr<int> y = &sy;
4646
int *z = (char *)(sus(x, y));
4747
//CHECK_NOALL: int *z = (char *)(sus(x, y));
48-
//CHECK_ALL: int *z = (char *)(sus(_Assume_bounds_cast<_Array_ptr<int>>(x, byte_count(0)), y));
48+
//CHECK_ALL: int *z = (char *)(sus(_Assume_bounds_cast<_Array_ptr<int>>(x, bounds(unknown)), y));
4949
return z;
5050
}

clang/test/3C/b_tests/b24_implicitunsafecast.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ int *foo() {
3030
//CHECK: _Ptr<int> y = &sy;
3131
int *z = (int *)sus(x, y);
3232
//CHECK_NOALL: _Ptr<int> z = (_Ptr<int>)sus(x, y);
33-
//CHECK_ALL: _Ptr<int> z = (_Ptr<int>)sus(_Assume_bounds_cast<_Array_ptr<int>>(x, byte_count(0)), y);
33+
//CHECK_ALL: _Ptr<int> z = (_Ptr<int>)sus(_Assume_bounds_cast<_Array_ptr<int>>(x, bounds(unknown)), y);
3434
*z = *z + 1;
3535
return z;
3636
}
@@ -45,6 +45,6 @@ char *bar() {
4545
//CHECK: _Ptr<int> y = &sy;
4646
char *z = sus(x, y);
4747
//CHECK_NOALL: char *z = ((int *)sus(x, y));
48-
//CHECK_ALL: char *z = ((int *)sus(_Assume_bounds_cast<_Array_ptr<int>>(x, byte_count(0)), y));
48+
//CHECK_ALL: char *z = ((int *)sus(_Assume_bounds_cast<_Array_ptr<int>>(x, bounds(unknown)), y));
4949
return z;
5050
}

clang/test/3C/b_tests/b24_retswitchimplicit.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ char *foo() {
3030
//CHECK: _Ptr<int> y = &sy;
3131
char *z = (int *)sus(x, y);
3232
//CHECK_NOALL: char *z = (int *)sus(x, y);
33-
//CHECK_ALL: char *z = (int *)sus(_Assume_bounds_cast<_Array_ptr<int>>(x, byte_count(0)), y);
33+
//CHECK_ALL: char *z = (int *)sus(_Assume_bounds_cast<_Array_ptr<int>>(x, bounds(unknown)), y);
3434
*z = *z + 1;
3535
return z;
3636
}
@@ -45,6 +45,6 @@ int *bar() {
4545
//CHECK: _Ptr<int> y = &sy;
4646
int *z = sus(x, y);
4747
//CHECK_NOALL: int *z = ((char *)sus(x, y));
48-
//CHECK_ALL: int *z = ((char *)sus(_Assume_bounds_cast<_Array_ptr<int>>(x, byte_count(0)), y));
48+
//CHECK_ALL: int *z = ((char *)sus(_Assume_bounds_cast<_Array_ptr<int>>(x, bounds(unknown)), y));
4949
return z;
5050
}

0 commit comments

Comments
 (0)