CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
697 lines
28 KiB
C++
697 lines
28 KiB
C++
// RUN: rm -rf %t
|
|
// RUN: split-file %s %t
|
|
// RUN: %clang_cc1 -fsyntax-only -flifetime-safety-inference -fexperimental-lifetime-safety-tu-analysis -Wlifetime-safety-suggestions -Wlifetime-safety -Wno-dangling -I%t -I%S -verify %t/test_source.cpp
|
|
// RUN: %clang_cc1 -fsyntax-only -std=c++23 -flifetime-safety-inference -fexperimental-lifetime-safety-tu-analysis -Wlifetime-safety-suggestions -Wlifetime-safety -Wno-dangling -I%t -I%S -verify %t/test_source.cpp
|
|
// RUN: %clang_cc1 -flifetime-safety-inference -fexperimental-lifetime-safety-tu-analysis -Wlifetime-safety-suggestions -Wlifetime-safety -Wno-dangling -I%t -I%S -fixit %t/test_source.cpp
|
|
// RUN: %clang_cc1 -fsyntax-only -flifetime-safety-inference -fexperimental-lifetime-safety-tu-analysis -Wlifetime-safety-suggestions -Wno-dangling -I%t -I%S -Werror=lifetime-safety-suggestions %t/test_source.cpp
|
|
|
|
View definition_before_header(View a);
|
|
|
|
//--- test_header.h
|
|
#ifndef TEST_HEADER_H
|
|
#define TEST_HEADER_H
|
|
|
|
struct View;
|
|
|
|
struct [[gsl::Owner]] MyObj {
|
|
int id;
|
|
MyObj(int i) : id(i) {}
|
|
MyObj() {}
|
|
~MyObj() {} // Non-trivial destructor
|
|
MyObj operator+(MyObj);
|
|
|
|
View getView() const [[clang::lifetimebound]];
|
|
};
|
|
|
|
struct [[gsl::Pointer()]] View {
|
|
View(const MyObj&); // Borrows from MyObj
|
|
View();
|
|
void use() const;
|
|
};
|
|
|
|
View definition_before_header(View a); // expected-warning {{parameter in cross-TU function should be marked [[clang::lifetimebound]]}}
|
|
|
|
View redeclared_before_header_include(View a); // expected-warning {{parameter in cross-TU function should be marked [[clang::lifetimebound]]}}
|
|
|
|
View return_view_directly(View a); // expected-warning {{parameter in cross-TU function should be marked [[clang::lifetimebound]]}}
|
|
|
|
View conditional_return_view(
|
|
View a, // expected-warning {{parameter in cross-TU function should be marked [[clang::lifetimebound]]}}
|
|
View b, // expected-warning {{parameter in cross-TU function should be marked [[clang::lifetimebound]]}}
|
|
bool c);
|
|
|
|
int* return_pointer_directly(int* a); // expected-warning {{parameter in cross-TU function should be marked [[clang::lifetimebound]]}}
|
|
|
|
MyObj* return_pointer_object(MyObj* a); // expected-warning {{parameter in cross-TU function should be marked [[clang::lifetimebound]]}}
|
|
|
|
inline View inline_header_return_view(View a) { // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}
|
|
return a; // expected-note {{param returned here}}
|
|
}
|
|
|
|
View redeclared_in_header(View a); // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}
|
|
inline View redeclared_in_header(View a) {
|
|
return a; // expected-note {{param returned here}}
|
|
}
|
|
|
|
View return_unnamed_view(View); // expected-warning {{parameter in cross-TU function should be marked [[clang::lifetimebound]]}}
|
|
MyObj& return_unnamed_ref(MyObj&, bool); // expected-warning {{parameter in cross-TU function should be marked [[clang::lifetimebound]]}}
|
|
|
|
struct ReturnThis {
|
|
const ReturnThis& get() const; // expected-warning {{implicit this in cross-TU function should be marked [[clang::lifetimebound]]}}.
|
|
};
|
|
|
|
struct ReturnThisPointer {
|
|
const ReturnThisPointer* get() const; // expected-warning {{implicit this in cross-TU function should be marked [[clang::lifetimebound]]}}.
|
|
};
|
|
|
|
|
|
#endif // TEST_HEADER_H
|
|
|
|
//--- test_redecls_header.h
|
|
|
|
View earliest_decl_in_header(View a); // expected-warning {{parameter in cross-TU function should be marked [[clang::lifetimebound]]}}
|
|
View earliest_decl_in_header(View a);
|
|
|
|
View multi_redecl_one_file(View a); // expected-warning {{parameter in cross-TU function should be marked [[clang::lifetimebound]]}}
|
|
View multi_redecl_one_file(View a);
|
|
View multi_redecl_one_file(View a);
|
|
|
|
View source_and_header(View a); // expected-warning {{parameter in cross-TU function should be marked [[clang::lifetimebound]]}}
|
|
|
|
//--- test_redecls_header_1.h
|
|
|
|
View in_two_headers(View a); // expected-warning {{parameter in cross-TU function should be marked [[clang::lifetimebound]]}}
|
|
|
|
//--- test_redecls_header_2.h
|
|
|
|
View in_two_headers(View a); // expected-warning {{parameter in cross-TU function should be marked [[clang::lifetimebound]]}}
|
|
|
|
//--- test_source.cpp
|
|
|
|
struct View;
|
|
View redeclared_before_header_include(View a); // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}
|
|
View source_and_header(View a); // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}
|
|
|
|
#include "test_header.h"
|
|
#include "test_redecls_header.h"
|
|
#include "test_redecls_header_1.h"
|
|
#include "test_redecls_header_2.h"
|
|
#include "Inputs/lifetime-analysis.h"
|
|
|
|
View earliest_decl_in_source(View a); // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}
|
|
View earliest_decl_in_source(View a);
|
|
|
|
View definition_before_header(View a) {
|
|
return a; // expected-note {{param returned here}}
|
|
}
|
|
|
|
View redeclared_before_header_include(View a) {
|
|
return a; // expected-note 2 {{param returned here}}
|
|
}
|
|
|
|
View return_view_directly(View a) {
|
|
return a; // expected-note {{param returned here}}
|
|
}
|
|
|
|
View conditional_return_view(View a, View b, bool c) {
|
|
View res;
|
|
if (c)
|
|
res = a;
|
|
else
|
|
res = b;
|
|
return res; // expected-note 2 {{param returned here}}
|
|
}
|
|
|
|
int* return_pointer_directly(int* a) {
|
|
return a; // expected-note {{param returned here}}
|
|
}
|
|
|
|
MyObj* return_pointer_object(MyObj* a) {
|
|
return a; // expected-note {{param returned here}}
|
|
}
|
|
|
|
View return_unnamed_view(View a) {
|
|
return a; // expected-note {{param returned here}}
|
|
}
|
|
|
|
MyObj& return_unnamed_ref(MyObj& a, bool c) {
|
|
return a; // expected-note {{param returned here}}
|
|
}
|
|
|
|
View earliest_decl_in_header(View a) {
|
|
return a; // expected-note {{param returned here}}
|
|
}
|
|
|
|
View earliest_decl_in_source(View a) {
|
|
return a; // expected-note {{param returned here}}
|
|
}
|
|
|
|
View multi_redecl_one_file(View a) {
|
|
return a; // expected-note {{param returned here}}
|
|
}
|
|
|
|
View in_two_headers(View a) {
|
|
return a; // expected-note 2 {{param returned here}}
|
|
}
|
|
|
|
View source_and_header(View a) {
|
|
return a; // expected-note 2 {{param returned here}}
|
|
}
|
|
|
|
MyObj& return_reference(MyObj& a, // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}
|
|
MyObj& b, // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}
|
|
bool c) {
|
|
if(c) {
|
|
return a; // expected-note {{param returned here}}
|
|
}
|
|
return b; // expected-note {{param returned here}}
|
|
}
|
|
|
|
const MyObj& return_reference_const(const MyObj& a) { // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}
|
|
return a; // expected-note {{param returned here}}
|
|
}
|
|
|
|
MyObj* return_ptr_to_ref(MyObj& a) { // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}
|
|
return &a; // expected-note {{param returned here}}
|
|
}
|
|
|
|
MyObj& return_ref_to_ptr(MyObj* a) { // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}
|
|
return *a; // expected-note {{param returned here}}
|
|
}
|
|
|
|
View return_ref_to_ptr_multiple(MyObj* a) { // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}
|
|
return *(&(*(&(*a)))); // expected-note {{param returned here}}
|
|
}
|
|
|
|
View return_view_from_reference(MyObj& p) { // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}
|
|
return p; // expected-note {{param returned here}}
|
|
}
|
|
|
|
struct Container {
|
|
MyObj data;
|
|
const MyObj& getData() [[clang::lifetimebound]] { return data; }
|
|
};
|
|
|
|
View return_struct_field(const Container& c) { // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}
|
|
return c.data; // expected-note {{param returned here}}
|
|
}
|
|
View return_struct_lifetimebound_getter(Container& c) { // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}
|
|
return c.getData().getView(); // expected-note {{param returned here}}
|
|
}
|
|
|
|
View return_view_from_reference_lifetimebound_member(MyObj& p) { // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}
|
|
return p.getView(); // expected-note {{param returned here}}
|
|
}
|
|
|
|
|
|
View return_cross_tu_func_View(View a) { // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}.
|
|
return return_view_directly(a); // expected-note {{param returned here}}
|
|
}
|
|
|
|
MyObj* return_cross_tu_func_obj(MyObj* a) { // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}.
|
|
return return_pointer_object(a); // expected-note {{param returned here}}
|
|
}
|
|
|
|
int* return_cross_tu_func_pointer(int* a) { // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}.
|
|
return return_pointer_directly(a); // expected-note {{param returned here}}
|
|
}
|
|
|
|
namespace {
|
|
View only_one_paramter_annotated(View a [[clang::lifetimebound]],
|
|
View b, // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}.
|
|
bool c) {
|
|
if(c)
|
|
return a;
|
|
return b; // expected-note {{param returned here}}
|
|
}
|
|
|
|
View reassigned_to_another_parameter(
|
|
View a,
|
|
View b) { // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}.
|
|
a = b;
|
|
return a; // expected-note {{param returned here}}
|
|
}
|
|
|
|
View intra_tu_func_redecl(View a); // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}.
|
|
View intra_tu_func_redecl(View a) {
|
|
return a; // expected-note {{param returned here}}
|
|
}
|
|
}
|
|
|
|
static View return_view_static(View a) { // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}.
|
|
return a; // expected-note {{param returned here}}
|
|
}
|
|
|
|
const ReturnThis& ReturnThis::get() const {
|
|
return *this; // expected-note {{param returned here}}
|
|
}
|
|
|
|
const ReturnThisPointer* ReturnThisPointer::get() const {
|
|
return this; // expected-note {{param returned here}}
|
|
}
|
|
|
|
struct ReturnsSelf {
|
|
ReturnsSelf() {}
|
|
~ReturnsSelf() {}
|
|
const ReturnsSelf& get() const { // expected-warning {{implicit this in intra-TU function should be marked [[clang::lifetimebound]]}}.
|
|
return *this; // expected-note {{param returned here}}
|
|
}
|
|
};
|
|
|
|
struct ReturnThisAnnotated {
|
|
const ReturnThisAnnotated& get() [[clang::lifetimebound]] { return *this; }
|
|
};
|
|
|
|
struct ViewProvider {
|
|
ViewProvider(int d) : data(d) {}
|
|
~ViewProvider() {}
|
|
MyObj data;
|
|
View getView() const { // expected-warning {{implicit this in intra-TU function should be marked [[clang::lifetimebound]]}}.
|
|
return data; // expected-note {{param returned here}}
|
|
}
|
|
};
|
|
|
|
View return_view_field(const ViewProvider& v) { // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}.
|
|
return v.data; // expected-note {{param returned here}}
|
|
}
|
|
|
|
void test_get_on_temporary_pointer() {
|
|
const ReturnsSelf* s_ref = &ReturnsSelf().get(); // expected-warning {{local temporary object does not live long enough}}.
|
|
// expected-note@-1 {{destroyed here}}
|
|
(void)s_ref; // expected-note {{later used here}}
|
|
}
|
|
|
|
void test_get_on_temporary_ref() {
|
|
const ReturnsSelf& s_ref = ReturnsSelf().get(); // expected-warning {{local temporary object does not live long enough}}.
|
|
// expected-note@-1 {{destroyed here}}
|
|
(void)s_ref; // expected-note {{later used here}}
|
|
}
|
|
|
|
void test_getView_on_temporary() {
|
|
View sv = ViewProvider{1}.getView(); // expected-warning {{local temporary object does not live long enough}}.
|
|
// expected-note@-1 {{destroyed here}}
|
|
(void)sv; // expected-note {{later used here}}
|
|
}
|
|
|
|
void test_get_on_temporary_copy() {
|
|
ReturnsSelf copy = ReturnsSelf().get();
|
|
(void)copy;
|
|
}
|
|
|
|
struct MemberReturn {
|
|
MyObj data;
|
|
|
|
MyObj& getRef() { // expected-warning {{implicit this in intra-TU function should be marked [[clang::lifetimebound]]}}.
|
|
return data; // expected-note {{param returned here}}
|
|
}
|
|
|
|
MyObj& getRefExplicit() { // expected-warning {{implicit this in intra-TU function should be marked [[clang::lifetimebound]]}}.
|
|
return this->data; // expected-note {{param returned here}}
|
|
}
|
|
|
|
MyObj& getRefDereference() { // expected-warning {{implicit this in intra-TU function should be marked [[clang::lifetimebound]]}}.
|
|
return (*this).data; // expected-note {{param returned here}}
|
|
}
|
|
|
|
const MyObj* getPtr() { // expected-warning {{implicit this in intra-TU function should be marked [[clang::lifetimebound]]}}.
|
|
return &data; // expected-note {{param returned here}}
|
|
}
|
|
|
|
const MyObj* getPtrExplicit() { // expected-warning {{implicit this in intra-TU function should be marked [[clang::lifetimebound]]}}.
|
|
return &(this->data); // expected-note {{param returned here}}
|
|
}
|
|
};
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Annotation Inference Test Cases
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
namespace correct_order_inference {
|
|
View return_view_by_func(View a) { // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}.
|
|
return return_view_directly(a); // expected-note {{param returned here}}
|
|
}
|
|
|
|
MyObj* return_pointer_by_func(MyObj* a) { // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}.
|
|
return return_pointer_object(a); // expected-note {{param returned here}}
|
|
}
|
|
} // namespace correct_order_inference
|
|
|
|
namespace incorrect_order_inference_view {
|
|
View return_view_callee(View a); // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}.
|
|
|
|
View return_view_caller(View a) { // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}.
|
|
return return_view_callee(a); // expected-note {{param returned here}}
|
|
}
|
|
|
|
View return_view_callee(View a) {
|
|
return a; // expected-note {{param returned here}}
|
|
}
|
|
} // namespace incorrect_order_inference_view
|
|
|
|
namespace incorrect_order_inference_object {
|
|
MyObj* return_object_callee(MyObj* a); // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}.
|
|
|
|
MyObj* return_object_caller(MyObj* a) { // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}.
|
|
return return_object_callee(a); // expected-note {{param returned here}}
|
|
}
|
|
|
|
MyObj* return_object_callee(MyObj* a) {
|
|
return a; // expected-note {{param returned here}}
|
|
}
|
|
} // namespace incorrect_order_inference_object
|
|
|
|
namespace simple_annotation_inference {
|
|
View inference_callee_return_identity(View a) { // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}.
|
|
return a; // expected-note {{param returned here}}
|
|
}
|
|
|
|
View inference_caller_forwards_callee(View a) { // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}.
|
|
return inference_callee_return_identity(a); // expected-note {{param returned here}}
|
|
}
|
|
|
|
View inference_top_level_return_stack_view() {
|
|
MyObj local_stack;
|
|
return inference_caller_forwards_callee(local_stack); // expected-warning {{stack memory associated with local variable 'local_stack' is returned}}
|
|
// expected-note@-1 {{returned here}}
|
|
}
|
|
} // namespace simple_annotation_inference
|
|
|
|
namespace inference_in_order_with_redecls {
|
|
View inference_callee_return_identity(View a); // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}.
|
|
View inference_callee_return_identity(View a) {
|
|
return a; // expected-note {{param returned here}}
|
|
}
|
|
|
|
View inference_caller_forwards_callee(View a); // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}.
|
|
View inference_caller_forwards_callee(View a) {
|
|
return inference_callee_return_identity(a); // expected-note {{param returned here}}
|
|
}
|
|
|
|
View inference_top_level_return_stack_view() {
|
|
MyObj local_stack;
|
|
return inference_caller_forwards_callee(local_stack); // expected-warning {{stack memory associated with local variable 'local_stack' is returned}}
|
|
// expected-note@-1 {{returned here}}
|
|
}
|
|
} // namespace inference_in_order_with_redecls
|
|
|
|
namespace inference_with_templates {
|
|
template<typename T>
|
|
T* template_identity(T* a) { // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}.
|
|
return a; // expected-note {{param returned here}}
|
|
}
|
|
|
|
template<typename T>
|
|
T* template_caller(T* a) { // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}.
|
|
return template_identity(a); // expected-note {{param returned here}}
|
|
}
|
|
|
|
MyObj* test_template_inference_with_stack() {
|
|
MyObj local_stack;
|
|
return template_caller(&local_stack); // expected-warning {{stack memory associated with local variable 'local_stack' is returned}}
|
|
// expected-note@-1 {{returned here}}
|
|
}
|
|
} // namespace inference_with_templates
|
|
|
|
namespace trailing_return {
|
|
struct TrailingReturn {
|
|
TrailingReturn() {}
|
|
~TrailingReturn() {}
|
|
MyObj data;
|
|
|
|
auto get_view() -> View { // expected-warning {{implicit this in intra-TU function should be marked [[clang::lifetimebound]]}}
|
|
return data; // expected-note {{param returned here}}
|
|
}
|
|
|
|
auto get_view_const() const -> View { // expected-warning {{implicit this in intra-TU function should be marked [[clang::lifetimebound]]}}
|
|
return data; // expected-note {{param returned here}}
|
|
}
|
|
|
|
auto get_ref() const -> const MyObj& { // expected-warning {{implicit this in intra-TU function should be marked [[clang::lifetimebound]]}}
|
|
return data; // expected-note {{param returned here}}
|
|
}
|
|
};
|
|
} // namespace trailing_return
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Negative Test Cases
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
View already_annotated(View a [[clang::lifetimebound]]) {
|
|
return a;
|
|
}
|
|
|
|
MyObj return_obj_by_value(MyObj& p) {
|
|
return p;
|
|
}
|
|
|
|
MyObj GlobalMyObj;
|
|
View Global = GlobalMyObj;
|
|
View Reassigned(View a) {
|
|
a = Global;
|
|
return a;
|
|
}
|
|
|
|
namespace lambda_captures {
|
|
|
|
struct NoSuggestionForThisCapturedByLambda {
|
|
MyObj s;
|
|
bool cond;
|
|
void foo() {
|
|
auto x = [&]() {
|
|
return cond > 0 ? &this->s : &s;
|
|
};
|
|
}
|
|
};
|
|
|
|
void Foo(int, int*, const MyObj&, View);
|
|
|
|
auto implicit_ref_capture(int integer, int* ptr,
|
|
const MyObj& ref, // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}
|
|
View view) {
|
|
return [&]() { Foo(integer, ptr, ref, view); }; // expected-warning {{stack memory associated with parameter 'ptr' is returned}} \
|
|
// expected-warning {{stack memory associated with parameter 'view' is returned}} \
|
|
// expected-warning {{stack memory associated with parameter 'integer' is returned}} \
|
|
// expected-note 3 {{returned here}} \
|
|
// expected-note {{param returned here}}
|
|
}
|
|
|
|
auto implicit_value_capture(int integer,
|
|
int* ptr, // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}
|
|
const MyObj& ref,
|
|
View view) { // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}
|
|
return [=]() { Foo(integer, ptr, ref, view); }; // expected-note 2 {{param returned here}}
|
|
}
|
|
} // namespace lambda_captures
|
|
|
|
namespace array {
|
|
|
|
struct MemberArrayReturn {
|
|
int arr[10];
|
|
|
|
int* getFirst() { // expected-warning {{implicit this in intra-TU function should be marked [[clang::lifetimebound]]}}
|
|
return &arr[0]; // expected-note {{param returned here}}
|
|
}
|
|
|
|
int* getData() { // expected-warning {{implicit this in intra-TU function should be marked [[clang::lifetimebound]]}}
|
|
return arr; // expected-note {{param returned here}}
|
|
}
|
|
int* getLast() { // expected-warning {{implicit this in intra-TU function should be marked [[clang::lifetimebound]]}}
|
|
return arr + 10; // expected-note {{param returned here}}
|
|
}
|
|
};
|
|
|
|
} // namespace array
|
|
|
|
namespace track_origins_for_lifetimebound_record_type {
|
|
|
|
struct S {
|
|
View view;
|
|
};
|
|
|
|
S getS(const MyObj &obj [[clang::lifetimebound]]);
|
|
|
|
S forward(const MyObj &obj) { // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}
|
|
return getS(obj); // expected-note {{param returned here}}
|
|
}
|
|
|
|
} // namespace track_origins_for_lifetimebound_record_type
|
|
|
|
namespace capturing_constructor {
|
|
struct CaptureRefToView {
|
|
View v; // expected-note {{escapes to this field}}
|
|
CaptureRefToView(const MyObj& obj) : v(obj) {} // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}
|
|
};
|
|
|
|
CaptureRefToView test_ref_to_view() {
|
|
MyObj obj;
|
|
CaptureRefToView x(obj); // expected-warning {{stack memory associated with local variable 'obj' is returned}}
|
|
return x; // expected-note {{returned here}}
|
|
}
|
|
|
|
struct CaptureRefToPtr {
|
|
const MyObj* p; // expected-note {{escapes to this field}}
|
|
CaptureRefToPtr(const MyObj& obj) : p(&obj) {} // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}
|
|
};
|
|
|
|
CaptureRefToPtr test_ref_to_ptr() {
|
|
MyObj obj;
|
|
CaptureRefToPtr x(obj); // expected-warning {{stack memory associated with local variable 'obj' is returned}}
|
|
return x; // expected-note {{returned here}}
|
|
}
|
|
|
|
struct CaptureViewToView {
|
|
View v; // expected-note {{escapes to this field}}
|
|
CaptureViewToView(View v_param) : v(v_param) {} // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}
|
|
};
|
|
|
|
CaptureViewToView test_view_to_view() {
|
|
MyObj obj;
|
|
View v(obj); // expected-warning {{stack memory associated with local variable 'obj' is returned}}
|
|
CaptureViewToView x(v);
|
|
return x; // expected-note {{returned here}}
|
|
}
|
|
|
|
struct CapturePtrToPtr {
|
|
const MyObj* p; // expected-note {{escapes to this field}}
|
|
CapturePtrToPtr(const MyObj* p_param) : p(p_param) {} // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}
|
|
};
|
|
|
|
CapturePtrToPtr test_ptr_to_ptr() {
|
|
MyObj obj;
|
|
CapturePtrToPtr x(&obj); // expected-warning {{stack memory associated with local variable 'obj' is returned}}
|
|
return x; // expected-note {{returned here}}
|
|
}
|
|
|
|
struct CaptureRefToRef {
|
|
const MyObj& r; // expected-note {{escapes to this field}}
|
|
CaptureRefToRef(const MyObj& obj) : r(obj) {} // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}
|
|
};
|
|
|
|
CaptureRefToRef test_ref_to_ref() {
|
|
MyObj obj;
|
|
CaptureRefToRef x(obj); // expected-warning {{stack memory associated with local variable 'obj' is returned}}
|
|
return x; // expected-note {{returned here}}
|
|
}
|
|
|
|
struct BaseWithView {
|
|
View v; // expected-note {{escapes to this field}}
|
|
};
|
|
struct CaptureRefToBaseView : BaseWithView {
|
|
CaptureRefToBaseView(const MyObj& obj) { // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}
|
|
v = obj;
|
|
}
|
|
};
|
|
|
|
CaptureRefToBaseView test_ref_to_base_view() {
|
|
MyObj obj;
|
|
CaptureRefToBaseView x(obj); // expected-warning {{stack memory associated with local variable 'obj' is returned}}
|
|
return x; // expected-note {{returned here}}
|
|
}
|
|
} // namespace capturing_constructor
|
|
|
|
namespace callable_wrappers {
|
|
|
|
std::function<void()> return_lambda_capturing_param(int &x) { // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}
|
|
return [&]() { (void)x; }; // expected-note {{param returned here}}
|
|
}
|
|
|
|
void uaf_via_inferred_lifetimebound() {
|
|
std::function<void()> f = []() {};
|
|
{
|
|
int local;
|
|
f = return_lambda_capturing_param(local); // expected-warning {{local variable 'local' does not live long enough}}
|
|
} // expected-note {{destroyed here}}
|
|
(void)f; // expected-note {{later used here}}
|
|
}
|
|
|
|
} // namespace callable_wrappers
|
|
|
|
namespace make_unique_suggestion {
|
|
|
|
struct LifetimeBoundCtor {
|
|
View v;
|
|
// FIXME: This test fails to propagate the lifetimebound in ctor if this is inferred (instead of the current explicit annotation).
|
|
LifetimeBoundCtor(const MyObj& obj [[clang::lifetimebound]]): v(obj) {}
|
|
};
|
|
|
|
std::unique_ptr<LifetimeBoundCtor> create_target(const MyObj& obj) { // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}
|
|
return std::make_unique<LifetimeBoundCtor>(obj); // expected-note {{param returned here}}
|
|
}
|
|
|
|
void test_inference() {
|
|
std::unique_ptr<LifetimeBoundCtor> ptr;
|
|
{
|
|
MyObj obj;
|
|
ptr = create_target(obj); // expected-warning {{local variable 'obj' does not live long enough}}
|
|
} // expected-note {{destroyed here}}
|
|
(void)ptr; // expected-note {{later used here}}
|
|
}
|
|
} // namespace make_unique_suggestion
|
|
|
|
namespace new_allocation_suggestion {
|
|
|
|
View* MakeView(const MyObj& in) { // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}
|
|
return new View(in); // expected-note {{param returned here}} {{destroyed here}}
|
|
}
|
|
|
|
void test_new_allocation() {
|
|
View* v = MakeView(MyObj{}); // expected-warning {{local temporary object does not live long enough}} \
|
|
// expected-note {{destroyed here}}
|
|
(void)v; // expected-note {{later used here}}
|
|
}
|
|
|
|
struct LifetimeBoundCtor {
|
|
View v;
|
|
LifetimeBoundCtor();
|
|
LifetimeBoundCtor(const MyObj& obj [[clang::lifetimebound]]) : v(obj) {}
|
|
};
|
|
|
|
struct HasCtorField {
|
|
LifetimeBoundCtor* field; // expected-note {{escapes to this field}}
|
|
HasCtorField(const MyObj& obj) : field(new LifetimeBoundCtor(obj)) {} // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}
|
|
};
|
|
|
|
HasCtorField test_dangling_field_ctor() {
|
|
MyObj obj;
|
|
HasCtorField x(obj); // expected-warning {{stack memory associated with local variable 'obj' is returned}}
|
|
return x; // expected-note {{returned here}}
|
|
}
|
|
|
|
struct HasSetterField {
|
|
LifetimeBoundCtor* field; // expected-note {{this field dangles}}
|
|
// FIXME: Does not currently suggest `lifetime_capture_by(this)` (even without `new`)
|
|
void set(const MyObj& obj) {
|
|
field = new LifetimeBoundCtor(obj);
|
|
}
|
|
void reset() {
|
|
MyObj obj;
|
|
field = new LifetimeBoundCtor(obj); // expected-warning {{stack memory associated with local variable 'obj' escapes to the field 'field' which will dangle}}
|
|
}
|
|
};
|
|
|
|
HasSetterField test_dangling_field_member_fn() {
|
|
MyObj obj;
|
|
HasSetterField x;
|
|
x.set(obj);
|
|
return x;
|
|
}
|
|
|
|
} // namespace new_allocation_suggestion
|
|
|
|
namespace GH193747 {
|
|
|
|
std::unique_ptr<int> create_up();
|
|
std::shared_ptr<int> create_sp() {
|
|
return create_up();
|
|
}
|
|
|
|
struct S {
|
|
int* field;
|
|
S(std::unique_ptr<int>&& up) : field(up.get()) { up.release(); }
|
|
};
|
|
|
|
S foo() {
|
|
return S(create_up());
|
|
}
|
|
} // namespace GH193747
|