When I compile this program:
#include <list>
int main() {
std::list<int> l = {1, 2};
l.remove(l.front());
}
With clang using ASAN and debug:
clang++-8 -fno-omit-frame-pointer -g -fsanitize=address -D_GLIBCXX_DEBUG -std=c++11 list-remove.cpp
I get a heap-use-after-free
:
==31868==ERROR: AddressSanitizer: heap-use-after-free on address 0x603000000020 at pc 0x0000004fa1ae bp 0x7fff52cc5630 sp 0x7fff52cc5628
READ of size 4 at 0x603000000020 thread T0
#0 0x4fa1ad in std::__debug::list<int, std::allocator<int> >::remove(int const&) /usr/bin/../lib/gcc/x86_64-linux-gnu/7.4.0/../../../../include/c++/7.4.0/debug/list:649:18
#1 0x4f990f in main /tmp/list-remove.cpp:5:7
#2 0x7ff27d974b96 in __libc_start_main /build/glibc-OTsEL5/glibc-2.27/csu/../csu/libc-start.c:310
#3 0x41b879 in _start (/tmp/list-remove+0x41b879)
It seems when remove
finds x
matches the first element, it removes the element from the list and deletes it. When it goes to check the second element, it then uses x
which has already been deleted to compare the element.
Is this a correct implementation according to C++ standard? It seems it would be better for it to move the elements to the end first and then delete them. This will avoid the heap-use-after-free
error, but perhaps such an implementation is not required.
From cppreference it makes no mention that the value
cannot be an alias to the element in the container.
Here is the c++ version I am using:
$ /usr/bin/c++ --version
c++ (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.