Skip to content

'bad access: nil dereference' when calling Error()/getMsg() method of type Error in terror/terror.go #576

@henng

Description

@henng

Bug Report

  1. What did you do?
    Debugging a test case in TiDB and stuck in debug mode, see error of 'bad access: nil dereference'

Here's an exactly case:

  • There are some loggings like ddl/ddl.go:588, which calls job.String()
// logutil.BgLogger().Info("[ddl] start DDL job", zap.String("job", job.String()), zap.String("query", job.Query))


func (job *Job) String() string {
	rowCount := job.GetRowCount()
	return fmt.Sprintf("ID:%d, Type:%s, State:%s, SchemaState:%s, SchemaID:%d, TableID:%d, RowCount:%d, ArgLen:%d, start time: %v, Err:%v, ErrCount:%d, SnapshotVersion:%v",
		job.ID, job.Type, job.State, job.SchemaState, job.SchemaID, job.TableID, rowCount, len(job.Args), TSConvert2Time(job.StartTS), job.Error, job.ErrorCount, job.SnapshotVer)
}
  • We can see above, when calling fmt.Sprintf() with job.Error is a nil dereference, it will reach /your_go_root/src/fmt/print.go::printArg(), in this case arg == nil is not true.
func (p *pp) printArg(arg interface{}, verb rune) {
	p.arg = arg
	p.value = reflect.Value{}

	if arg == nil {
		switch verb {
		case 'T', 'v':
			p.fmt.padString(nilAngleString)
		default:
			p.badVerb(verb)
		}
		return
	}
       ......
}
  • Finally, we got /your_go_rootc/src/fmt/print.go::handleMethods(), in this case v or p.arg is a nil dereference cause it's from job.Error, and it is an error type casue job.Error is a pointer of terror.Error, so error occurs when calling v.Error().
switch verb {
	case 'v', 's', 'x', 'X', 'q':
		switch v := p.arg.(type) {
			case error:
				handled = true
				defer p.catchPanic(p.arg, verb, "Error")
				p.fmtString(v.Error(), verb)
				return
                                ......
                }
                ......
}

Here's a simple test case that you can re-produce the error in debug mode:

type ABC struct {
	a int64
	b bool
	c *terror.Error
}

func TestSprintf(t *testing.T) {
	abc := &ABC{c: nil}
	s := fmt.Sprintf("Testing's Err: %v", abc.c)
	println(s)
}
  1. What did you expect to see?

No Errors

  1. What did you see instead?

bad access: nil dereference

  1. What version of TiDB SQL Parser are you using?

parser@v0.0.0-20190923031704-33636bc5e5d6

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions