-
Notifications
You must be signed in to change notification settings - Fork 10.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[-Wunsafe-buffer-usage] Warning for unsafe invocation of span::data (#…
…75650) …-Wunsafe-buffer-usage, there maybe accidental re-introduction of new OutOfBound accesses into the code bases. One such case is invoking span::data() method on a span variable to retrieve a pointer, which is then cast to a larger type and dereferenced. Such dereferences can introduce OutOfBound accesses. To address this, a new WarningGadget is being introduced to warn against such invocations. --------- Co-authored-by: MalavikaSamak <malavika2@apple.com>
- Loading branch information
1 parent
e32b1d1
commit 7122f55
Showing
6 changed files
with
182 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
131 changes: 131 additions & 0 deletions
131
clang/test/SemaCXX/warn-unsafe-buffer-usage-warning-data-invocation.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
// RUN: %clang_cc1 -std=c++20 -Wno-all -Wunsafe-buffer-usage \ | ||
// RUN: -fsafe-buffer-usage-suggestions \ | ||
// RUN: -fblocks -include %s -verify %s | ||
|
||
// RUN: %clang -x c++ -frtti -fsyntax-only -fblocks -include %s %s 2>&1 | FileCheck --allow-empty %s | ||
// RUN: %clang_cc1 -std=c++11 -fblocks -include %s %s 2>&1 | FileCheck --allow-empty %s | ||
// RUN: %clang_cc1 -std=c++20 -fblocks -include %s %s 2>&1 | FileCheck --allow-empty %s | ||
// CHECK-NOT: [-Wunsafe-buffer-usage] | ||
|
||
#ifndef INCLUDED | ||
#define INCLUDED | ||
#pragma clang system_header | ||
|
||
// no spanification warnings for system headers | ||
#else | ||
|
||
namespace std { | ||
class type_info; | ||
class bad_cast; | ||
class bad_typeid; | ||
} | ||
using size_t = __typeof(sizeof(int)); | ||
void *malloc(size_t); | ||
|
||
void foo(int v) { | ||
} | ||
|
||
void foo(int *p){} | ||
|
||
namespace std{ | ||
template <typename T> class span { | ||
|
||
T *elements; | ||
|
||
span(T *, unsigned){} | ||
|
||
public: | ||
|
||
constexpr span<T> subspan(size_t offset, size_t count) const { | ||
return span<T> (elements+offset, count); // expected-warning{{unsafe pointer arithmetic}} | ||
} | ||
|
||
constexpr T* data() const noexcept { | ||
return elements; | ||
} | ||
|
||
|
||
constexpr T* hello() const noexcept { | ||
return elements; | ||
} | ||
}; | ||
|
||
template <typename T> class span_duplicate { | ||
span_duplicate(T *, unsigned){} | ||
|
||
T array[10]; | ||
|
||
public: | ||
|
||
T* data() { | ||
return array; | ||
} | ||
|
||
}; | ||
} | ||
|
||
using namespace std; | ||
|
||
class A { | ||
int a, b, c; | ||
}; | ||
|
||
class B { | ||
int a, b, c; | ||
}; | ||
|
||
struct Base { | ||
virtual ~Base() = default; | ||
}; | ||
|
||
struct Derived: Base { | ||
int d; | ||
}; | ||
|
||
void cast_without_data(int *ptr) { | ||
A *a = (A*) ptr; | ||
float *p = (float*) ptr; | ||
} | ||
|
||
void warned_patterns(std::span<int> span_ptr, std::span<Base> base_span, span<int> span_without_qual) { | ||
A *a1 = (A*)span_ptr.data(); // expected-warning{{unsafe invocation of span::data}} | ||
a1 = (A*)span_ptr.data(); // expected-warning{{unsafe invocation of span::data}} | ||
|
||
A *a2 = (A*) span_without_qual.data(); // expected-warning{{unsafe invocation of span::data}} | ||
|
||
// TODO:: Should we warn when we cast from base to derived type? | ||
Derived *b = dynamic_cast<Derived*> (base_span.data());// expected-warning{{unsafe invocation of span::data}} | ||
|
||
// TODO:: This pattern is safe. We can add special handling for it, if we decide this | ||
// is the recommended fixit for the unsafe invocations. | ||
A *a3 = (A*)span_ptr.subspan(0, sizeof(A)).data(); // expected-warning{{unsafe invocation of span::data}} | ||
} | ||
|
||
void not_warned_patterns(std::span<A> span_ptr, std::span<Base> base_span) { | ||
int *p = (int*) span_ptr.data(); // Cast to a smaller type | ||
|
||
B *b = (B*) span_ptr.data(); // Cast to a type of same size. | ||
|
||
p = (int*) span_ptr.data(); | ||
A *a = (A*) span_ptr.hello(); // Invoking other methods. | ||
} | ||
|
||
// We do not want to warn about other types | ||
void other_classes(std::span_duplicate<int> span_ptr) { | ||
int *p; | ||
A *a = (A*)span_ptr.data(); | ||
a = (A*)span_ptr.data(); | ||
} | ||
|
||
// Potential source for false negatives | ||
|
||
A false_negatives(std::span<int> span_pt, span<A> span_A) { | ||
int *ptr = span_pt.data(); | ||
|
||
A *a1 = (A*)ptr; //TODO: We want to warn here eventually. | ||
|
||
A *a2= span_A.data(); | ||
return *a2; // TODO: Can cause OOB if span_pt is empty | ||
|
||
} | ||
#endif |