Skip to content

Commit dc8d45f

Browse files
author
Chris Elder
committed
[FAB-3555] Peer panic on SIGSEV connecting to CouchDB
A peer panic was encountered connecting to CouchDB on peer startup. This occurred in the code after multiple retries. The panic was caused by a null pointer when attempting to read the status code from an http return object. The http return object was already checked for an error. The situation causing the null pointer can only be caused if the golang http return has a nil for both the response and the error. According to golang spec this is not possible. An additional check is being made to ensure a good error message is returned from the CouchDB connection request. Change-Id: I13740a32231d49faf3a6acf7b37f7bc6e4bba3fa Signed-off-by: Chris Elder <[email protected]>
1 parent f5dbbaf commit dc8d45f

File tree

2 files changed

+47
-0
lines changed

2 files changed

+47
-0
lines changed

core/ledger/util/couchdb/couchdb.go

+25
Original file line numberDiff line numberDiff line change
@@ -1223,6 +1223,10 @@ func (couchInstance *CouchInstance) handleRequest(method, connectURL string, dat
12231223
//set initial wait duration for retries
12241224
waitDuration := retryWaitTime * time.Millisecond
12251225

1226+
if maxRetries < 1 {
1227+
return nil, nil, fmt.Errorf("Number of retries must be greater than zero.")
1228+
}
1229+
12261230
//attempt the http request for the max number of retries
12271231
for attempts := 0; attempts < maxRetries; attempts++ {
12281232

@@ -1285,6 +1289,11 @@ func (couchInstance *CouchInstance) handleRequest(method, connectURL string, dat
12851289
//Execute http request
12861290
resp, errResp = couchInstance.client.Do(req)
12871291

1292+
//check to see if the return from CouchDB is valid
1293+
if invalidCouchDBReturn(resp, errResp) {
1294+
continue
1295+
}
1296+
12881297
//if there is no golang http error and no CouchDB 500 error, then drop out of the retry
12891298
if errResp == nil && resp != nil && resp.StatusCode < 500 {
12901299
break
@@ -1329,6 +1338,14 @@ func (couchInstance *CouchInstance) handleRequest(method, connectURL string, dat
13291338
return nil, nil, errResp
13301339
}
13311340

1341+
//This situation should not occur according to the golang spec.
1342+
//if this error returned (errResp) from an http call, then the resp should be not nil,
1343+
//this is a structure and StatusCode is an int
1344+
//This is meant to provide a more graceful error if this should occur
1345+
if invalidCouchDBReturn(resp, errResp) {
1346+
return nil, nil, fmt.Errorf("Unable to connect to CouchDB, check the hostname and port.")
1347+
}
1348+
13321349
//set the return code for the couchDB request
13331350
couchDBReturn.StatusCode = resp.StatusCode
13341351

@@ -1364,6 +1381,14 @@ func (couchInstance *CouchInstance) handleRequest(method, connectURL string, dat
13641381
return resp, couchDBReturn, nil
13651382
}
13661383

1384+
//invalidCouchDBResponse checks to make sure either a valid response or error is returned
1385+
func invalidCouchDBReturn(resp *http.Response, errResp error) bool {
1386+
if resp == nil && errResp == nil {
1387+
return true
1388+
}
1389+
return false
1390+
}
1391+
13671392
//IsJSON tests a string to determine if a valid JSON
13681393
func IsJSON(s string) bool {
13691394
var js map[string]interface{}

core/ledger/util/couchdb/couchdb_test.go

+22
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,28 @@ func TestDBTimeoutConflictRetry(t *testing.T) {
594594
}
595595
}
596596

597+
func TestDBBadNumberOfRetries(t *testing.T) {
598+
599+
if ledgerconfig.IsCouchDBEnabled() {
600+
601+
database := "testdbbadretries"
602+
err := cleanup(database)
603+
testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to cleanup Error: %s", err))
604+
defer cleanup(database)
605+
606+
// if there was an error upon cleanup, return here
607+
if err != nil {
608+
return
609+
}
610+
611+
//create a new instance and database object
612+
_, err = CreateCouchInstance(couchDBDef.URL, couchDBDef.Username, couchDBDef.Password,
613+
0, 3, couchDBDef.RequestTimeout)
614+
testutil.AssertError(t, err, fmt.Sprintf("Error should have been thrown while attempting to create a database"))
615+
616+
}
617+
}
618+
597619
func TestDBBadJSON(t *testing.T) {
598620

599621
if ledgerconfig.IsCouchDBEnabled() {

0 commit comments

Comments
 (0)