Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inplace new-ing an array overwrites the square of the memory #41441

Closed
AlisdairM mannequin opened this issue May 31, 2019 · 11 comments · Fixed by #83124, #89036 or #96464
Closed

Inplace new-ing an array overwrites the square of the memory #41441

AlisdairM mannequin opened this issue May 31, 2019 · 11 comments · Fixed by #83124, #89036 or #96464
Labels
bugzilla Issues migrated from bugzilla c++ clang:frontend Language frontend issues, e.g. anything involving "Sema" confirmed Verified by a second party

Comments

@AlisdairM
Copy link
Mannequin

AlisdairM mannequin commented May 31, 2019

Bugzilla Link 42096
Version 8.0
OS Linux
CC @dwblaikie,@DougGregor,@jfbastien,@riccibruno,@zygoloid

Extended Description

When in-place new-ing a local variable of an array of trivial type, the generated code calls memset with the square of the size of the array, corrupting the stack.

Quick example:

#include <new>

template <typename TYPE>
void f()
{
    typedef TYPE TArray[7];

    TArray x;
    new(&x) TArray();
}

int main()
{
    f<char>();
    f<int>();
}

Sample code generation can be seen for Clang 7 and 8 via godbolt:
https://godbolt.org/z/WjhFrc

@dwblaikie
Copy link
Collaborator

Neat! I'll take a look.

@dwblaikie
Copy link
Collaborator

Seems to only happen in the template case, not if you inline it into a non-template situation. Huh.

@dwblaikie
Copy link
Collaborator

Talked to Richard Smith & summarizing that discussion:

In general Clang currently strips the first array bound of an array new to handle it differently (because it can be a runtime bound, etc) - but in a non-dependent case then adjusts the type of the new to the nested type (removing that outer bound). But in a dependent case it does not perform that type adjustment - so later on uses both the size of the outer bound that was split off, plus the size of the un-adjusted array, that includes that outer bound.

ActOnCXXNew is where all new expressions are handled, and it does the top-bound stripping off for non-dependent types.
CreateCXXNew is where it gets weird & the dependent type case gets the bound extracted but the type is not adjusted.

General thought: Representationally it'd probably be better not to "adjust" the type - extract the top bound for runtime bound/other reasons, but keep the original type (with possible runtime bound). Then when computing the size, always strip off the top bound and multiply it by the extracted bound.

@AlisdairM
Copy link
Mannequin Author

AlisdairM mannequin commented Dec 24, 2020

Updated godbolt link showing this issue is still present on trunk, 2020/12/23:
https://godbolt.org/z/zre3j4

@llvmbot llvmbot transferred this issue from llvm/llvm-bugzilla-archive Dec 10, 2021
@mahtohappy
Copy link
Contributor

Hi, I added a fix for this, but couldn't link it somehow, now sure why. #83124

@EugeneZelenko EugeneZelenko added the clang:frontend Language frontend issues, e.g. anything involving "Sema" label Feb 27, 2024
@llvmbot
Copy link

llvmbot commented Feb 27, 2024

@llvm/issue-subscribers-clang-frontend

Author: None (e84ee981-20b7-441e-8de0-adb2190144d6)

