@@ -6802,77 +6802,103 @@ def UnsafeBufferUsageDocs : Documentation {
68026802 let Category = DocCatFunction;
68036803 let Content = [{
68046804The attribute ``[[clang::unsafe_buffer_usage]]`` should be placed on functions
6805- that need to be avoided as they are prone to buffer overflows. It is designed to
6806- work together with the off-by-default compiler warning ``-Wunsafe-buffer-usage``
6807- to help codebases transition away from raw pointer based buffer management,
6808- in favor of safer abstractions such as C++20 ``std::span``. The attribute causes
6809- ``-Wunsafe-buffer-usage`` to warn on every use of the function, and it may
6810- enable ``-Wunsafe-buffer-usage`` to emit automatic fix-it hints
6811- which would help the user replace such unsafe functions with safe
6805+ that need to be avoided as they are prone to buffer overflows or unsafe buffer
6806+ struct fields. It is designed to work together with the off-by-default compiler
6807+ warning ``-Wunsafe-buffer-usage`` to help codebases transition away from raw pointer
6808+ based buffer management, in favor of safer abstractions such as C++20 ``std::span``.
6809+ The attribute causes ``-Wunsafe-buffer-usage`` to warn on every use of the function or
6810+ the field it is attached to, and it may also lead to emission of automatic fix-it
6811+ hints which would help the user replace the use of unsafe functions(/fields) with safe
68126812alternatives, though the attribute can be used even when the fix can't be automated.
68136813
6814- The attribute does not suppress ``-Wunsafe-buffer-usage`` inside the function
6815- to which it is attached. These warnings still need to be addressed.
6814+ * Attribute attached to functions: The attribute does not suppress
6815+ ``-Wunsafe-buffer-usage`` inside the function to which it is attached.
6816+ These warnings still need to be addressed.
68166817
6817- The attribute is warranted even if the only way a function can overflow
6818- the buffer is by violating the function's preconditions. For example, it
6819- would make sense to put the attribute on function ``foo()`` below because
6820- passing an incorrect size parameter would cause a buffer overflow:
6818+ The attribute is warranted even if the only way a function can overflow
6819+ the buffer is by violating the function's preconditions. For example, it
6820+ would make sense to put the attribute on function ``foo()`` below because
6821+ passing an incorrect size parameter would cause a buffer overflow:
68216822
6822- .. code-block:: c++
6823+ .. code-block:: c++
68236824
6824- [[clang::unsafe_buffer_usage]]
6825- void foo(int *buf, size_t size) {
6826- for (size_t i = 0; i < size; ++i) {
6827- buf[i] = i;
6825+ [[clang::unsafe_buffer_usage]]
6826+ void foo(int *buf, size_t size) {
6827+ for (size_t i = 0; i < size; ++i) {
6828+ buf[i] = i;
6829+ }
68286830 }
6829- }
68306831
6831- The attribute is NOT warranted when the function uses safe abstractions,
6832- assuming that these abstractions weren't misused outside the function.
6833- For example, function ``bar()`` below doesn't need the attribute,
6834- because assuming that the container ``buf`` is well-formed (has size that
6835- fits the original buffer it refers to), overflow cannot occur:
6832+ The attribute is NOT warranted when the function uses safe abstractions,
6833+ assuming that these abstractions weren't misused outside the function.
6834+ For example, function ``bar()`` below doesn't need the attribute,
6835+ because assuming that the container ``buf`` is well-formed (has size that
6836+ fits the original buffer it refers to), overflow cannot occur:
68366837
6837- .. code-block:: c++
6838+ .. code-block:: c++
68386839
6839- void bar(std::span<int> buf) {
6840- for (size_t i = 0; i < buf.size(); ++i) {
6841- buf[i] = i;
6840+ void bar(std::span<int> buf) {
6841+ for (size_t i = 0; i < buf.size(); ++i) {
6842+ buf[i] = i;
6843+ }
68426844 }
6843- }
68446845
6845- In this case function ``bar()`` enables the user to keep the buffer
6846- "containerized" in a span for as long as possible. On the other hand,
6847- Function ``foo()`` in the previous example may have internal
6848- consistency, but by accepting a raw buffer it requires the user to unwrap
6849- their span, which is undesirable according to the programming model
6850- behind ``-Wunsafe-buffer-usage``.
6846+ In this case function ``bar()`` enables the user to keep the buffer
6847+ "containerized" in a span for as long as possible. On the other hand,
6848+ Function ``foo()`` in the previous example may have internal
6849+ consistency, but by accepting a raw buffer it requires the user to unwrap
6850+ their span, which is undesirable according to the programming model
6851+ behind ``-Wunsafe-buffer-usage``.
68516852
6852- The attribute is warranted when a function accepts a raw buffer only to
6853- immediately put it into a span:
6853+ The attribute is warranted when a function accepts a raw buffer only to
6854+ immediately put it into a span:
68546855
6855- .. code-block:: c++
6856+ .. code-block:: c++
68566857
6857- [[clang::unsafe_buffer_usage]]
6858- void baz(int *buf, size_t size) {
6859- std::span<int> sp{ buf, size };
6860- for (size_t i = 0; i < sp.size(); ++i) {
6861- sp[i] = i;
6858+ [[clang::unsafe_buffer_usage]]
6859+ void baz(int *buf, size_t size) {
6860+ std::span<int> sp{ buf, size };
6861+ for (size_t i = 0; i < sp.size(); ++i) {
6862+ sp[i] = i;
6863+ }
68626864 }
6863- }
68646865
6865- In this case ``baz()`` does not contain any unsafe operations, but the awkward
6866- parameter type causes the caller to unwrap the span unnecessarily.
6867- Note that regardless of the attribute, code inside ``baz()`` isn't flagged
6868- by ``-Wunsafe-buffer-usage`` as unsafe. It is definitely undesirable,
6869- but if ``baz()`` is on an API surface, there is no way to improve it
6870- to make it as safe as ``bar()`` without breaking the source and binary
6871- compatibility with existing users of the function. In such cases
6872- the proper solution would be to create a different function (possibly
6873- an overload of ``baz()``) that accepts a safe container like ``bar()``,
6874- and then use the attribute on the original ``baz()`` to help the users
6875- update their code to use the new function.
6866+ In this case ``baz()`` does not contain any unsafe operations, but the awkward
6867+ parameter type causes the caller to unwrap the span unnecessarily.
6868+ Note that regardless of the attribute, code inside ``baz()`` isn't flagged
6869+ by ``-Wunsafe-buffer-usage`` as unsafe. It is definitely undesirable,
6870+ but if ``baz()`` is on an API surface, there is no way to improve it
6871+ to make it as safe as ``bar()`` without breaking the source and binary
6872+ compatibility with existing users of the function. In such cases
6873+ the proper solution would be to create a different function (possibly
6874+ an overload of ``baz()``) that accepts a safe container like ``bar()``,
6875+ and then use the attribute on the original ``baz()`` to help the users
6876+ update their code to use the new function.
6877+
6878+ * Attribute attached to fields: The attribute should only be attached to
6879+ struct fields, if the fields can not be updated to a safe type with bounds
6880+ check, such as std::span. In other words, the buffers prone to unsafe accesses
6881+ should always be updated to use safe containers/views and attaching the attribute
6882+ must be last resort when such an update is infeasible.
6883+
6884+ The attribute can be placed on individual fields or a set of them as shown below.
6885+
6886+ .. code-block:: c++
6887+
6888+ struct A {
6889+ [[clang::unsafe_buffer_usage]]
6890+ int *ptr1;
6891+
6892+ [[clang::unsafe_buffer_usage]]
6893+ int *ptr2, buf[10];
6894+
6895+ [[clang::unsafe_buffer_usage]]
6896+ size_t sz;
6897+ };
6898+
6899+ Here, every read/write to the fields ptr1, ptr2, buf and sz will trigger a warning
6900+ that the field has been explcitly marked as unsafe due to unsafe-buffer operations.
6901+
68766902 }];
68776903}
68786904
0 commit comments