This is an archive of the discontinued LLVM Phabricator instance.

[dataflow] Disallow implicit copy of Environment, use fork() instead
ClosedPublic

Authored by sammccall on Jun 23 2023, 5:45 PM.

Details

Summary

Environments are heavyweight, and copies are observably different from the
original: they introduce new SAT variables, which degrade performance &
debugging. Copies should only be done deliberately, where justified.

Empirically there are several places in the framework where we perform dubious
copies, sometimes entirely accidentally. (see e.g. D153491). Making these
explicit makes this mistake harder.

This patch forces copies to go through fork(), the copy-constructor is private.
This requires changes to existing callsites: some are correct and call fork(),
some are incorrect and are fixed, others are difficult and I left a FIXME.

Diff Detail

Event Timeline

sammccall created this revision.Jun 23 2023, 5:45 PM
Herald added a project: Restricted Project. · View Herald Transcript
Herald added a subscriber: martong. · View Herald Transcript
sammccall requested review of this revision.Jun 23 2023, 5:45 PM
Herald added a project: Restricted Project. · View Herald TranscriptJun 23 2023, 5:45 PM
Herald added a subscriber: cfe-commits. · View Herald Transcript
sammccall added inline comments.Jun 23 2023, 5:52 PM
clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h
211

these copies shouldn't be happening (or if we're really going to do them, PostVisitCFG should get the env by value!)

However I think fixing it means changing the signature of PostVisitCFG...

228

with auto&& this fails to compile, complaining about the copy constructor being deleted.

Not sure exactly what's going on - maybe the wrong overload of transformOptional is called for some reason.

In any case, I'm fairly sure we were accidentally copying here.

clang/lib/Analysis/FlowSensitive/Transfer.cpp
868

this looks like it was an accidental copy

clang/unittests/Analysis/FlowSensitive/TestingSupport.h
366

this seems legitimate to me: the only way to preserve the Environment from halfway through a BB is to fork it

gribozavr2 accepted this revision.Jun 23 2023, 5:53 PM
This revision is now accepted and ready to land.Jun 23 2023, 5:53 PM
xazax.hun accepted this revision.Jun 26 2023, 12:54 AM

Nice, looks like this change did catch some unintentional copies! Already paying dividends :)

This revision was landed with ongoing or failed builds.Jun 26 2023, 6:26 AM
This revision was automatically updated to reflect the committed changes.

Hi, there is a compiling error introduced recently as like following when files under clang/lib/Analysis/FlowSensitive/ are being compiled such as TypeErasedDataflowAnalysis.cpp and Transfer.cpp. Does anybody meet also?

from /usr/include/c++/7/functional:60,
from /iothome/wuzx/workspace/master-csky/clang/unittests/Analysis/FlowSensitive/TestingSupport.h:16,
from /iothome/wuzx/workspace/master-csky/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp:9:

/usr/include/c++/7/optional:453:11: note: ‘std::optional<clang::dataflow::DataflowAnalysisState<clang::dataflow::NoopLattice> >::optional(const std::optional<clang::dataflow::DataflowAnalysisState<clang::dataflow::NoopLattice> >&)’ is implicitly deleted because the default definition would be ill-formed:

class optional
      ^~~~~~~~

/usr/include/c++/7/optional:453:11: error: use of deleted function ‘constexpr std::_Enable_copy_move<false, false, true, true, _Tag>::_Enable_copy_move(const std::_Enable_copy_move<false, false, true, true, _Tag>&) [with _Tag = std::optional<clang::dataflow::DataflowAnalysisState<clang::dataflow::NoopLattice> >]’
In file included from /usr/include/c++/7/optional:43:0,

from /usr/include/c++/7/bits/node_handle.h:39,
from /usr/include/c++/7/bits/hashtable.h:37,
from /usr/include/c++/7/unordered_map:47,
from /usr/include/c++/7/functional:60,
from /iothome/wuzx/workspace/master-csky/clang/unittests/Analysis/FlowSensitive/TestingSupport.h:16,
from /iothome/wuzx/workspace/master-csky/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp:9:

/usr/include/c++/7/bits/enable_special_members.h:157:15: note: declared here

constexpr _Enable_copy_move(_Enable_copy_move const&) noexcept  = delete;
          ^~~~~~~~~~~~~~~~~

In file included from /usr/include/c++/7

