Skip to content
This repository was archived by the owner on Oct 23, 2024. It is now read-only.

Commit 42d4f6b

Browse files
author
James DeFelice
committed
conn: fix racy access to result fields when connection is closing
1 parent 449c45a commit 42d4f6b

File tree

1 file changed

+38
-1
lines changed

1 file changed

+38
-1
lines changed

zk/conn.go

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1009,7 +1009,17 @@ func (c *Conn) queueRequest(opcode int32, req interface{}, res interface{}, recv
10091009

10101010
func (c *Conn) request(opcode int32, req interface{}, res interface{}, recvFunc func(*request, *responseHeader, error)) (int64, error) {
10111011
r := <-c.queueRequest(opcode, req, res, recvFunc)
1012-
return r.zxid, r.err
1012+
select {
1013+
case <-c.shouldQuit:
1014+
// queueRequest() can be racy, double-check for the race here and avoid
1015+
// a potential data-race. otherwise the client of this func may try to
1016+
// access `res` fields concurrently w/ the async response processor.
1017+
// NOTE: callers of this func should check for (at least) ErrConnectionClosed
1018+
// and avoid accessing fields of the response object if such error is present.
1019+
return -1, ErrConnectionClosed
1020+
default:
1021+
return r.zxid, r.err
1022+
}
10131023
}
10141024

10151025
func (c *Conn) AddAuth(scheme string, auth []byte) error {
@@ -1045,6 +1055,9 @@ func (c *Conn) Children(path string) ([]string, *Stat, error) {
10451055

10461056
res := &getChildren2Response{}
10471057
_, err := c.request(opGetChildren2, &getChildren2Request{Path: path, Watch: false}, res, nil)
1058+
if err == ErrConnectionClosed {
1059+
return nil, nil, err
1060+
}
10481061
return res.Children, &res.Stat, err
10491062
}
10501063

@@ -1073,6 +1086,9 @@ func (c *Conn) Get(path string) ([]byte, *Stat, error) {
10731086

10741087
res := &getDataResponse{}
10751088
_, err := c.request(opGetData, &getDataRequest{Path: path, Watch: false}, res, nil)
1089+
if err == ErrConnectionClosed {
1090+
return nil, nil, err
1091+
}
10761092
return res.Data, &res.Stat, err
10771093
}
10781094

@@ -1102,6 +1118,9 @@ func (c *Conn) Set(path string, data []byte, version int32) (*Stat, error) {
11021118

11031119
res := &setDataResponse{}
11041120
_, err := c.request(opSetData, &SetDataRequest{path, data, version}, res, nil)
1121+
if err == ErrConnectionClosed {
1122+
return nil, err
1123+
}
11051124
return &res.Stat, err
11061125
}
11071126

@@ -1112,6 +1131,9 @@ func (c *Conn) Create(path string, data []byte, flags int32, acl []ACL) (string,
11121131

11131132
res := &createResponse{}
11141133
_, err := c.request(opCreate, &CreateRequest{path, data, acl, flags}, res, nil)
1134+
if err == ErrConnectionClosed {
1135+
return "", err
1136+
}
11151137
return res.Path, err
11161138
}
11171139

@@ -1180,6 +1202,9 @@ func (c *Conn) Exists(path string) (bool, *Stat, error) {
11801202

11811203
res := &existsResponse{}
11821204
_, err := c.request(opExists, &existsRequest{Path: path, Watch: false}, res, nil)
1205+
if err == ErrConnectionClosed {
1206+
return false, nil, err
1207+
}
11831208
exists := true
11841209
if err == ErrNoNode {
11851210
exists = false
@@ -1220,6 +1245,9 @@ func (c *Conn) GetACL(path string) ([]ACL, *Stat, error) {
12201245

12211246
res := &getAclResponse{}
12221247
_, err := c.request(opGetAcl, &getAclRequest{Path: path}, res, nil)
1248+
if err == ErrConnectionClosed {
1249+
return nil, nil, err
1250+
}
12231251
return res.Acl, &res.Stat, err
12241252
}
12251253
func (c *Conn) SetACL(path string, acl []ACL, version int32) (*Stat, error) {
@@ -1229,6 +1257,9 @@ func (c *Conn) SetACL(path string, acl []ACL, version int32) (*Stat, error) {
12291257

12301258
res := &setAclResponse{}
12311259
_, err := c.request(opSetAcl, &setAclRequest{Path: path, Acl: acl, Version: version}, res, nil)
1260+
if err == ErrConnectionClosed {
1261+
return nil, err
1262+
}
12321263
return &res.Stat, err
12331264
}
12341265

@@ -1239,6 +1270,9 @@ func (c *Conn) Sync(path string) (string, error) {
12391270

12401271
res := &syncResponse{}
12411272
_, err := c.request(opSync, &syncRequest{Path: path}, res, nil)
1273+
if err == ErrConnectionClosed {
1274+
return "", err
1275+
}
12421276
return res.Path, err
12431277
}
12441278

@@ -1274,6 +1308,9 @@ func (c *Conn) Multi(ops ...interface{}) ([]MultiResponse, error) {
12741308
}
12751309
res := &multiResponse{}
12761310
_, err := c.request(opMulti, req, res, nil)
1311+
if err == ErrConnectionClosed {
1312+
return nil, err
1313+
}
12771314
mr := make([]MultiResponse, len(res.Ops))
12781315
for i, op := range res.Ops {
12791316
mr[i] = MultiResponse{Stat: op.Stat, String: op.String, Error: op.Err.toError()}

0 commit comments

Comments
 (0)