parser icon indicating copy to clipboard operation
parser copied to clipboard

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

Open henng opened this issue 6 years ago • 2 comments

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?

[email protected]

henng avatar Oct 12 '19 08:10 henng

Made a try to fix this, see #577

henng avatar Oct 12 '19 08:10 henng

Just a ping, @henng may you update https://github.com/pingcap/parser/pull/577 please?

bb7133 avatar Oct 29 '20 14:10 bb7133