Bug #6548
closedwt3: data race and other oddities during WFileUpload
0%
Description
Hi,
We have been seeing std::string related segfaults during WFileUploads
in our Wt (3.3.8) with Qt (5.7.x) app.
I believe I've traced the problem down to a data race between two
threads over the HTTP request ParameterMap.
The first thread is updating the ParameterMap in
Request::parseFormUrlEncoded
- this seems to happen
for every block of data received during the upload -
you can see the 4 ParameterMap vectors growing in size
during the upload:
void Request::parseFormUrlEncoded(const std::string& s,
ParameterMap& parameters)
{
for (std::size_t pos = 0; pos < s.length();) {
std::size_t next = s.find_first_of("&=", pos);
if (next == std::string::npos || s[next] == '&') {
if (next == std::string::npos)
next = s.length();
std::string key = s.substr(pos, next - pos);
Utils::inplaceUrlDecode(key);
parameters[key].push_back(std::string());
pos = next + 1;
} else {
std::size_t amp = s.find('&', next + 1);
if (amp == std::string::npos)
amp = s.length();
std::string key = s.substr(pos, next - pos);
Utils::inplaceUrlDecode(key);
std::string value = s.substr(next + 1, amp - (next + 1));
Utils::inplaceUrlDecode(value);
parameters[key].push_back(value); // << thread 3 here, key=="rand"
pos = amp + 1;
}
}
}
Meanwhile, thread 4 is accessing the same ParameterMap in
Wt::WebController::updateResourceProgress
:
460 void WebController::updateResourceProgress(WebRequest *request,
461 boost::uintmax_t current,
462 boost::uintmax_t total)
463 {
464 WApplication *app = WApplication::instance();
465
466 const std::string *requestE = request->getParameter("request");
467
468 WResource *resource = 0;
469 if (!requestE && !request->pathInfo().empty())
470 resource = app->decodeExposedResource("/path/" + request->pathInfo());
471
472 if (!resource) {
473 const std::string *resourceE = request->getParameter("resource");
* 474 resource = app->decodeExposedResource(*resourceE);
475 }
The segfault occurs because resourceE
no longer points to a
valid std::string
.
The call to request->getParameter
in line 473 succeeded, but
we're racing with thread 3, which has since pushed another value
onto the "resource" parameter vector, causing it to be realloc'd
elsewhere.
The memory that *resourceE
points at appears to have been reused.
You can see this clearly in the attached screenshot, which shows
the request->parameters_
map vector sizes at the point of the
segfault.
In summary:
- We have a data-race on the request parameters map between two
threads. Could we be misusing the library, or does this look
like a Wt bug? I don't see any protection around the
ParameterMap, and it's clear to me who really "owns" it. - The current
parseFormUrlEncoded
behaviour seems undesirable
regardless. I was able to mitigate the effects of the race
in our project by patching it to only append parameter values
that are new/unique - thereby avoiding the realloc entirely.
I hope I've explained this clearly enough.
Let me know if you'd like me to provide any more information.
Chris.
Files
Updated by Chris Sykes over 6 years ago
- File request.parameters.png request.parameters.png added
Updated by Chris Sykes over 6 years ago
My impression is that, in our implementation, the synchonisation between WQApplication
and WServer
isn't working as intended.
When these crashes occur, the updateResourceProgress
call is running in the QThread
/ WQApplication
context, and parseFormUrlEncoded
from the WServer
's thread pool.
If I reduce the WServer
thread pool count down to 1 (from 2):
- The
WProgressBar
we add to ourWFileUpload
now works properly, updating incrementally during the upload. With a thread count of 2, the progress bar would often stall during the upload, then zoom up to 100% when the upload completed. - The upload is quite a bit slower (presumably because everthing's now getting serialised through a single thread?)
- I cannot (yet) reproduce the crash.
Updated by Chris Sykes about 6 years ago
- File upload-recreate.tar.gz upload-recreate.tar.gz added
I've managed to reproduce the crash using a small demo app (attached).
Steps to reproduce, assuming an out-of-tree build dir at ../build-upload-recreate/
From the source dir:
- Run the demo app:
upload-recreate $ ./run ../build-upload-recreate/upload-recreate
- Connect to http://127.0.0.1:8080/
- Upload files until you hit the race/crash (took me 6 attempts using a 135MiB file).
Stack traces for the competing threads:
Thread 6:
1 std::string::compare(std::string const&) const 0x7ffff579415a
2 std::operator< <char, std::char_traits<char>, std::allocator<char>> basic_string.h 6088 0x7ffff5e41398
3 std::less<std::string>::operator() stl_function.h 386 0x7ffff5e41398
4 std::_Rb_tree<std::string, std::pair<std::string const, Wt::WResource *>, std::_Select1st<std::pair<std::string const, Wt::WResource *>>, std::less<std::string>, std::allocator<std::pair<std::string const, Wt::WResource *>>>::_M_lower_bound stl_tree.h 1888 0x7ffff5e41398
5 std::_Rb_tree<std::string, std::pair<std::string const, Wt::WResource *>, std::_Select1st<std::pair<std::string const, Wt::WResource *>>, std::less<std::string>, std::allocator<std::pair<std::string const, Wt::WResource *>>>::find stl_tree.h 2536 0x7ffff5e41398
6 std::map<std::string, Wt::WResource *>::find stl_map.h 1189 0x7ffff5e41398
7 Wt::WApplication::decodeExposedResource WApplication.C 857 0x7ffff5e41398
8 Wt::WebController::updateResourceProgress WebController.C 474 0x7ffff6267c08
9 boost::function0<void>::operator() function_template.hpp 759 0x7ffff627a8ac
10 Wt::WebSession::notify WebSession.C 2215 0x7ffff627a8ac
11 Wt::WQApplication::realNotify WQApplication.C 109 0x47f2dd
12 Wt::DispatchThread::doEvent DispatchThread.C 163 0x47c064
13 Wt::DispatchObject::onEvent DispatchThread.C 44 0x47b954
14 Wt::DispatchObject::qt_static_metacall moc_DispatchThread.cpp 79 0x47fcb7
15 QObject::event qobject.cpp 1247 0x7ffff79ae35a
16 doNotify qcoreapplication.cpp 1099 0x7ffff7984bea
17 QCoreApplication::notifyInternal2 qcoreapplication.cpp 1024 0x7ffff7984cd7
18 QCoreApplication::sendEvent qcoreapplication.h 233 0x7ffff798745b
19 QCoreApplicationPrivate::sendPostedEvents qcoreapplication.cpp 1699 0x7ffff798745b
20 QCoreApplication::sendPostedEvents qcoreapplication.cpp 1553 0x7ffff7987978
...
Thread 5:
1 _int_malloc malloc.c 3733 0x7ffff4dd410c
2 __GI___libc_malloc malloc.c 3066 0x7ffff4dd602d
3 operator new(unsigned long) 0x7ffff56fc668
4 std::string::_M_construct<const char *> basic_string.tcc 219 0x7ffff6264f8f
5 std::string::_M_construct_aux<char *> basic_string.h 236 0x7ffff6266673
6 std::string::_M_construct<char *> basic_string.h 255 0x7ffff6266673
7 std::string::basic_string basic_string.h 440 0x7ffff6266673
8 Wt::ApplicationEvent::ApplicationEvent(std::string const&, boost::function<void ()> const&, boost::function<void ()> const&) WebController.h 69 0x7ffff6266673
9 Wt::WebController::requestDataReceived WebController.C 449 0x7ffff6266673
10 http::server::WtReply::consumeRequestBody WtReply.C 191 0x7ffff67b36ac
11 http::server::WtReply::consumeData WtReply.C 145 0x7ffff67b43e9
12 http::server::RequestParser::parseBody RequestParser.C 214 0x7ffff6776087
13 http::server::Connection::handleReadBody Connection.C 297 0x7ffff674c1e5
14 http::server::Connection::handleReadBody Connection.C 375 0x7ffff674ca6f
15 boost::_mfi::mf3<void, http::server::Connection, boost::shared_ptr<http::server::Reply>, boost::system::error_code const&, unsigned long>::call<boost::shared_ptr<http::server::TcpConnection>, boost::shared_ptr<http::server::Reply>, boost::system::error_code const, unsigned long> mem_fn_template.hpp 384 0x7ffff67ac719
16 boost::_mfi::mf3<void, http::server::Connection, boost::shared_ptr<http::server::Reply>, boost::system::error_code const&, unsigned long>::operator()<boost::shared_ptr<http::server::TcpConnection>> mem_fn_template.hpp 399 0x7ffff67ac719
17 boost::_bi::list4<boost::_bi::value<boost::shared_ptr<http::server::TcpConnection>>, boost::_bi::value<boost::shared_ptr<http::server::Reply>>, boost::arg<1> ( *)(), boost::arg<2> ( *)()>::operator()<boost::_mfi::mf3<void, http::server::Connection, boost::shared_ptr<http::server::Reply>, boost::system::error_code const&, unsigned long>, boost::_bi::rrlist2<boost::system::error_code const&, unsigned long const&>> bind.hpp 463 0x7ffff67ac719
18 boost::_bi::bind_t<void, boost::_mfi::mf3<void, http::server::Connection, boost::shared_ptr<http::server::Reply>, boost::system::error_code const&, unsigned long>, boost::_bi::list4<boost::_bi::value<boost::shared_ptr<http::server::TcpConnection>>, boost::_bi::value<boost::shared_ptr<http::server::Reply>>, boost::arg<1> ( *)(), boost::arg<2> ( *)()>>::operator()<boost::system::error_code const&, unsigned long const&> bind.hpp 1318 0x7ffff67ac719
19 boost::asio::detail::binder2<boost::_bi::bind_t<void, boost::_mfi::mf3<void, http::server::Connection, boost::shared_ptr<http::server::Reply>, boost::system::error_code const&, unsigned long>, boost::_bi::list4<boost::_bi::value<boost::shared_ptr<http::server::TcpConnection>>, boost::_bi::value<boost::shared_ptr<http::server::Reply>>, boost::arg<1> ( *)(), boost::arg<2> ( *)()>>, boost::system::error_code, unsigned long>::operator() bind_handler.hpp 127 0x7ffff67ac719
20 boost::asio::asio_handler_invoke<boost::asio::detail::binder2<boost::_bi::bind_t<void, boost::_mfi::mf3<void, http::server::Connection, boost::shared_ptr<http::server::Reply>, boost::system::error_code const&, unsigned long>, boost::_bi::list4<boost::_bi::value<boost::shared_ptr<http::server::TcpConnection>>, boost::_bi::value<boost::shared_ptr<http::server::Reply>>, boost::arg<1> ( *)(), boost::arg<2> ( *)()>>, boost::system::error_code, unsigned long>> handler_invoke_hook.hpp 69 0x7ffff67ac719
...
Updated by Chris Sykes about 6 years ago
Reproduced with Wt 3.3.11 (debug build):
#0 0x00007ffff37ced77 in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::rfind(char, unsigned long) const () from /lib64/libstdc++.so.6
#1 0x00007ffff519d620 in Wt::WApplication::decodeExposedResource (this=0x7fffd0004b90, resourceKey="") at /mnt/work/tmp/wt/wt/src/Wt/WApplication.C:891
#2 0x00007ffff5861a83 in Wt::WebController::updateResourceProgress (this=0x6ce860, request=0x7fffd0004410, current=384459, total=254129634)
at /mnt/work/tmp/wt/wt/src/web/WebController.C:474
#3 0x00007ffff586998d in boost::_mfi::mf3<void, Wt::WebController, Wt::WebRequest*, unsigned long, unsigned long>::operator() (this=0x7fffd802cf70, p=0x6ce860, a1=0x7fffd0004410,
a2=384459, a3=254129634) at /usr/include/boost/bind/mem_fn_template.hpp:393
#4 0x00007ffff58694fa in boost::_bi::list4<boost::_bi::value<Wt::WebController*>, boost::_bi::value<Wt::WebRequest*>, boost::_bi::value<unsigned long>, boost::_bi::value<unsigned long> >::operator()<boost::_mfi::mf3<void, Wt::WebController, Wt::WebRequest*, unsigned long, unsigned long>, boost::_bi::list0> (this=0x7fffd802cf80, f=..., a=...)
at /usr/include/boost/bind/bind.hpp:463
#5 0x00007ffff5868b5b in boost::_bi::bind_t<void, boost::_mfi::mf3<void, Wt::WebController, Wt::WebRequest*, unsigned long, unsigned long>, boost::_bi::list4<boost::_bi::value<Wt::WebController*>, boost::_bi::value<Wt::WebRequest*>, boost::_bi::value<unsigned long>, boost::_bi::value<unsigned long> > >::operator() (this=0x7fffd802cf70) at /usr/include/boost/bind/bind.hpp:1294
#6 0x00007ffff5868426 in boost::detail::function::void_function_obj_invoker0<boost::_bi::bind_t<void, boost::_mfi::mf3<void, Wt::WebController, Wt::WebRequest*, unsigned long, unsigned long>, boost::_bi::list4<boost::_bi::value<Wt::WebController*>, boost::_bi::value<Wt::WebRequest*>, boost::_bi::value<unsigned long>, boost::_bi::value<unsigned long> > >, void>::invoke (
function_obj_ptr=...) at /usr/include/boost/function/function_template.hpp:159
#7 0x00007ffff66bae8c in boost::function0<void>::operator() (this=0x7fffe5da3a70) at /usr/include/boost/function/function_template.hpp:759
#8 0x00007ffff58859d5 in Wt::WebSession::notify (this=0x7fffe0004430, event=...) at /mnt/work/tmp/wt/wt/src/web/WebSession.C:2221
#9 0x00007ffff51a0e36 in Wt::WApplication::notify (this=0x7fffd0004b90, e=...) at /mnt/work/tmp/wt/wt/src/Wt/WApplication.C:1533
#10 0x000000000047f34d in Wt::WQApplication::realNotify (this=0x7fffd0004b90, e=...) at /mnt/work/tmp/wt/upload-recreate/upload-recreate/WQApplication.C:109
#11 0x000000000047c0d4 in Wt::DispatchThread::doEvent (this=0x7fffd000cde0) at /mnt/work/tmp/wt/upload-recreate/upload-recreate/DispatchThread.C:163
#12 0x000000000047b9c4 in Wt::DispatchObject::onEvent (this=0x7fffd4003ce0) at /mnt/work/tmp/wt/upload-recreate/upload-recreate/DispatchThread.C:44
#13 0x000000000047fd27 in Wt::DispatchObject::qt_static_metacall (_o=0x7fffd4003ce0, _c=QMetaObject::InvokeMetaMethod, _id=1, _a=0x7fffdc06e6b0)
at /mnt/work/tmp/wt/upload-recreate/build-upload-recreate-Default/upload-recreate_autogen/EWIEGA46WW/moc_DispatchThread.cpp:79
#14 0x00007ffff79ae35a in QObject::event (this=0x7fffd4003ce0, e=<optimized out>) at kernel/qobject.cpp:1247
#15 0x00007ffff7984bea in doNotify (receiver=<optimized out>, event=<optimized out>) at kernel/qcoreapplication.cpp:1099
(gdb) frame 2
#2 0x00007ffff5861a83 in Wt::WebController::updateResourceProgress (this=0x6ce860, request=0x7fffd0004410, current=384459, total=254129634)
at /mnt/work/tmp/wt/wt/src/web/WebController.C:474
(gdb) p request->parameters_
$2 = std::map with 4 elements = {["rand"] = std::vector of length 146, capacity 256 = {"39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39",
"39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39",
"39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39",
"39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39",
"39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39", "39",
"39", "39", "39", "39", "39", "39", "39", "39", "39"}, ["request"] = std::vector of length 146, capacity 256 = {"resource", "resource", "resource", "resource", "resource", "resource",
"resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource",
"resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource",
"resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource",
"resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource",
"resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource",
"resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource",
"resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource",
"resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource",
"resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource", "resource",
"resource", "resource", "resource", "resource", "resource"}, ["resource"] = std::vector of length 146, capacity 256 = {"otubari", "otubari", "otubari", "otubari", "otubari", "otubari",
"otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari",
"otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari",
"otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari",
"otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari",
"otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari",
"otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari",
"otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari",
"otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari",
"otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari", "otubari"},
["wtd"] = std::vector of length 146, capacity 256 = {"Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk",
"Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk",
"Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk",
"Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk",
"Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk",
"Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk",
"Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk",
"Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk",
"Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk",
"Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk", "Aj9kJTz3oDhv5Nsk",
... snipped ...
It looks like resourceE no longer points to a valid std::string
:
(gdb) p resourceE
$3 = (const std::__cxx11::string *) 0x7fffd80481f0
(gdb) p *resourceE
$4 = ""
(gdb) p resourceE->_M_string_length
$5 = 140736817268512
140736817268512
== 0x7fffd8000720
.
(gdb) x/8xb 0x7fffd8000720
0x7fffd8000720: 0x70 0xac 0x00 0xd8 0xff 0x7f 0x00 0x00
(gdb) x/1xg 0x7fffd8000720
0x7fffd8000720: 0x00007fffd800ac70
Updated by Roel Standaert about 4 years ago
- Description updated (diff)
- Status changed from New to Resolved
- Target version set to 4.5.0
I pushed a commit that should normally resolve this issue.
Updated by Roel Standaert almost 4 years ago
- Status changed from Resolved to Closed