Skip to content

Fix nil pointer dereference when a failing sub-status has no message - #174

Open
Axisflow wants to merge 1 commit into
apache:mainfrom
Axisflow:fix/nil-message-in-verify-successes
Open

Fix nil pointer dereference when a failing sub-status has no message#174
Axisflow wants to merge 1 commit into
apache:mainfrom
Axisflow:fix/nil-message-in-verify-successes

Conversation

@Axisflow

Copy link
Copy Markdown

What

Guard the optional TSStatus.Message in verifySuccesses (client/utils.go) so a
failing sub-status without a message no longer panics inside the client.

Problem

TSStatus.Message is optional in the Thrift IDL, so a server may return a failing
sub-status carrying only a code. verifySuccesses dereferences it unconditionally:

// client/utils.go
func verifySuccesses(statuses []*common.TSStatus) error {
	buff := bytes.Buffer{}
	for _, status := range statuses {
		if status.Code != SuccessStatus && status.Code != RedirectionRecommend {
			buff.WriteString(*status.Message + ";")   // panics when Message is nil
		}
	}
	...

So a MULTIPLE_ERROR response whose sub-statuses have no messages crashes the
caller with invalid memory address or nil pointer dereference, inside the client
rather than as a returned error. Every Insert* path reaches this through
VerifySuccess, so a batch insert is enough to trigger it.

VerifySuccess, a few lines below in the same file, already guards the envelope
message the same way:

	if status.Code != SuccessStatus {
		msg := ""
		if status.Message != nil {
			msg = *status.Message
		}
		return &ExecutionError{Code: status.Code, Message: msg}
	}

which is what makes the missing guard in verifySuccesses look like an oversight
rather than a deliberate assumption.

Present on main, on dev/1.3, and in the released v1.3.7 and v2.0.8.

Fix

Fall back to the status code when no message is supplied, so the returned
BatchError still identifies which sub-status failed instead of contributing an
empty entry:

			if status.Message != nil {
				buff.WriteString(*status.Message)
				buff.WriteString(";")
			} else {
				fmt.Fprintf(&buff, "error code: %d;", status.Code)
			}

BatchError.GetStatuses() is unchanged, so callers that inspect the per-tablet
statuses themselves are unaffected.

Verification

Reproduced and verified locally against a MULTIPLE_ERROR whose failing
sub-status carries only a code:

  • without this change, VerifySuccess panics with
    runtime error: invalid memory address or nil pointer dereference
  • with it, the call returns a *BatchError whose message names the failing code
    and whose GetStatuses() still holds the full sub-status slice

go build ./..., go vet ./client/ and go test ./client/ pass. make generate
was not run locally (it needs the thrift toolchain); this change does not touch the
generated code.

No test is included in this PR to keep it to the one-line guard. I have the
reproducing test (a MULTIPLE_ERROR with a message-less sub-status, which panics
without the fix) and am happy to add it here or in a follow-up if you would like it
in the suite.

Please also cherry-pick to dev/1.3

The same line is present on dev/1.3 and shipped in v1.3.7, so a fix that lands
only on main will not reach users on the 1.3 line.

TSStatus.Message is optional in the Thrift IDL, so a failing sub-status can
arrive without one. verifySuccesses dereferenced it unconditionally:

    if status.Code != SuccessStatus && status.Code != RedirectionRecommend {
        buff.WriteString(*status.Message + ";")
    }

so a MULTIPLE_ERROR whose sub-statuses carry only codes panics inside the
client, on a response the server is allowed to send. VerifySuccess already
guards the envelope message a few lines below, which is what makes the missing
guard here look like an oversight rather than an assumption.

Fall back to the status code when no message is supplied, so the returned
BatchError still identifies which sub-status failed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant