Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci-macos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
strategy:
matrix:
build_type: [ Release ]
os: [macos-13, macos-14, macos-15]
os: [macos-latest]
compiler:
- cc: cc
cxx: c++
Expand Down
6 changes: 4 additions & 2 deletions integration_test/legacy/attr-psets.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1102,10 +1102,11 @@ void kill_materialized_temporary() {
void delete_pointee(int *p) {
int *q = p;
__lifetime_pset(q); // expected-warning {{((null), *p)}}
// expected-note@+1 {{deleted here}}
delete q; // expected-warning {{naked new-deletes disables lifetime analysis}}
__lifetime_pset(q); // expected-warning {{((invalid))}}
__lifetime_pset(p); // expected-warning {{((invalid))}}
}
} // expected-warning {{returning a dangling pointer as output value '*p'}}

int throw_local() {
int i;
Expand Down Expand Up @@ -1673,6 +1674,7 @@ struct Node {
__lifetime_pset(next_temp); // expected-warning {{(*(*this).next)}}
// expected-warning@-1 {{((global), *(*this).next)}}
// expected-warning@-2 {{((global), *(*this).next)}}
// expected-note@+1 {{deleted here}}
delete cur; // expected-warning {{naked new-deletes disables lifetime analysis}}
__lifetime_pset(next_temp); // expected-warning {{(*(*this).next)}}
// expected-warning@-1 {{((global), *(*this).next)}}
Expand All @@ -1682,7 +1684,7 @@ struct Node {
// expected-warning@-2 {{(invalid)}}
cur = next_temp;
}
}
} // expected-warning {{returning a dangling pointer as output value '*this'}}
};

namespace boundedness {
Expand Down
32 changes: 32 additions & 0 deletions integration_test/options/warn_delete.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#include "../feature/common.h"

void free(int* p)
{
delete p;
__lifetime_pset(p); // expected-warning {{pset(p) = ((invalid))}}
}

void free2(void* p)
{
delete (int*)p;
__lifetime_pset(p); // expected-warning {{pset(p) = ((invalid))}}
}

void free3(void* p)
{
delete static_cast<int*>(p);
__lifetime_pset(p); // expected-warning {{pset(p) = ((invalid))}}
}

void free4(void* p)
{
auto* t = (int*)p;
delete t;
__lifetime_pset(p); // expected-warning {{pset(p) = ((invalid))}}
}

CPPSAFE_POST("*p", ":invalid")
void free5(int* p)
{
delete p;
}
41 changes: 41 additions & 0 deletions integration_test/options/warn_delete_strict.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// ARGS: --Wlifetime-disabled

#include "../feature/common.h"

void free(int* p)
{
// expected-note@+1 {{deleted here}}
delete p; // expected-warning {{naked new-deletes disables lifetime analysis}}
__lifetime_pset(p); // expected-warning {{pset(p) = ((invalid))}}
} // expected-warning {{returning a dangling pointer as output value '*p'}}

void free2(void* p)
{
// expected-note@+1 {{deleted here}}
delete (int*)p; // expected-warning {{naked new-deletes disables lifetime analysis}}
// expected-warning@-1 {{unsafe cast disables lifetime analysis}}
__lifetime_pset(p); // expected-warning {{pset(p) = ((invalid))}}
} // expected-warning {{returning a dangling pointer as output value '*p'}}

void free3(void* p)
{
// expected-note@+1 {{deleted here}}
delete static_cast<int*>(p); // expected-warning {{naked new-deletes disables lifetime analysis}}
// expected-warning@-1 {{unsafe cast disables lifetime analysis}}
__lifetime_pset(p); // expected-warning {{pset(p) = ((invalid))}}
} // expected-warning {{returning a dangling pointer as output value '*p'}}

void free4(void* p)
{
auto* t = (int*)p;
// expected-warning@-1 {{unsafe cast disables lifetime analysis}}
// expected-note@+1 {{deleted here}}
delete t; // expected-warning {{naked new-deletes disables lifetime analysis}}
__lifetime_pset(p); // expected-warning {{pset(p) = ((invalid))}}
} // expected-warning {{returning a dangling pointer as output value '*p'}}

CPPSAFE_POST("*p", ":invalid")
void free5(int* p)
{
delete p; // expected-warning {{naked new-deletes disables lifetime analysis}}
}
1 change: 0 additions & 1 deletion integration_test/safety/contract_return_aggr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,6 @@ B createStaticB()
{
static int t = 0;
static const B b { .x = &t };
__lifetime_pmap();
return b;
}

Expand Down
10 changes: 10 additions & 0 deletions integration_test/safety/new_delete.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#include "../feature/common.h"

void foo()
{
auto* p = new int{};
auto* q = p;
delete q;
__lifetime_pset(p); // expected-warning {{((global))}}
__lifetime_pset(q); // expected-warning {{((invalid))}}
}
26 changes: 23 additions & 3 deletions lib/lifetime/LifetimePsetBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -191,10 +191,23 @@ class PSetsBuilder final : public ConstStmtVisitor<PSetsBuilder, void>, public P
for (const auto& Var : PS.vars()) {
// TODO: diagnose if we are deleting the buffer of on owner?
invalidateVar(Var, InvalidationReason::deleted(DE->getSourceRange(), CurrentBlock));

// void free(int* p)
// after the call, *p is invalid. but to avoid noisy, turn it off by default
if (Reporter.getOptions().LifetimeDisabled) {
setPSet(PSet::singleton(Var),
PSet::invalid(InvalidationReason::deleted(DE->getSourceRange(), CurrentBlock)),
DE->getSourceRange());
}
}

setPSet(getPSet(DE->getArgument()->IgnoreImplicit()),
PSet::invalid(InvalidationReason::deleted(DE->getSourceRange(), CurrentBlock)), DE->getSourceRange());
const auto* E = DE->getArgument()->IgnoreCasts();
// auto* p = new int{}; delete p;
if (E->isLValue()) {
setPSet(getPSet(E), PSet::invalid(InvalidationReason::deleted(DE->getSourceRange(), CurrentBlock)),
DE->getSourceRange());
return;
}
}
}