The gcc version is gcc (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0.

Hi, sorry about that - are you able to provide a full log, or link to a
failing bot?
That error message doesn't show where in the LLVM code the error occurs.

Hi, sorry about that - are you able to provide a full log, or link to a
failing bot?
That error message doesn't show where in the LLVM code the error occurs.

It can pass with gcc 8. And I can upload the .i file.

g++ error.i -std=c++17
In file included from /usr/include/c++/7/memory:64:0,

from /iothome/wuzx/workspace/llvm-comm/llvm/include/llvm/Support/Casting.h:20,
from /iothome/wuzx/workspace/llvm-comm/clang/include/clang/Basic/LLVM.h:21,
from /iothome/wuzx/workspace/llvm-comm/clang/include/clang/Basic/DiagnosticIDs.h:17,
from /iothome/wuzx/workspace/llvm-comm/clang/include/clang/Basic/IdentifierTable.h:18,
from /iothome/wuzx/workspace/llvm-comm/clang/include/clang/AST/Stmt.h:20,
from /iothome/wuzx/workspace/llvm-comm/clang/include/clang/Analysis/FlowSensitive/Transfer.h:17,
from /iothome/wuzx/workspace/llvm-comm/clang/lib/Analysis/FlowSensitive/Transfer.cpp:14:

/usr/include/c++/7/bits/stl_construct.h: In instantiation of ‘void std::_Construct(_T1*, _Args&& ...) [with _T1 = std::optional<clang::dataflow::DataflowAnalysisState<clang::dataflow::NoopLattice> >; _Args = {const std::optional<clang::dataflow::DataflowAnalysisState<clang::dataflow::NoopLattice> >&}]’:
/usr/include/c++/7/bits/stl_uninitialized.h:83:18: required from ‘static _ForwardIterator std::uninitialized_copy<_TrivialValueTypes>::uninit_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = gnu_cxx::normal_iterator<const std::optional<clang::dataflow::DataflowAnalysisState<clang::dataflow::NoopLattice> >*, std::vector<std::optional<clang::dataflow::DataflowAnalysisState<clang::dataflow::NoopLattice> >, std::allocator<std::optional<clang::dataflow::DataflowAnalysisState<clang::dataflow::NoopLattice> > > > >; _ForwardIterator = std::optional<clang::dataflow::DataflowAnalysisState<clang::dataflow::NoopLattice> >*; bool _TrivialValueTypes = false]’
/usr/include/c++/7/bits/stl_uninitialized.h:134:15: required from ‘_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = gnu_cxx::normal_iterator<const std::optional<clang::dataflow::DataflowAnalysisState<clang::dataflow::NoopLattice> >*, std::vector<std::optional<clang::dataflow::DataflowAnalysisState<clang::dataflow::NoopLattice> >, std::allocator<std::optional<clang::dataflow::DataflowAnalysisState<clang::dataflow::NoopLattice> > > > >; _ForwardIterator = std::optional<clang::dataflow::DataflowAnalysisState<clang::dataflow::NoopLattice> >*]’
/usr/include/c++/7/bits/stl_uninitialized.h:289:37: required from ‘_ForwardIterator std::uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, std::allocator<_Tp>&) [with _InputIterator = gnu_cxx::__normal_iterator<const std::optional<clang::dataflow::DataflowAnalysisState<clang::dataflow::NoopLattice> >*, std::vector<std::optional<clang::dataflow::DataflowAnalysisState<clang::dataflow::NoopLattice> >, std::allocator<std::optional<clang::dataflow::DataflowAnalysisState<clang::dataflow::NoopLattice> > > > >; _ForwardIterator = std::optional<clang::dataflow::DataflowAnalysisState<clang::dataflow::NoopLattice> >*; _Tp = std::optional<clang::dataflow::DataflowAnalysisState<clang::dataflow::NoopLattice> >]’
/usr/include/c++/7/bits/stl_vector.h:331:31: required from ‘std::vector<_Tp, _Alloc>::vector(const std::vector<_Tp, _Alloc>&) [with _Tp = std::optional<clang::dataflow::DataflowAnalysisState<clang::dataflow::NoopLattice> >; _Alloc = std::allocator<std::optional<clang::dataflow::DataflowAnalysisState<clang::dataflow::NoopLattice> > >]’
/iothome/wuzx/workspace/llvm-comm/llvm/include/llvm/Support/Error.h:520:5: required from ‘llvm::Expected<T>::Expected(OtherT&&, std::enable_if_t<is_convertible_v<OtherT, T> >*) [with OtherT = std::vector<std::optional<clang::dataflow::DataflowAnalysisState<clang::dataflow::NoopLattice> >, std::allocator<std::optional<clang::dataflow::DataflowAnalysisState<clang::dataflow::NoopLattice> > > >&; T = std::vector<std::optional<clang::dataflow::DataflowAnalysisState<clang::dataflow::NoopLattice> >, std::allocator<std::optional<clang::dataflow::DataflowAnalysisState<clang::dataflow::NoopLattice> > > >; std::enable_if_t<is_convertible_v<OtherT, T> > = void]’
/iothome/wuzx/workspace/llvm-comm/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h:235:10: required from ‘llvm::Expected<std::vector<std::optional<clang::dataflow::DataflowAnalysisState<typename AnalysisT::Lattice> > > > clang::dataflow::runDataflowAnalysis(const clang::dataflow::ControlFlowContext&, AnalysisT&, const clang::dataflow::Environment&, std::function<void(const clang::CFGElement&, const clang::dataflow::DataflowAnalysisState<typename AnalysisT::Lattice>&)>) [with AnalysisT = clang::dataflow::NoopAnalysis; typename AnalysisT::Lattice = clang::dataflow::NoopLattice]’
/iothome/wuzx/workspace/llvm-comm/clang/lib/Analysis/FlowSensitive/Transfer.cpp:871:38: required from ‘void clang::dataflow::{anonymous}::TransferVisitor::transferInlineCall(const E*, const clang::FunctionDecl*) [with E = clang::CXXConstructExpr]’
/iothome/wuzx/workspace/llvm-comm/clang/lib/Analysis/FlowSensitive/Transfer.cpp:625:42: required from here
/usr/include/c++/7/bits/stl_construct.h:75:7: error: use of deleted function ‘std::optional<clang::dataflow::DataflowAnalysisState<clang::dataflow::NoopLattice> >::optional(const std::optional<clang::dataflow::DataflowAnalysisState<clang::dataflow::NoopLattice> >&)’

{ ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }
  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

In file included from /iothome/wuzx/workspace/llvm-comm/llvm/include/llvm/Support/Alignment.h:26:0,

from /iothome/wuzx/workspace/llvm-comm/llvm/include/llvm/Support/TrailingObjects.h:50,
from /iothome/wuzx/workspace/llvm-comm/clang/include/clang/AST/DeclGroup.h:16,
from /iothome/wuzx/workspace/llvm-comm/clang/include/clang/AST/Stmt.h:16,
from /iothome/wuzx/workspace/llvm-comm/clang/include/clang/Analysis/FlowSensitive/Transfer.h:17,
from /iothome/wuzx/workspace/llvm-comm/clang/lib/Analysis/FlowSensitive/Transfer.cpp:14:

/usr/include/c++/7/optional:453:11: note: ‘std::optional<clang::dataflow::DataflowAnalysisState<clang::dataflow::NoopLattice> >::optional(const std::optional<clang::dataflow::DataflowAnalysisState<clang::dataflow::NoopLattice> >&)’ is implicitly deleted because the default definition would be ill-formed:

class optional
      ^~~~~~~~

/usr/include/c++/7/optional:453:11: error: use of deleted function ‘constexpr std::_Enable_copy_move<false, false, true, true, _Tag>::_Enable_copy_move(const std::_Enable_copy_move<false, false, true, true, _Tag>&) [with _Tag = std::optional<clang::dataflow::DataflowAnalysisState<clang::dataflow::NoopLattice> >]’
In file included from /usr/include/c++/7/optional:43:0,

from /iothome/wuzx/workspace/llvm-comm/llvm/include/llvm/Support/Alignment.h:26,
from /iothome/wuzx/workspace/llvm-comm/llvm/include/llvm/Support/TrailingObjects.h:50,
from /iothome/wuzx/workspace/llvm-comm/clang/include/clang/AST/DeclGroup.h:16,
from /iothome/wuzx/workspace/llvm-comm/clang/include/clang/AST/Stmt.h:16,
from /iothome/wuzx/workspace/llvm-comm/clang/include/clang/Analysis/FlowSensitive/Transfer.h:17,
from /iothome/wuzx/workspace/llvm-comm/clang/lib/Analysis/FlowSensitive/Transfer.cpp:14:

/usr/include/c++/7/bits/enable_special_members.h:157:15: note: declared here

constexpr _Enable_copy_move(_Enable_copy_move const&) noexcept  = delete;
          ^~~~~~~~~~~~~~~~~

I'm also using gcc (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0 (which supported according to the LLVM "Getting Started" page) and I see the same std::optional compilation errors. Please revert this commit or fix the build.

Sorry about the delay, and thanks for the .i.

It took me a while to work out what was going on, but it looks like it's just a bug where GCC forgets to automatic-move.
Fixed in 2f7d30dee8262746c3e8ee1f6f25be8c1ace9990

Sorry about the delay, and thanks for the .i.

It took me a while to work out what was going on, but it looks like it's just a bug where GCC forgets to automatic-move.
Fixed in 2f7d30dee8262746c3e8ee1f6f25be8c1ace9990

Thanks a lot.

Thank you for the fix :) !

When I tried to compile with gcc 7.5 after your fix commit (2f7d30dee826), I got another very similar compilation error from a different location and I pushed commit cec30e2b190b to fix that. After this second correction I can successfully run ninja check-clang-analysis with gcc7.5.