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

deliberately illegal use-after-destroy in llvm/lib/IR/User.cpp #24952

Open
llvmbot opened this issue Aug 25, 2015 · 7 comments
Open

deliberately illegal use-after-destroy in llvm/lib/IR/User.cpp #24952

llvmbot opened this issue Aug 25, 2015 · 7 comments
Labels
bugzilla Issues migrated from bugzilla code-quality llvm:core

Comments

@llvmbot
Copy link
Collaborator

llvmbot commented Aug 25, 2015

Bugzilla Link 24578
Version unspecified
OS Linux
Reporter LLVM Bugzilla Contributor
CC @eugenis,@morehouse

Extended Description

The test lvm/llvm/test:Transforms/ScalarRepl/sroa-fca.ll.test fails when running it with -fsanitize-memory-use-after-dtor, and environment option MSAN_OPTIONS=poison_in_dtor=1

Invalid access of member HasHungOffUses in definition of operator delete for user. The member is inherited from llvm::Value. During test execution, the destructor of some llvm::Value instance is invoked, and poisons its own memory. The later destruction of the User instance fails when it attempts to access the inherited member.

@eugenis
Copy link
Contributor

eugenis commented Aug 25, 2015

To put it simply, operator delete for class User inspects memory of the object after the end of its lifetime. This shows as a use-after-dtor error when running under MemorySanitizer.

There is a similar problem with operator delete for MDNode.

This needs to be fixed or suppressed before we enable use-after-dtor sanitization on the bootstrap bot.

@morehouse
Copy link
Collaborator

It looks like a potential solution would be to modify User's overloaded new operators to allocate extra memory to store NumUserOperands, HasHungOffUses, and HasDescriptor. Then the overloaded delete can read that extra memory and delete accordingly without touching the memory poisoned by the destructor.

Of course there are performance implications and likely other difficulties that are outside my current level of understanding.

@llvmbot
Copy link
Collaborator Author

llvmbot commented Jan 23, 2018

*** Bug llvm/llvm-bugzilla-archive#36022 has been marked as a duplicate of this bug. ***

@llvmbot
Copy link
Collaborator Author

llvmbot commented Jan 23, 2018

I've been looking at this but I don't have a good solution yet :(

The fact that User objs have stuff -- an array of Uses, or a ptr to a separate Use[] array -- just before it in memory, make it difficult. The trick is knowing where the start of the User's allocation actually is, because operator new allocates extra memory and serves an address after that allocation.

I was hoping the Use[] or Use** could go after the User data but I think that would interfere with subclasses' data.

One thing I did try (which failed) was, like Matt mentioned, stash the needed data in non-poisoned memory. Because it's difficult in User::operator delete to know anything other than where the User* (i.e. the User's this which is being deallocated) address is, simply store the address of the base allocation at this, with something like: new ((void**)this) (void*) (addr), and then read it during operator delete and free it there. No good. Besides adding an additional, (gross) hack, it may introduce another problem, or just exposes some other use-after-free in Value which tries to free its Name.

Some other ideas:

  • Let User have a llvm::SmallVector<Use, 2> for operands. It'll have at most 2 operands in-situ, or if more are needed, they'll live externally to that SmallVector. SmallVector has similar outside-the-C++-object-layout shenanigans, with essentially the same goal: reduce allocations if possible. This would make the layout more predictable, easier to understand, less prone to *-SAN aborts.

@llvmbot
Copy link
Collaborator Author

llvmbot commented Jan 23, 2018

Indeed MDNode has the same pattern and the same issues.

I'll put out another idea then: how about a handful of classes like OwnsFixedStorage<T, N>, OwnsVariableSizedStorage<T>, etc.?

Benefits are:

  • encapsulate the ugly details of memory layout to make classes more readable,
  • make this easy to integrate in other classes that may want this -- DIExpression has a TODO to this effect
  • cut down on redundancy / number of implementations / copypasta
  • written with a focus on being MSAN/ASAN/UBSAN/*-SAN clean -- or at least, one place to fix those bugs.

@llvmbot
Copy link
Collaborator Author

llvmbot commented Jan 29, 2018

There's a class TrailingObjects which is remarkably like this. Except the extra data live after the main object, not before it, in memory.

I'm working on a new class LeadingObjects which will be kind of the counterpart to TrailingObjects but not have all the same kinds of functionality; just parts that I'm factoring out of classes which do this pre-this data thing, like User, MDNode.

@llvmbot
Copy link
Collaborator Author

llvmbot commented Nov 27, 2021

mentioned in issue llvm/llvm-bugzilla-archive#36022

@llvmbot llvmbot transferred this issue from llvm/llvm-bugzilla-archive Dec 10, 2021
thesamesam added a commit that referenced this issue May 13, 2023
LLVM data structures like llvm::User and llvm::MDNode rely on
the value of object storage persisting beyond the lifetime of the
object (#24952).  This is not standard compliant and causes a runtime
crash if LLVM is built with GCC and LTO enabled (#57740).  Until
these issues are fixed, we need to disable dead store eliminations
eliminations based on object lifetime.

Bug: #24952
Bug: #57740
Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106943

Reviewed By: MaskRay, thesamesam, nikic

Differential Revision: https://reviews.llvm.org/D150505
llvmbot pushed a commit to llvm/llvm-project-release-prs that referenced this issue May 13, 2023
LLVM data structures like llvm::User and llvm::MDNode rely on
the value of object storage persisting beyond the lifetime of the
object (#24952).  This is not standard compliant and causes a runtime
crash if LLVM is built with GCC and LTO enabled (#57740).  Until
these issues are fixed, we need to disable dead store eliminations
eliminations based on object lifetime.

Bug: llvm/llvm-project#24952
Bug: llvm/llvm-project#57740
Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106943

Reviewed By: MaskRay, thesamesam, nikic

Differential Revision: https://reviews.llvm.org/D150505

(cherry picked from commit 94f7c96)
thesamesam pushed a commit that referenced this issue May 14, 2023
LLVM data structures like llvm::User and llvm::MDNode rely on
the value of object storage persisting beyond the lifetime of the
object (#24952).  This is not standard compliant and causes a runtime
crash if LLVM is built with GCC and LTO enabled (#57740).  Until
these issues are fixed, we need to disable dead store eliminations
eliminations based on object lifetime.

Bug: #24952
Bug: #57740
Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106943

(This was originally committed as 94f7c96 but
I reverted it in b974991f4c4457a2104b648d9797a0ed438ecc9 to fix authorship.)

Reviewed By: MaskRay, thesamesam, nikic

Differential Revision: https://reviews.llvm.org/D150505

Signed-off-by: Sam James <sam@gentoo.org>
llvmbot pushed a commit to llvm/llvm-project-release-prs that referenced this issue May 14, 2023
LLVM data structures like llvm::User and llvm::MDNode rely on
the value of object storage persisting beyond the lifetime of the
object (#24952).  This is not standard compliant and causes a runtime
crash if LLVM is built with GCC and LTO enabled (#57740).  Until
these issues are fixed, we need to disable dead store eliminations
eliminations based on object lifetime.

Bug: llvm/llvm-project#24952
Bug: llvm/llvm-project#57740
Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106943

(This was originally committed as 94f7c96 but
I reverted it in b974991f4c4457a2104b648d9797a0ed438ecc9 to fix authorship.)

Reviewed By: MaskRay, thesamesam, nikic

Differential Revision: https://reviews.llvm.org/D150505

Signed-off-by: Sam James <sam@gentoo.org>
(cherry picked from commit ce990b5)
thesamesam added a commit that referenced this issue May 14, 2023
This reverts commit ce990b5.

This breaks some build bots - specifically when using GCC to build LLVM and
then -fno-lifetime-dse ends up passed to Clang in some tests like at
https://lab.llvm.org/buildbot/#/builders/139/builds/40594.

Bug: #24952
Bug: #57740

Differential Revision: https://reviews.llvm.org/D150505
thesamesam pushed a commit that referenced this issue May 15, 2023
LLVM data structures like llvm::User and llvm::MDNode rely on
the value of object storage persisting beyond the lifetime of the
object (#24952).  This is not standard compliant and causes a runtime
crash if LLVM is built with GCC and LTO enabled (#57740).  Until
these issues are fixed, we need to disable dead store eliminations
eliminations based on object lifetime.

The previous test issues are fixed by 626849c.

Bug: #24952
Bug: #57740
Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106943

Reviewed By: MaskRay, thesamesam, nikic

Differential Revision: https://reviews.llvm.org/D150505
llvmbot pushed a commit to llvm/llvm-project-release-prs that referenced this issue May 15, 2023
LLVM data structures like llvm::User and llvm::MDNode rely on
the value of object storage persisting beyond the lifetime of the
object (#24952).  This is not standard compliant and causes a runtime
crash if LLVM is built with GCC and LTO enabled (#57740).  Until
these issues are fixed, we need to disable dead store eliminations
eliminations based on object lifetime.

The previous test issues are fixed by 626849c.

Bug: llvm/llvm-project#24952
Bug: llvm/llvm-project#57740
Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106943

Reviewed By: MaskRay, thesamesam, nikic

Differential Revision: https://reviews.llvm.org/D150505

(cherry picked from commit 47f5c54)
tstellar pushed a commit to llvm/llvm-project-release-prs that referenced this issue May 17, 2023
LLVM data structures like llvm::User and llvm::MDNode rely on
the value of object storage persisting beyond the lifetime of the
object (#24952).  This is not standard compliant and causes a runtime
crash if LLVM is built with GCC and LTO enabled (#57740).  Until
these issues are fixed, we need to disable dead store eliminations
eliminations based on object lifetime.

The previous test issues are fixed by 626849c.

Bug: llvm/llvm-project#24952
Bug: llvm/llvm-project#57740
Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106943

Reviewed By: MaskRay, thesamesam, nikic

Differential Revision: https://reviews.llvm.org/D150505

(cherry picked from commit 47f5c54)
@jayfoad jayfoad changed the title deliberately illegal se-after-destroy in llvm/lib/IR/User.cpp deliberately illegal use-after-destroy in llvm/lib/IR/User.cpp May 22, 2023
@MaskRay MaskRay added llvm:core and removed clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Aug 31, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bugzilla Issues migrated from bugzilla code-quality llvm:core
Projects
None yet
Development

No branches or pull requests

5 participants