Skip to content

Commit 9415bf4

Browse files
Fix canwrite_constraints test and constrain itypes in unwritable files. (#593)
* Re-enable the canwrite_constraints test except for diagnostic verification. Reformat a CHECK comment to match the code reformatting done in 2a6a28e. (This wasn't caught at the time because the test was XFAILed.) After this fix, the test passes except for #581. Also remove some obsolete TODO comments: there are no known problems with these tests on Windows. * Don't allow itypes in unwritable files to change. Also take the opportunity to improve the documentation of equateWithItype based on what I learned. Some things are probably still wrong with the code and/or the documentation, but I think this is better than the status quo. Fixes #581. * Add variable to make equateWithItype conditionals easier to understand.
1 parent 8401770 commit 9415bf4

File tree

6 files changed

+87
-46
lines changed

6 files changed

+87
-46
lines changed

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

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -162,12 +162,24 @@ class ConstraintVariable {
162162
void setValidDecl() { IsForDecl = true; }
163163
bool isForValidDecl() const { return IsForDecl; }
164164

165-
// Copies ConstAtoms from SrcVars vector into the main VarAtoms vector. This
166-
// causes the solved type for the variable to be the same as the the type in
167-
// source. This is currently called on function parameters with itypes when
168-
// we don't want to allow the itype to solve to a fully checked type or an
169-
// itype with a different pointer type.
170-
virtual void equateWithItype(ProgramInfo &CS, bool ForceEquate) = 0;
165+
// By default, 3C allows itypes to be re-solved arbitrarily. But in several
166+
// cases, we need to restrict itype re-solving; this function applies those
167+
// restrictions. (It isn't needed for fully checked types because 3C doesn't
168+
// allow checked types to be re-solved yet.)
169+
//
170+
// In some cases, we don't want the checked portion of the type to change, but
171+
// the itype can still become a fully checked type; we achieve that by copying
172+
// ConstAtoms from SrcVars vector into the main VarAtoms vector, which forces
173+
// the solved checked type for the variable to be the same as it was in the
174+
// source. In other cases, we don't want the itype to change at all; to
175+
// achieve that, we additionally constrain the internal variables to not
176+
// change.
177+
//
178+
// Some cases in which the itype must not change at all are indicated by
179+
// passing a reason for the "root cause of wildness" as ReasonUnchangeable.
180+
// Otherwise ReasonUnchangeable should be set to the empty string.
181+
virtual void equateWithItype(ProgramInfo &CS,
182+
const std::string &ReasonUnchangeable) = 0;
171183

172184
virtual ConstraintVariable *getCopy(Constraints &CS) = 0;
173185

@@ -473,7 +485,8 @@ class PointerVariableConstraint : public ConstraintVariable {
473485

474486
~PointerVariableConstraint() override{};
475487

476-
void equateWithItype(ProgramInfo &CS, bool ForceEquate) override;
488+
void equateWithItype(ProgramInfo &CS,
489+
const std::string &ReasonUnchangeable) override;
477490
};
478491

479492
typedef PointerVariableConstraint PVConstraint;
@@ -524,7 +537,8 @@ class FVComponentVariable {
524537
PVConstraint *getInternal() const { return InternalConstraint; }
525538
PVConstraint *getExternal() const { return ExternalConstraint; }
526539

527-
void equateWithItype(ProgramInfo &CS, bool ForceEquate) const;
540+
void equateWithItype(ProgramInfo &CS,
541+
const std::string &ReasonUnchangeable) const;
528542

529543
bool solutionEqualTo(Constraints &CS, const FVComponentVariable *CV,
530544
bool ComparePtyp) const;
@@ -646,7 +660,8 @@ class FunctionVariableConstraint : public ConstraintVariable {
646660
bool isSolutionChecked(const EnvironmentMap &E) const override;
647661
bool isSolutionFullyChecked(const EnvironmentMap &E) const override;
648662

649-
void equateWithItype(ProgramInfo &CS, bool ForceEquate) override;
663+
void equateWithItype(ProgramInfo &CS,
664+
const std::string &ReasonUnchangeable) override;
650665

651666
~FunctionVariableConstraint() override {}
652667
};

clang/lib/3C/ConstraintVariables.cpp

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1954,8 +1954,8 @@ Atom *PointerVariableConstraint::getAtom(unsigned AtomIdx, Constraints &CS) {
19541954
return nullptr;
19551955
}
19561956

1957-
void
1958-
PointerVariableConstraint::equateWithItype(ProgramInfo &I, bool ForceEquate) {
1957+
void PointerVariableConstraint::equateWithItype(
1958+
ProgramInfo &I, const std::string &ReasonUnchangeable) {
19591959
Constraints &CS = I.getConstraints();
19601960
assert(SrcVars.size() == Vars.size());
19611961
for (unsigned VarIdx = 0; VarIdx < Vars.size(); VarIdx++) {
@@ -1966,7 +1966,7 @@ PointerVariableConstraint::equateWithItype(ProgramInfo &I, bool ForceEquate) {
19661966
Vars[VarIdx] = SrcVars[VarIdx];
19671967
}
19681968
if (FV) {
1969-
FV->equateWithItype(I, ForceEquate);
1969+
FV->equateWithItype(I, ReasonUnchangeable);
19701970
}
19711971
}
19721972

@@ -2006,11 +2006,11 @@ bool FunctionVariableConstraint::isOriginallyChecked() const {
20062006
return ReturnVar.ExternalConstraint->isOriginallyChecked();
20072007
}
20082008

2009-
void
2010-
FunctionVariableConstraint::equateWithItype(ProgramInfo &I, bool ForceEquate) {
2011-
ReturnVar.equateWithItype(I, ForceEquate);
2009+
void FunctionVariableConstraint::equateWithItype(
2010+
ProgramInfo &I, const std::string &ReasonUnchangeable) {
2011+
ReturnVar.equateWithItype(I, ReasonUnchangeable);
20122012
for (auto Param : ParamVars)
2013-
Param.equateWithItype(I, ForceEquate);
2013+
Param.equateWithItype(I, ReasonUnchangeable);
20142014
}
20152015

20162016
void FVComponentVariable::mergeDeclaration(FVComponentVariable *From,
@@ -2115,18 +2115,32 @@ FVComponentVariable::FVComponentVariable(const QualType &QT,
21152115
}
21162116
}
21172117

2118-
void
2119-
FVComponentVariable::equateWithItype(ProgramInfo &I, bool ForceEquate) const {
2118+
void FVComponentVariable::equateWithItype(
2119+
ProgramInfo &I, const std::string &ReasonUnchangeable) const {
21202120
Constraints &CS = I.getConstraints();
2121-
bool IsGeneric = ExternalConstraint->getIsGeneric();
2121+
const std::string ReasonUnchangeable2 =
2122+
(ReasonUnchangeable.empty() && ExternalConstraint->getIsGeneric())
2123+
// TODO: Add a test for this root-cause message somewhere once
2124+
// diagnostic verification is re-enabled
2125+
// (https://github.com/correctcomputation/checkedc-clang/issues/503).
2126+
? "Internal constraint for generic function declaration, "
2127+
"for which 3C currently does not support re-solving."
2128+
: ReasonUnchangeable;
21222129
bool HasBounds = ExternalConstraint->srcHasBounds();
21232130
bool HasItype = ExternalConstraint->srcHasItype();
2124-
if (HasItype && (ForceEquate || IsGeneric || HasBounds)) {
2125-
ExternalConstraint->equateWithItype(I, ForceEquate);
2131+
// If the type cannot change at all (ReasonUnchangeable2 is set), then we
2132+
// constrain both the external and internal types to not change. Otherwise, if
2133+
// the variable has bounds, then we don't want the checked (external) portion
2134+
// of the type to change because that could blow away the bounds, but we still
2135+
// allow the internal type to change so that the type can change from an itype
2136+
// to fully checked.
2137+
bool MustConstrainInternalType = !ReasonUnchangeable2.empty();
2138+
if (HasItype && (MustConstrainInternalType || HasBounds)) {
2139+
ExternalConstraint->equateWithItype(I, ReasonUnchangeable2);
21262140
if (ExternalConstraint != InternalConstraint)
21272141
linkInternalExternal(I, false);
2128-
if (IsGeneric)
2129-
InternalConstraint->constrainToWild(CS, "Internal constraint for generic function.");
2142+
if (MustConstrainInternalType)
2143+
InternalConstraint->constrainToWild(CS, ReasonUnchangeable2);
21302144
}
21312145
}
21322146

clang/lib/3C/ProgramInfo.cpp

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -412,21 +412,23 @@ bool ProgramInfo::link() {
412412
std::string FuncName = U.first;
413413
FVConstraint *G = U.second;
414414

415+
// If there was a checked type on a variable in the input program, it
416+
// should stay that way. Otherwise, we shouldn't be adding a checked type
417+
// to an extern function.
418+
std::string Rsn = (G->hasBody() ? ""
419+
: "Unchecked pointer in parameter or "
420+
"return of external function " +
421+
FuncName);
422+
415423
// Handle the cases where itype parameters should not be treated as their
416424
// unchecked type.
417-
G->equateWithItype(*this, !G->hasBody());
425+
G->equateWithItype(*this, Rsn);
418426

419427
// If we've seen this symbol, but never seen a body for it, constrain
420428
// everything about it.
421429
// Some global symbols we don't need to constrain to wild, like
422430
// malloc and free. Check those here and skip if we find them.
423431
if (!G->hasBody()) {
424-
// If there was a checked type on a variable in the input program, it
425-
// should stay that way. Otherwise, we shouldn't be adding a checked type
426-
// to an extern function.
427-
std::string Rsn =
428-
"Unchecked pointer in parameter or return of external function " +
429-
FuncName;
430432
const FVComponentVariable *Ret = G->getCombineReturn();
431433
Ret->getInternal()->constrainToWild(CS, Rsn);
432434
if (!Ret->getExternal()->srcHasItype() &&
@@ -456,13 +458,15 @@ bool ProgramInfo::link() {
456458
std::string FuncName = V.first;
457459
FVConstraint *G = V.second;
458460

459-
G->equateWithItype(*this, !G->hasBody());
461+
std::string Rsn = (G->hasBody() ? ""
462+
: "Unchecked pointer in parameter or "
463+
"return of static function " +
464+
FuncName + " in " + FileName);
465+
466+
G->equateWithItype(*this, Rsn);
460467

461468
if (!G->hasBody()) {
462469

463-
std::string Rsn =
464-
"Unchecked pointer in parameter or return of static function " +
465-
FuncName + " in " + FileName;
466470
if (!G->getExternalReturn()->getIsGeneric())
467471
G->getExternalReturn()->constrainToWild(CS, Rsn);
468472
for (unsigned I = 0; I < G->numParams(); I++)
@@ -729,7 +733,7 @@ void ProgramInfo::addVariable(clang::DeclaratorDecl *D,
729733

730734
assert("We shouldn't be adding a null CV to Variables map." && NewCV);
731735
if (!canWrite(PLoc.getFileName())) {
732-
NewCV->equateWithItype(*this, true);
736+
NewCV->equateWithItype(*this, "Declaration in non-writable file");
733737
NewCV->constrainToWild(CS, "Declaration in non-writable file", &PLoc);
734738
}
735739
constrainWildIfMacro(NewCV, D->getLocation());
Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,27 @@
1-
// TODO: refactor this test
2-
// https://github.com/correctcomputation/checkedc-clang/issues/503
3-
// XFAIL: *
4-
51
// Test that non-canWrite files are constrained not to change so that the final
62
// annotations of other files are consistent with the original annotations of
73
// the non-canWrite files. The currently supported cases are function and
84
// variable declarations and checked regions.
95
// (https://github.com/correctcomputation/checkedc-clang/issues/387)
106

11-
// TODO: Windows compatibility?
12-
137
// RUN: rm -rf %t*
148

159
// "Lower" case: -base-dir should default to the working directory, so we should
1610
// not allow canwrite_constraints.h to change, and the internal types of q and
1711
// the return should remain wild.
1812
//
19-
// RUN: cd %S && 3c -addcr -output-dir=%t.checked/base_subdir -warn-all-root-cause -verify %s --
13+
// The root cause warning verification part of this test is currently disabled
14+
// because of https://github.com/correctcomputation/checkedc-clang/issues/503;
15+
// the rest of the test still works. TODO: Re-enable warning verification.
16+
//
17+
// RUN: cd %S && 3c -alltypes -addcr -output-dir=%t.checked/base_subdir -warn-all-root-cause %s --
2018
// RUN: FileCheck -match-full-lines -check-prefixes=CHECK_LOWER --input-file %t.checked/base_subdir/canwrite_constraints.c %s
2119
// RUN: test ! -f %t.checked/canwrite_constraints.checked.h
2220

2321
// "Higher" case: When -base-dir is set to the parent directory, we can change
2422
// canwrite_constraints.h, so both q and the return should become checked.
2523
//
26-
// RUN: cd %S && 3c -addcr -base-dir=.. -output-dir=%t.checked2 %s --
24+
// RUN: cd %S && 3c -alltypes -addcr -base-dir=.. -output-dir=%t.checked2 %s --
2725
// RUN: FileCheck -match-full-lines -check-prefixes=CHECK_HIGHER --input-file %t.checked2/base_subdir/canwrite_constraints.c %s
2826
// RUN: FileCheck -match-full-lines -check-prefixes=CHECK_HIGHER --input-file %t.checked2/canwrite_constraints.h %S/../canwrite_constraints.h
2927

@@ -38,7 +36,7 @@ int *bar(int *q) {
3836

3937
int gar(intptr a) {
4038
int *b = a;
41-
//CHECK_LOWER: int* b = a;
39+
//CHECK_LOWER: int *b = a;
4240
//CHECK_HIGHER: _Ptr<int> b = a;
4341
return *b;
4442
}

clang/test/3C/base_subdir/canwrite_constraints_unimplemented.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@
77
// an error diagnostic.
88
// (https://github.com/correctcomputation/checkedc-clang/issues/387)
99

10-
// TODO: Ditto the TODO comments from canwrite_constraints.c re the RUN
11-
// commands.
1210
// RUN: cd %S && 3c -addcr -verify %s --
1311

1412
// expected-error@../base_subdir_partial_defn.h:1 {{3C internal error: 3C generated changes to this file even though it is not allowed to write to the file}}

clang/test/3C/canwrite_constraints.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,15 @@ void unwritable_cast(void((*g)(int *q)) : itype(_Ptr<void(_Ptr<int>)>)) {
4747
// expected-warning@+1 {{3C internal error: tried to insert a cast into an unwritable file}}
4848
(*g)(p);
4949
}
50+
51+
// Make sure that FVComponentVariable::equateWithItype prevents both of these
52+
// from being changed.
53+
//
54+
// TODO: Add the correct expected root cause warnings once diagnostic
55+
// verification is re-enabled
56+
// (https://github.com/correctcomputation/checkedc-clang/issues/503).
57+
void unwritable_func_with_itype(int *p : itype(_Array_ptr<int>)) {}
58+
59+
void unwritable_func_with_itype_and_bounds(int *p
60+
: itype(_Array_ptr<int>) count(12)) {
61+
}

0 commit comments

Comments
 (0)