Skip to content

Commit 03526e2

Browse files
author
Alex Menkov
committed
8355960: JvmtiAgentList::Iterator dtor double free with -fno-elide-constructors
Reviewed-by: dholmes, sspitsyn
1 parent 1de2ace commit 03526e2

File tree

6 files changed

+48
-60
lines changed

6 files changed

+48
-60
lines changed

src/hotspot/share/jfr/periodic/jfrPeriodic.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,7 @@ static void send_agent_event(AgentEvent& event, const JvmtiAgent* agent) {
291291
}
292292

293293
TRACE_REQUEST_FUNC(JavaAgent) {
294-
const JvmtiAgentList::Iterator it =JvmtiAgentList::java_agents();
294+
JvmtiAgentList::Iterator it = JvmtiAgentList::java_agents();
295295
while (it.has_next()) {
296296
const JvmtiAgent* agent = it.next();
297297
assert(agent->is_jplis(), "invariant");
@@ -300,7 +300,7 @@ TRACE_REQUEST_FUNC(JavaAgent) {
300300
}
301301
}
302302

303-
static void send_native_agent_events(const JvmtiAgentList::Iterator& it) {
303+
static void send_native_agent_events(JvmtiAgentList::Iterator& it) {
304304
while (it.has_next()) {
305305
const JvmtiAgent* agent = it.next();
306306
assert(!agent->is_jplis(), "invariant");
@@ -311,9 +311,9 @@ static void send_native_agent_events(const JvmtiAgentList::Iterator& it) {
311311
}
312312

313313
TRACE_REQUEST_FUNC(NativeAgent) {
314-
const JvmtiAgentList::Iterator native_agents_it = JvmtiAgentList::native_agents();
314+
JvmtiAgentList::Iterator native_agents_it = JvmtiAgentList::native_agents();
315315
send_native_agent_events(native_agents_it);
316-
const JvmtiAgentList::Iterator xrun_agents_it = JvmtiAgentList::xrun_agents();
316+
JvmtiAgentList::Iterator xrun_agents_it = JvmtiAgentList::xrun_agents();
317317
send_native_agent_events(xrun_agents_it);
318318
}
319319
#else // INCLUDE_JVMTI

src/hotspot/share/prims/jvmtiAgent.cpp

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "prims/jvmtiEnvBase.hpp"
3232
#include "prims/jvmtiExport.hpp"
3333
#include "runtime/arguments.hpp"
34+
#include "runtime/atomic.hpp"
3435
#include "runtime/handles.inline.hpp"
3536
#include "runtime/interfaceSupport.inline.hpp"
3637
#include "runtime/java.hpp"
@@ -82,11 +83,7 @@ JvmtiAgent::JvmtiAgent(const char* name, const char* options, bool is_absolute_p
8283
_xrun(false) {}
8384

8485
JvmtiAgent* JvmtiAgent::next() const {
85-
return _next;
86-
}
87-
88-
void JvmtiAgent::set_next(JvmtiAgent* agent) {
89-
_next = agent;
86+
return Atomic::load_acquire(&_next);
9087
}
9188

9289
const char* JvmtiAgent::name() const {

src/hotspot/share/prims/jvmtiAgent.hpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ class JvmtiAgent : public CHeapObj<mtServiceability> {
5252
bool _xrun;
5353

5454
JvmtiAgent* next() const;
55-
void set_next(JvmtiAgent* agent);
5655
void convert_xrun_agent();
5756
void set_xrun();
5857

src/hotspot/share/prims/jvmtiAgentList.cpp

Lines changed: 34 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
#include "runtime/atomic.hpp"
3232
#include "runtime/os.inline.hpp"
3333

34-
JvmtiAgent* JvmtiAgentList::_list = nullptr;
34+
JvmtiAgent* JvmtiAgentList::_head = nullptr;
3535

3636
// Selection as a function of the filter.
3737
JvmtiAgent* JvmtiAgentList::Iterator::select(JvmtiAgent* agent) const {
@@ -61,68 +61,59 @@ JvmtiAgent* JvmtiAgentList::Iterator::select(JvmtiAgent* agent) const {
6161
return nullptr;
6262
}
6363

64-
static inline JvmtiAgent* head(JvmtiAgent** list) {
65-
assert(list != nullptr, "invariant");
66-
return Atomic::load_acquire(list);
67-
}
68-
69-
// The storage list is a single cas-linked-list, to allow for concurrent iterations.
70-
// Especially during initial loading of agents, there exist an order requirement to iterate oldest -> newest.
71-
// Our concurrent storage linked-list is newest -> oldest.
72-
// The correct order is preserved by the iterator, by storing a filtered set of entries in a stack.
73-
JvmtiAgentList::Iterator::Iterator(JvmtiAgent** list, Filter filter) :
74-
_stack(new GrowableArrayCHeap<JvmtiAgent*, mtServiceability>(16)), _filter(filter) {
75-
JvmtiAgent* next = head(list);
76-
while (next != nullptr) {
77-
next = select(next);
78-
if (next != nullptr) {
79-
_stack->push(next);
80-
next = next->next();
81-
}
82-
}
64+
JvmtiAgentList::Iterator::Iterator(JvmtiAgent* head, Filter filter) : _filter(filter), _next(select(head)) {
8365
}
8466

8567
bool JvmtiAgentList::Iterator::has_next() const {
86-
assert(_stack != nullptr, "invariant");
87-
return _stack->is_nonempty();
88-
}
89-
90-
const JvmtiAgent* JvmtiAgentList::Iterator::next() const {
91-
assert(has_next(), "invariant");
92-
return _stack->pop();
68+
return _next != nullptr;
9369
}
9470

9571
JvmtiAgent* JvmtiAgentList::Iterator::next() {
96-
return const_cast<JvmtiAgent*>(const_cast<const Iterator*>(this)->next());
72+
assert(_next != nullptr, "must be");
73+
JvmtiAgent* result = _next;
74+
_next = select(_next->next());
75+
return result;
76+
9777
}
9878

9979
JvmtiAgentList::Iterator JvmtiAgentList::agents() {
100-
return Iterator(&_list, Iterator::NOT_XRUN);
80+
return Iterator(head(), Iterator::NOT_XRUN);
10181
}
10282

10383
JvmtiAgentList::Iterator JvmtiAgentList::java_agents() {
104-
return Iterator(&_list, Iterator::JAVA);
84+
return Iterator(head(), Iterator::JAVA);
10585
}
10686

10787
JvmtiAgentList::Iterator JvmtiAgentList::native_agents() {
108-
return Iterator(&_list, Iterator::NATIVE);
88+
return Iterator(head(), Iterator::NATIVE);
10989
}
11090

11191
JvmtiAgentList::Iterator JvmtiAgentList::xrun_agents() {
112-
return Iterator(&_list, Iterator::XRUN);
92+
return Iterator(head(), Iterator::XRUN);
11393
}
11494

11595
JvmtiAgentList::Iterator JvmtiAgentList::all() {
116-
return Iterator(&_list, Iterator::ALL);
96+
return Iterator(head(), Iterator::ALL);
11797
}
11898

11999
void JvmtiAgentList::add(JvmtiAgent* agent) {
120100
assert(agent != nullptr, "invariant");
121-
JvmtiAgent* next;
122-
do {
123-
next = head(&_list);
124-
agent->set_next(next);
125-
} while (Atomic::cmpxchg(&_list, next, agent) != next);
101+
102+
// address of the pointer to add new agent (&_head when the list is empty or &agent->_next of the last agent in the list)
103+
JvmtiAgent** tail_ptr = &_head;
104+
while (true) {
105+
JvmtiAgent* next = Atomic::load(tail_ptr);
106+
if (next == nullptr) {
107+
// *tail_ptr == nullptr here
108+
if (Atomic::cmpxchg(tail_ptr, (JvmtiAgent*)nullptr, agent) != nullptr) {
109+
// another thread added an agent, reload next from tail_ptr
110+
continue;
111+
}
112+
// successfully set, exit
113+
break;
114+
}
115+
tail_ptr = &next->_next;
116+
}
126117
}
127118

128119
void JvmtiAgentList::add(const char* name, const char* options, bool absolute_path) {
@@ -143,6 +134,10 @@ static void assert_initialized(JvmtiAgentList::Iterator& it) {
143134
}
144135
#endif
145136

137+
JvmtiAgent* JvmtiAgentList::head() {
138+
return Atomic::load_acquire(&_head);
139+
}
140+
146141
// In case an agent did not enable the VMInit callback, or if it is an -Xrun agent,
147142
// it gets an initializiation timestamp here.
148143
void JvmtiAgentList::initialize() {
@@ -283,6 +278,6 @@ void JvmtiAgentList::disable_agent_list() {
283278
assert(CDSConfig::is_dumping_final_static_archive(), "use this only for -XX:AOTMode=create!");
284279
assert(!Universe::is_bootstrapping() && !Universe::is_fully_initialized(), "must do this very early");
285280
log_info(aot)("Disabled all JVMTI agents during -XX:AOTMode=create");
286-
_list = nullptr; // Pretend that no agents have been added.
281+
_head = nullptr; // Pretend that no agents have been added.
287282
#endif
288283
}

src/hotspot/share/prims/jvmtiAgentList.hpp

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,12 @@
2525
#ifndef SHARE_PRIMS_JVMTIAGENTLIST_HPP
2626
#define SHARE_PRIMS_JVMTIAGENTLIST_HPP
2727

28-
#include "nmt/memTag.hpp"
2928
#include "prims/jvmtiAgent.hpp"
30-
#include "utilities/growableArray.hpp"
3129

3230
class JvmtiEnv;
3331

34-
// Maintains a single cas linked-list of JvmtiAgents.
32+
// Maintains thread-safe linked list of JvmtiAgents.
3533
class JvmtiAgentList : AllStatic {
36-
friend class Iterator;
3734
friend class JvmtiExport;
3835
public:
3936
class Iterator {
@@ -46,20 +43,20 @@ class JvmtiAgentList : AllStatic {
4643
NOT_XRUN,
4744
ALL
4845
};
49-
GrowableArrayCHeap<JvmtiAgent*, mtServiceability>* _stack;
5046
const Filter _filter;
51-
Iterator() : _stack(nullptr), _filter(ALL) {}
52-
Iterator(JvmtiAgent** list, Filter filter);
47+
JvmtiAgent* _next;
48+
Iterator(): _filter(ALL), _next(nullptr) {}
49+
Iterator(JvmtiAgent* head, Filter filter);
5350
JvmtiAgent* select(JvmtiAgent* agent) const;
5451
public:
5552
bool has_next() const NOT_JVMTI_RETURN_(false);
5653
JvmtiAgent* next() NOT_JVMTI_RETURN_(nullptr);
57-
const JvmtiAgent* next() const NOT_JVMTI_RETURN_(nullptr);
58-
~Iterator() { delete _stack; }
5954
};
6055

6156
private:
62-
static JvmtiAgent* _list;
57+
static JvmtiAgent* _head;
58+
59+
static JvmtiAgent* head();
6360

6461
static void initialize();
6562
static void convert_xrun_agents();

src/hotspot/share/runtime/os.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1125,7 +1125,7 @@ void os::print_environment_variables(outputStream* st, const char** env_list) {
11251125

11261126
void os::print_jvmti_agent_info(outputStream* st) {
11271127
#if INCLUDE_JVMTI
1128-
const JvmtiAgentList::Iterator it = JvmtiAgentList::all();
1128+
JvmtiAgentList::Iterator it = JvmtiAgentList::all();
11291129
if (it.has_next()) {
11301130
st->print_cr("JVMTI agents:");
11311131
} else {

0 commit comments

Comments
 (0)