| | | | --- | --- | | Bugzilla Link | [42096](https://llvm.org/bz42096) | | Version | 8.0 | | OS | Linux | | CC | @dwblaikie,@DougGregor,@jfbastien,@riccibruno,@zygoloid |

Extended Description

When in-place new-ing a local variable of an array of trivial type, the generated code calls 'memset' with the square of the size of the array, corrupting the stack.

Quick example:

#include <new>

template <typename TYPE>
void f()
{
typedef TYPE TArray[7];

TArray x;
new(&amp;x) TArray();

}

int main()
{
f<char>();
f<int>();
}

Sample code generation can be seen for Clang 7 and 8 via godbolt:
https://godbolt.org/z/WjhFrc

@shafik shafik added the confirmed Verified by a second party label Feb 27, 2024
cor3ntin pushed a commit that referenced this issue Apr 16, 2024
…ze (#83124)

When in-place new-ing a local variable of an array of trivial type, the
generated code calls 'memset' with the correct size of the array,
earlier it was generating size (squared of the typedef array + size).

The cause: `typedef TYPE TArray[8]; TArray x;` The type of declarator is
Tarray[8] and in `SemaExprCXX.cpp::BuildCXXNew` we check if it's of
typedef and of constant size then we get the original type and it works
fine for non-dependent cases.
But in case of template we do `TreeTransform.h:TransformCXXNEWExpr` and
there we again check the allocated type which is TArray[8] and it stays
that way, so ArraySize=(Tarray[8] type, alloc Tarray[8*type]) so the
squared size allocation.

ArraySize gets calculated earlier in `TreeTransform.h` so that
`if(!ArraySize)` condition was failing.
fix: I changed that condition to `if(ArraySize)`. 


Fixes #41441
mahtohappy added a commit to mahtohappy/llvm-project that referenced this issue Apr 17, 2024
…ze (llvm#83124)

When in-place new-ing a local variable of an array of trivial type, the
generated code calls 'memset' with the correct size of the array,
earlier it was generating size (squared of the typedef array + size).

The cause: `typedef TYPE TArray[8]; TArray x;` The type of declarator is
Tarray[8] and in `SemaExprCXX.cpp::BuildCXXNew` we check if it's of
typedef and of constant size then we get the original type and it works
fine for non-dependent cases.
But in case of template we do `TreeTransform.h:TransformCXXNEWExpr` and
there we again check the allocated type which is TArray[8] and it stays
that way, so ArraySize=(Tarray[8] type, alloc Tarray[8*type]) so the
squared size allocation.

ArraySize gets calculated earlier in `TreeTransform.h` so that
`if(!ArraySize)` condition was failing.
fix: I changed that condition to `if(ArraySize)`. 


Fixes llvm#41441
@awson
Copy link
Contributor

awson commented Jun 24, 2024

The "fix" has been reverted, the problem is still with us.

CreateCXXNew is where it gets weird & the dependent type case gets the bound extracted but the type is not adjusted

@dwblaikie, I can't find CreateCXXNew anywhere in the code (even after preprocessing), do you mean BuildCXXNew?

@dwblaikie
Copy link
Collaborator

The "fix" has been reverted, the problem is still with us.

CreateCXXNew is where it gets weird & the dependent type case gets the bound extracted but the type is not adjusted

@dwblaikie, I can't find CreateCXXNew anywhere in the code (even after preprocessing), do you mean BuildCXXNew?

Yeah, been a while - but at a cursory glance that correction sounds right.

@dwblaikie
Copy link
Collaborator

(patch was reverted in e1321fa)

@dwblaikie dwblaikie reopened this Jun 24, 2024
@awson
Copy link
Contributor

awson commented Sep 14, 2024

@djtodoro, how is this "completed"?

I see neither my PR (#96464) is merged, nor any newer one is referenced in this issue.

@djtodoro djtodoro reopened this Sep 14, 2024
@djtodoro
Copy link
Collaborator

@djtodoro, how is this "completed"?

I see neither my PR (#96464) is merged, nor any newer one is referenced in this issue.

I have no idea what happened here. Never touched or visited this issue.

DanielCChen pushed a commit to DanielCChen/llvm-project that referenced this issue Oct 16, 2024
The [last attempt](llvm#89036) to
fix llvm#41441 has been reverted
immediately.

Here I'm trying the simplest idea I've been able to come with: skip
handling dependent case in `BuildCXXNew`.

The original test (borrowed form
llvm#89036) passes.

Also I've created and added to the tests a minimal repro of the code
llvm#89036 fails on. This
(obviously) also passes.
bricknerb pushed a commit to bricknerb/llvm-project that referenced this issue Oct 17, 2024
The [last attempt](llvm#89036) to
fix llvm#41441 has been reverted
immediately.

Here I'm trying the simplest idea I've been able to come with: skip
handling dependent case in `BuildCXXNew`.

The original test (borrowed form
llvm#89036) passes.

Also I've created and added to the tests a minimal repro of the code
llvm#89036 fails on. This
(obviously) also passes.
EricWF pushed a commit to efcs/llvm-project that referenced this issue Oct 22, 2024
The [last attempt](llvm#89036) to
fix llvm#41441 has been reverted
immediately.

Here I'm trying the simplest idea I've been able to come with: skip
handling dependent case in `BuildCXXNew`.

The original test (borrowed form
llvm#89036) passes.

Also I've created and added to the tests a minimal repro of the code
llvm#89036 fails on. This
(obviously) also passes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bugzilla Issues migrated from bugzilla c++ clang:frontend Language frontend issues, e.g. anything involving "Sema" confirmed Verified by a second party
Projects
None yet
7 participants