aboutsummaryrefslogtreecommitdiff
path: root/llvm/docs/LangRef.rst
diff options
context:
space:
mode:
authorHans Wennborg <hans@chromium.org>2022-01-03 18:03:43 +0100
committerHans Wennborg <hans@chromium.org>2022-01-13 12:04:49 +0100
commit2bc57d85ebf244f19a3046295b58eb8c667f947d (patch)
tree7e97752c4425b7d6ab0489fad02ac0be7484c87b /llvm/docs/LangRef.rst
parentf4139440f1cf2b30705d7f81104cc51eca3d4977 (diff)
downloadllvm-2bc57d85ebf244f19a3046295b58eb8c667f947d.zip
llvm-2bc57d85ebf244f19a3046295b58eb8c667f947d.tar.gz
llvm-2bc57d85ebf244f19a3046295b58eb8c667f947d.tar.bz2
Don't override __attribute__((no_stack_protector)) by inlining (PR52886)
Since 26c6a3e736d3, LLVM's inliner will "upgrade" the caller's stack protector attribute based on the callee. This lead to surprising results with Clang's no_stack_protector attribute added in 4fbf84c1732f (D46300). Consider the following code compiled with clang -fstack-protector-strong -Os (https://godbolt.org/z/7s3rW7a1q). extern void h(int* p); inline __attribute__((always_inline)) int g() { return 0; } int __attribute__((__no_stack_protector__)) f() { int a[1]; h(a); return g(); } LLVM will inline g() into f(), and f() would get a stack protector, against the users explicit wishes, potentially breaking the program e.g. if h() changes the value of the stack cookie. That's a miscompile. More recently, bc044a88ee3c (D91816) addressed this problem by preventing inlining when the stack protector is disabled in the caller and enabled in the callee or vice versa. However, the problem remained if the callee is marked always_inline as in the example above. This affected users, see e.g. http://crbug.com/1274129 and http://llvm.org/pr52886. One way to fix this would be to prevent inlining also in the always_inline case. Despite the name, always_inline does not guarantee inlining, so this would be legal but potentially surprising to users. However, I think the better fix is to not enable the stack protector in a caller based on the callee. The motivation for the old behaviour is unclear, it seems counter-intuitive, and causes real problems as we've seen. This commit implements that fix, which means in the example above, g() gets inlined into f() (also without always_inline), and f() is emitted without stack protector. I think that matches most developers' expectations, and that's also what GCC does. Another effect of this change is that a no_stack_protector function can now be inlined into a stack protected function, e.g. (https://godbolt.org/z/hafP6W856): extern void h(int* p); inline int __attribute__((__no_stack_protector__)) __attribute__((always_inline)) g() { return 0; } int f() { int a[1]; h(a); return g(); } I think that's fine. Such code would be unusual since no_stack_protector is normally applied to a program entry point which sets up the stack canary. And even if such code exists, inlining doesn't change the semantics: there is still no stack cookie setup/check around entry/exit of the g() code region, but there may be in the surrounding context, as there was before inlining. This also matches GCC. See also the discussion at https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94722 Differential revision: https://reviews.llvm.org/D116589
Diffstat (limited to 'llvm/docs/LangRef.rst')
-rw-r--r--llvm/docs/LangRef.rst26
1 files changed, 10 insertions, 16 deletions
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 3a47cb5..33ff3a8 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -1995,11 +1995,9 @@ example:
Variables that are identified as requiring a protector will be arranged
on the stack such that they are adjacent to the stack protector guard.
- A function with the ``ssp`` attribute but without the ``alwaysinline``
- attribute cannot be inlined into a function without a
- ``ssp/sspreq/sspstrong`` attribute. If inlined, the caller will get the
- ``ssp`` attribute. ``call``, ``invoke``, and ``callbr`` instructions with
- the ``alwaysinline`` attribute force inlining.
+ If a function with an ``ssp`` attribute is inlined into a calling function,
+ the attribute is not carried over to the calling function.
+
``sspstrong``
This attribute indicates that the function should emit a stack smashing
protector. This attribute causes a strong heuristic to be used when
@@ -2024,12 +2022,10 @@ example:
This overrides the ``ssp`` function attribute.
- A function with the ``sspstrong`` attribute but without the
- ``alwaysinline`` attribute cannot be inlined into a function without a
- ``ssp/sspstrong/sspreq`` attribute. If inlined, the caller will get the
- ``sspstrong`` attribute unless the ``sspreq`` attribute exists. ``call``,
- ``invoke``, and ``callbr`` instructions with the ``alwaysinline`` attribute
- force inlining.
+ If a function with an ``sspstrong`` attribute is inlined into a calling
+ function which has an ``ssp`` attribute, the calling function's attribute
+ will be upgraded to ``sspstrong``.
+
``sspreq``
This attribute indicates that the function should *always* emit a stack
smashing protector. This overrides the ``ssp`` and ``sspstrong`` function
@@ -2046,11 +2042,9 @@ example:
#. Variables that have had their address taken are 3rd closest to the
protector.
- A function with the ``sspreq`` attribute but without the ``alwaysinline``
- attribute cannot be inlined into a function without a
- ``ssp/sspstrong/sspreq`` attribute. If inlined, the caller will get the
- ``sspreq`` attribute. ``call``, ``invoke``, and ``callbr`` instructions
- with the ``alwaysinline`` attribute force inlining.
+ If a function with an ``sspreq`` attribute is inlined into a calling
+ function which has an ``ssp`` or ``sspstrong`` attribute, the calling
+ function's attribute will be upgraded to ``sspreq``.
``strictfp``
This attribute indicates that the function was called from a scope that