Bug 64329 - Crash when returning reference from lambda with deduced type
Summary: Crash when returning reference from lambda with deduced type
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 4.9.1
: P3 normal
Target Milestone: 4.9.3
Assignee: Not yet assigned to anyone
URL:
Keywords: c++-lambda, wrong-code
Depends on:
Blocks: lambdas
  Show dependency treegraph
 
Reported: 2014-12-16 12:03 UTC by Will Benfold
Modified: 2022-03-11 00:32 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Known to work: 5.1.0, 6.0
Known to fail: 4.9.3
Last reconfirmed: 2016-04-16 00:00:00


Attachments
Preprocessed source (92.44 KB, text/plain)
2014-12-16 12:03 UTC, Will Benfold
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Will Benfold 2014-12-16 12:03:36 UTC
Created attachment 34289 [details]
Preprocessed source

I believe the program below is valid and correct, but I see heap corruption at the end of main() (in  std::map::~map) when I allow the compiler to deduce return type of the lambda. 

Both the parameters to apply() are still alive when the returned lambda is invoked, so fn(arg) should safely return a valid const ref to a tuple.  If the return type for the lambda is given explicitly (see comments in code) then everything is fine, whether it's returning by value or by const ref.

Compiling with "-Wall --std=c++11 -O0 -g3"; optimisation level seems to make no difference.

----------------------------------------------------------------

#include <functional>
#include <map>
#include <string>
#include <tuple>

typedef std::tuple<std::string, std::string, double> Result;
typedef std::map<int, Result> Argument;
typedef std::function<const Result & (const Argument &)> Function;

std::function<Result ()> apply (const Argument &arg, const Function &fn)
{
  //  No trouble with any of these...
  //  return [&fn, &arg]() -> Result          { return fn(arg); };
  //  return [&fn, &arg]() -> const Result &  { return fn(arg); };
  //  return [&fn, &arg]()                    { Result r = fn(arg); return r; };

  //  But this causes heap corruption
      return [&fn, &arg]()                    { return fn(arg); };
}

const Result &func (const Argument &arg)
{
  //  std::map::at returns a const ref
  return arg.at(0);
}

int main (int argc, char *argv[])
{
  Argument arg;
  arg[0] = Result("", "a", 0);

  Function f = &func;
  auto g = apply(arg, f);
  g();
  return 0;
}

----------------------------------------------------------------

Using built-in specs.
COLLECT_GCC=/software/thirdparty/gcc/4.9.1-0.el6_64/bin/g++
COLLECT_LTO_WRAPPER=/software/thirdparty/gcc/4.9.1-0.el6_64/libexec/gcc/x86_64-unknown-linux-gnu/4.9.1/lto-wrapper
Target: x86_64-unknown-linux-gnu
Configured with: ../configure --prefix=/software/thirdparty/gcc/4.9.1-0.el6_64 --with-system-zlib --enable-shared --enable-threads=posix --enable-laguages=all --with-ppl --with-cloog --disable-multilib
Thread model: posix
gcc version 4.9.1 (GCC)
Comment 1 Michael Stahl 2016-04-15 16:20:33 UTC
i believe i've hit the same problem, here's the footgun reproducer i came up with:



#include <functional>
#include <cstdio>

int foo = 42;

int const& bar()
{   
    return foo;
}

int main()
{   
    std::function<int const& ()> f{ [] () { return bar(); } };
    int const& rfoo = f();
    printf("%p %p\n", (void*)&foo, (void*)&rfoo);
    return &foo == &rfoo;
}


this is g++ (GCC) 5.3.1 20160406 (Red Hat 5.3.1-6)

> g++ -std=c++11 -Wall -Wextra -pedantic -Weffc++ -W lambdaref.cc  && ./a.out 
0x60204c (nil)


the problem is that the deduced return type of the lambda is a value
type, never a reference type.  this caught me by surprise, but it's
the same rule as for "auto".

if the C++ committee has to make surprising and error-prone type
inference rules, then at least implementations like g++ could
give a warning about returning a reference from a lambda that
is implicitly copied to a value, only to be implicitly converted
again into nothing.

Visual Studio 2013 gives a "warning C4172 returning address of local
variable or temporary" from somewhere inside its std::function code.
Comment 2 Jonathan Wakely 2016-04-15 16:39:42 UTC
(In reply to Michael Stahl from comment #1)
> i believe i've hit the same problem

I don't think so. The original bug report is for 4.9.3, and seems to be an actual compiler bug that is fixed already in GCC 5 and later.

Your case is invalid code. While I agree a warning would be nice, it's not the same as a bug in 4.9.3 that has been fixed.
Comment 3 Jonathan Wakely 2016-04-15 16:41:27 UTC
Oops, the original report was for 4.9.1, but the bug is still present in 4.9.3
Comment 4 Jonathan Wakely 2016-04-16 13:18:15 UTC
Confirming the original report, which is a real bug.


N.B. for the different issue in comment 1, G++ will warn but only with -Wsystem-headers, because the problem is inside the <functional> header:

/home/jwakely/gcc/6/include/c++/6.0.0/functional:1726:40: warning: returning reference to temporary [-Wreturn-local-addr]
      std::forward<_ArgTypes>(__args)...);
                                        ^
Comment 5 Jonathan Wakely 2016-04-16 13:30:45 UTC
(In reply to Jonathan Wakely from comment #2)
> (In reply to Michael Stahl from comment #1)
> > i believe i've hit the same problem
> 
> I don't think so. The original bug report is for 4.9.3, and seems to be an
> actual compiler bug that is fixed already in GCC 5 and later.
> 
> Your case is invalid code. While I agree a warning would be nice, it's not
> the same as a bug in 4.9.3 that has been fixed.

I've created PR 70692 for the missing warning on the invalid code, since it's a different problem to the one in this PR.
Comment 6 Marek Polacek 2019-06-18 21:15:33 UTC
I can't reproduce the original ICE with either version.
Comment 7 Eric Gallager 2019-11-30 18:25:43 UTC
(In reply to Jonathan Wakely from comment #5)
> (In reply to Jonathan Wakely from comment #2)
> > (In reply to Michael Stahl from comment #1)
> > > i believe i've hit the same problem
> > 
> > I don't think so. The original bug report is for 4.9.3, and seems to be an
> > actual compiler bug that is fixed already in GCC 5 and later.
> > 
> > Your case is invalid code. While I agree a warning would be nice, it's not
> > the same as a bug in 4.9.3 that has been fixed.
> 
> I've created PR 70692 for the missing warning on the invalid code, since
> it's a different problem to the one in this PR.

ah right, I think this just reminded me of a bug whose number I was trying to remember for a different bug...
Comment 8 Jason Merrill 2019-12-19 14:20:52 UTC
Closing as fixed long ago.