Expand Down Expand Up @@ -1866,7 +1879,9 @@ void PSetsBuilder::onFunctionFinish(const CFGBlock& B)
}

auto OutVarIt = PMap.find(OutVarInPostCond);
CPPSAFE_ASSERT(OutVarIt != PMap.end());
if (OutVarIt == PMap.end()) {
continue;
}

OutVarIt->second.transformVars([&](Variable V) {
if (!V.isField()) {
Expand Down Expand Up @@ -1910,6 +1925,11 @@ void PSetsBuilder::onFunctionFinish(const CFGBlock& B)
// TODO: add this&&

if (OutPSet.containsInvalid()) {
auto It = PostConditions.find(OutVar);
if (It != PostConditions.end() && It->second.containsInvalid()) {
continue;
}

Reporter.warnNullDangling(
WarnType::Dangling, Range, ValueSource::OutputParam, OutVar.getName(), !OutPSet.isInvalid());
OutPSet.explainWhyInvalid(Reporter);
Expand Down
4 changes: 0 additions & 4 deletions lib/lifetime/LifetimeTypeCategory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
#include <clang/Basic/Specifiers.h>
#include <clang/Sema/Sema.h>
#include <llvm/ADT/STLExtras.h>
#include <llvm/Support/raw_ostream.h>

#include <array>
#include <cassert>
Expand Down Expand Up @@ -521,9 +520,6 @@ static QualType getPointeeType(const CXXRecordDecl* R)
}

if (classifyTypeCategory(PointeeType) != TypeCategory::Pointer) {
// TODO: diag?
llvm::errs() << "begin() function does not return a Pointer!\n";
FoundMD->dump();
return {};
}
PointeeType = getPointeeType(PointeeType);
Expand Down