Skip to content

Commit 157e2cd

Browse files
Fix the root-cause tests. (#613)
* Re-enable root-cause-related tests with minor changes. - Update the expected warnings. - Add a test of a global function with no definition to go along with the existing test of a global variable, so we can test that the new equateWithItype code gets the correct PSL even if the AtomSourceMap is turned off. - Add a test of the root-cause warning for the internal constraint of a generic function (a feature added in #593 while the test was disabled). * Only count atoms in writable files when computing root cause stats * Make equateWithItype take a PSL for constraints to wild. Change the "unwritable code" case to actually pass a PSL. The "external variable or function" case doesn't yet. Also, make PointerVariableConstraint::equateWithItype attach ReasonUnchangeable to the wildness constraints it generates. Apparently this case affects unwritable global variables and I missed it in #593. * Improve the reliability of the AtomSourceMap fallback. - We shouldn't exclude unwritable elements because they may well be the root cause of wildness of pointers we care about. This decision shouldn't be confused with excluding unwritable pointers from the count of affected pointers, which we definitely _do_ want. - Prioritize variable definitions over references. * Improve the comment about the `&i` root-cause warning. Co-authored-by: John Kastner <[email protected]>
1 parent a929d23 commit 157e2cd

File tree

6 files changed

+68
-44
lines changed

6 files changed

+68
-44
lines changed

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

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,8 @@ class ConstraintVariable {
179179
// passing a reason for the "root cause of wildness" as ReasonUnchangeable.
180180
// Otherwise ReasonUnchangeable should be set to the empty string.
181181
virtual void equateWithItype(ProgramInfo &CS,
182-
const std::string &ReasonUnchangeable) = 0;
182+
const std::string &ReasonUnchangeable,
183+
PersistentSourceLoc *PSL) = 0;
183184

184185
virtual ConstraintVariable *getCopy(Constraints &CS) = 0;
185186

@@ -485,8 +486,8 @@ class PointerVariableConstraint : public ConstraintVariable {
485486

486487
~PointerVariableConstraint() override{};
487488

488-
void equateWithItype(ProgramInfo &CS,
489-
const std::string &ReasonUnchangeable) override;
489+
void equateWithItype(ProgramInfo &CS, const std::string &ReasonUnchangeable,
490+
PersistentSourceLoc *PSL) override;
490491
};
491492

492493
typedef PointerVariableConstraint PVConstraint;
@@ -537,8 +538,8 @@ class FVComponentVariable {
537538
PVConstraint *getInternal() const { return InternalConstraint; }
538539
PVConstraint *getExternal() const { return ExternalConstraint; }
539540

540-
void equateWithItype(ProgramInfo &CS,
541-
const std::string &ReasonUnchangeable) const;
541+
void equateWithItype(ProgramInfo &CS, const std::string &ReasonUnchangeable,
542+
PersistentSourceLoc *PSL) const;
542543

543544
bool solutionEqualTo(Constraints &CS, const FVComponentVariable *CV,
544545
bool ComparePtyp) const;
@@ -660,8 +661,8 @@ class FunctionVariableConstraint : public ConstraintVariable {
660661
bool isSolutionChecked(const EnvironmentMap &E) const override;
661662
bool isSolutionFullyChecked(const EnvironmentMap &E) const override;
662663

663-
void equateWithItype(ProgramInfo &CS,
664-
const std::string &ReasonUnchangeable) override;
664+
void equateWithItype(ProgramInfo &CS, const std::string &ReasonUnchangeable,
665+
PersistentSourceLoc *PSL) override;
665666

666667
~FunctionVariableConstraint() override {}
667668
};

clang/lib/3C/ConstraintVariables.cpp

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1955,18 +1955,22 @@ Atom *PointerVariableConstraint::getAtom(unsigned AtomIdx, Constraints &CS) {
19551955
}
19561956

19571957
void PointerVariableConstraint::equateWithItype(
1958-
ProgramInfo &I, const std::string &ReasonUnchangeable) {
1958+
ProgramInfo &I, const std::string &ReasonUnchangeable,
1959+
PersistentSourceLoc *PSL) {
19591960
Constraints &CS = I.getConstraints();
19601961
assert(SrcVars.size() == Vars.size());
19611962
for (unsigned VarIdx = 0; VarIdx < Vars.size(); VarIdx++) {
19621963
ConstAtom *CA = SrcVars[VarIdx];
19631964
if (isa<WildAtom>(CA))
1964-
CS.addConstraint(CS.createGeq(Vars[VarIdx], CA, true));
1965+
CS.addConstraint(CS.createGeq(
1966+
Vars[VarIdx], CA,
1967+
ReasonUnchangeable.empty() ? DEFAULT_REASON : ReasonUnchangeable, PSL,
1968+
true));
19651969
else
19661970
Vars[VarIdx] = SrcVars[VarIdx];
19671971
}
19681972
if (FV) {
1969-
FV->equateWithItype(I, ReasonUnchangeable);
1973+
FV->equateWithItype(I, ReasonUnchangeable, PSL);
19701974
}
19711975
}
19721976

@@ -2007,10 +2011,11 @@ bool FunctionVariableConstraint::isOriginallyChecked() const {
20072011
}
20082012

20092013
void FunctionVariableConstraint::equateWithItype(
2010-
ProgramInfo &I, const std::string &ReasonUnchangeable) {
2011-
ReturnVar.equateWithItype(I, ReasonUnchangeable);
2014+
ProgramInfo &I, const std::string &ReasonUnchangeable,
2015+
PersistentSourceLoc *PSL) {
2016+
ReturnVar.equateWithItype(I, ReasonUnchangeable, PSL);
20122017
for (auto Param : ParamVars)
2013-
Param.equateWithItype(I, ReasonUnchangeable);
2018+
Param.equateWithItype(I, ReasonUnchangeable, PSL);
20142019
}
20152020

20162021
void FVComponentVariable::mergeDeclaration(FVComponentVariable *From,
@@ -2124,14 +2129,12 @@ FVComponentVariable::FVComponentVariable(const QualType &QT,
21242129
}
21252130
}
21262131

2127-
void FVComponentVariable::equateWithItype(
2128-
ProgramInfo &I, const std::string &ReasonUnchangeable) const {
2132+
void FVComponentVariable::equateWithItype(ProgramInfo &I,
2133+
const std::string &ReasonUnchangeable,
2134+
PersistentSourceLoc *PSL) const {
21292135
Constraints &CS = I.getConstraints();
21302136
const std::string ReasonUnchangeable2 =
21312137
(ReasonUnchangeable.empty() && ExternalConstraint->getIsGeneric())
2132-
// TODO: Add a test for this root-cause message somewhere once
2133-
// diagnostic verification is re-enabled
2134-
// (https://github.com/correctcomputation/checkedc-clang/issues/503).
21352138
? "Internal constraint for generic function declaration, "
21362139
"for which 3C currently does not support re-solving."
21372140
: ReasonUnchangeable;
@@ -2145,11 +2148,11 @@ void FVComponentVariable::equateWithItype(
21452148
// to fully checked.
21462149
bool MustConstrainInternalType = !ReasonUnchangeable2.empty();
21472150
if (HasItype && (MustConstrainInternalType || HasBounds)) {
2148-
ExternalConstraint->equateWithItype(I, ReasonUnchangeable2);
2151+
ExternalConstraint->equateWithItype(I, ReasonUnchangeable2, PSL);
21492152
if (ExternalConstraint != InternalConstraint)
21502153
linkInternalExternal(I, false);
21512154
if (MustConstrainInternalType)
2152-
InternalConstraint->constrainToWild(CS, ReasonUnchangeable2);
2155+
InternalConstraint->constrainToWild(CS, ReasonUnchangeable2, PSL);
21532156
}
21542157
}
21552158

clang/lib/3C/ProgramInfo.cpp

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,7 @@ bool ProgramInfo::link() {
402402
"External global variable " + VarName + " has no definition";
403403
const std::set<PVConstraint *> &C = GlobalVariableSymbols[VarName];
404404
for (const auto &Var : C) {
405+
// TODO: Is there an easy way to get a PSL to attach to the constraint?
405406
Var->constrainToWild(CS, Rsn);
406407
}
407408
}
@@ -423,7 +424,9 @@ bool ProgramInfo::link() {
423424

424425
// Handle the cases where itype parameters should not be treated as their
425426
// unchecked type.
426-
G->equateWithItype(*this, Rsn);
427+
// TODO: Ditto re getting a PSL (in the case in which Rsn is non-empty and
428+
// it is actually used).
429+
G->equateWithItype(*this, Rsn, nullptr);
427430

428431
// If we've seen this symbol, but never seen a body for it, constrain
429432
// everything about it.
@@ -464,7 +467,8 @@ bool ProgramInfo::link() {
464467
"return of static function " +
465468
FuncName + " in " + FileName);
466469

467-
G->equateWithItype(*this, Rsn);
470+
// TODO: Ditto re getting a PSL
471+
G->equateWithItype(*this, Rsn, nullptr);
468472

469473
if (!G->hasBody()) {
470474

@@ -734,7 +738,7 @@ void ProgramInfo::addVariable(clang::DeclaratorDecl *D,
734738

735739
assert("We shouldn't be adding a null CV to Variables map." && NewCV);
736740
if (!canWrite(PLoc.getFileName())) {
737-
NewCV->equateWithItype(*this, "Declaration in non-writable file");
741+
NewCV->equateWithItype(*this, "Declaration in non-writable file", &PLoc);
738742
NewCV->constrainToWild(CS, "Declaration in non-writable file", &PLoc);
739743
}
740744
constrainWildIfMacro(NewCV, D->getLocation());
@@ -1015,7 +1019,9 @@ bool ProgramInfo::computeInterimConstraintState(
10151019
auto *SearchVA = dyn_cast<VarAtom>(SearchAtom);
10161020
if (SearchVA && AllValidVars.find(SearchVA) != AllValidVars.end()) {
10171021
CState.RCMap[SearchVA->getLoc()].insert(VA->getLoc());
1018-
TmpCGrp.insert(SearchVA->getLoc());
1022+
1023+
if (ValidVarsKey.find(SearchVA->getLoc()) != ValidVarsKey.end())
1024+
TmpCGrp.insert(SearchVA->getLoc());
10191025
if (DirectWildVarAtoms.find(SearchVA) == DirectWildVarAtoms.end()) {
10201026
OnlyIndirect.insert(SearchVA->getLoc());
10211027
}
@@ -1038,6 +1044,12 @@ bool ProgramInfo::computeInterimConstraintState(
10381044
findIntersection(CState.TotalNonDirectWildAtoms, ValidVarsKey,
10391045
CState.InSrcNonDirectWildAtoms);
10401046

1047+
// The ConstraintVariable for a variable normally appears in Variables for the
1048+
// definition, but it may also be reused directly in ExprConstraintVars for a
1049+
// reference to that variable. We want to give priority to the PSL of the
1050+
// definition, not the reference. We currently achieve this by processing
1051+
// Variables before ExprConstraintVars and making insertIntoPtrSourceMap not
1052+
// overwrite a PSL already recorded for a given atom.
10411053
for (const auto &I : Variables)
10421054
insertIntoPtrSourceMap(&(I.first), I.second);
10431055
for (const auto &I : ExprConstraintVars) {
@@ -1070,13 +1082,13 @@ void ProgramInfo::insertIntoPtrSourceMap(const PersistentSourceLoc *PSL,
10701082
std::string FilePath = PSL->getFileName();
10711083
if (canWrite(FilePath))
10721084
CState.ValidSourceFiles.insert(FilePath);
1073-
else
1074-
return;
10751085

10761086
if (auto *PV = dyn_cast<PVConstraint>(CV)) {
10771087
for (auto *A : PV->getCvars())
10781088
if (auto *VA = dyn_cast<VarAtom>(A))
1079-
CState.AtomSourceMap[VA->getLoc()] = PSL;
1089+
// Don't overwrite a PSL already recorded for a given atom: see the
1090+
// comment in computeInterimConstraintState.
1091+
CState.AtomSourceMap.insert(std::make_pair(VA->getLoc(), PSL));
10801092
// If the PVConstraint is a function pointer, create mappings for parameter
10811093
// and return variables.
10821094
if (auto *FV = PV->getFV()) {

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

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,7 @@
1010
// not allow canwrite_constraints.h to change, and the internal types of q and
1111
// the return should remain wild.
1212
//
13-
// TODO: Fix the discrepancies in warnings that were introduced while the
14-
// diagnostic verifier was disabled
15-
// (https://github.com/correctcomputation/checkedc-clang/issues/609)
16-
// and then re-enable diagnostic verification here.
17-
//
18-
// RUN: cd %S && 3c -alltypes -addcr -output-dir=%t.checked/base_subdir -warn-all-root-cause %s --
13+
// RUN: cd %S && 3c -alltypes -addcr -output-dir=%t.checked/base_subdir -warn-all-root-cause %s -- -Xclang -verify
1914
// RUN: FileCheck -match-full-lines -check-prefixes=CHECK_LOWER --input-file %t.checked/base_subdir/canwrite_constraints.c %s
2015
// RUN: test ! -f %t.checked/canwrite_constraints.checked.h
2116

clang/test/3C/canwrite_constraints.h

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,12 @@ int *foo_var = ((void *)0);
1717
// Make sure we don't allow the types of casts in non-writable files to be
1818
// changed. This problem was seen with the inline definition of `atol(p)` as
1919
// `strtol(p, (char **) NULL, 10)` in the system headers.
20+
21+
// Now that itypes can be re-solved, an itype in a non-writable file generates a
22+
// root cause warning just like a fully unchecked type.
23+
// expected-warning@+1 {{Declaration in non-writable file}}
2024
void strtol_like(int *p : itype(_Ptr<int>));
25+
2126
void atol_like() {
2227
// expected-warning@+1 {{Expression in non-writable file}}
2328
strtol_like((int *)0);
@@ -34,11 +39,14 @@ inline void no_op() {}
3439
// expected-warning@+1 {{Declaration in non-writable file}}
3540
typedef int *intptr;
3641
// CHECK_HIGHER: typedef _Ptr<int> intptr;
42+
3743
// Test the unwritable cast internal warning
3844
// (https://github.com/correctcomputation/checkedc-clang/issues/454) using the
3945
// known bug with itypes and function pointers
4046
// (https://github.com/correctcomputation/checkedc-clang/issues/423) as an
4147
// example.
48+
49+
// expected-warning@+1 {{Declaration in non-writable file}}
4250
void unwritable_cast(void((*g)(int *q)) : itype(_Ptr<void(_Ptr<int>)>)) {
4351
// expected-warning@+1 {{Declaration in non-writable file}}
4452
int *p = 0;
@@ -50,20 +58,24 @@ void unwritable_cast(void((*g)(int *q)) : itype(_Ptr<void(_Ptr<int>)>)) {
5058

5159
// Make sure that FVComponentVariable::equateWithItype prevents both of these
5260
// 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/609).
61+
62+
// expected-warning@+1 {{Declaration in non-writable file}}
5763
void unwritable_func_with_itype(int *p : itype(_Array_ptr<int>)) {}
5864

65+
// expected-warning@+1 {{Declaration in non-writable file}}
5966
void unwritable_func_with_itype_and_bounds(int *p
6067
: itype(_Array_ptr<int>) count(12)) {
6168
}
6269

6370
// Test for https://github.com/correctcomputation/checkedc-clang/issues/580
71+
// expected-warning@+1 {{Declaration in non-writable file}}
6472
_Itype_for_any(T) void my_generic_function(void *p : itype(_Ptr<T>));
6573

6674
void unwritable_type_argument() {
6775
int i;
76+
// This warning relates to the atom representing the temporary pointer of
77+
// `&i`. https://github.com/correctcomputation/checkedc-clang/issues/618 would
78+
// make 3C smarter to avoid the need to constrain the temporary pointer.
79+
// expected-warning@+1 {{Expression in non-writable file}}
6880
my_generic_function(&i);
6981
}

clang/test/3C/root_cause.c

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,3 @@
1-
// TODO: Fix the failures in this test that were introduced while the diagnostic
2-
// verifier was disabled
3-
// (https://github.com/correctcomputation/checkedc-clang/issues/609).
4-
// XFAIL: *
5-
61
// RUN: 3c -base-dir=%S -alltypes -warn-root-cause %s -- -Xclang -verify -Wno-everything
72

83
// This test is unusual in that it checks for the errors in the code
@@ -41,8 +36,11 @@ void test1() {
4136
int *d = malloc(1); // expected-warning {{Unsafe call to allocator function}}
4237
}
4338

44-
extern int *
45-
glob; // expected-warning {{External global variable glob has no definition}}
39+
// expected-warning@+1 {{External global variable glob has no definition}}
40+
extern int *glob;
41+
42+
// expected-warning@+1 {{Unchecked pointer in parameter or return of external function glob_f}}
43+
int *glob_f(void);
4644

4745
void (*f)(void *); // expected-warning {{Default void* type}}
4846

@@ -51,3 +49,6 @@ typedef struct {
5149
float f;
5250
} A, *PA;
5351
// expected-warning@-1 {{Unable to rewrite a typedef with multiple names}}
52+
53+
// expected-warning@+1 {{Internal constraint for generic function declaration, for which 3C currently does not support re-solving.}}
54+
_Itype_for_any(T) void remember(void *p : itype(_Ptr<T>)) {}

0 commit comments

Comments
 (0)