github.com/lzhfromustc/gofuzz@v0.0.0-20211116160056-151b3108bbd1/runtime/myoracle.go (about)

     1  package runtime
     2  
     3  import "sync/atomic"
     4  
     5  func init() {
     6  	MapChToChanInfo = make(map[interface{}]PrimInfo)
     7  }
     8  
     9  var GlobalEnableOracle = true
    10  
    11  // during benchmark, we don't need to print bugs to stdout
    12  var BoolReportBug = gogetenv("GF_BENCHMARK") != "1"
    13  var BoolDelayCheck = true
    14  
    15  var MuReportBug mutex
    16  
    17  type PrimInfo interface {
    18  	Lock()
    19  	Unlock()
    20  	MapRef() map[*GoInfo]struct{}
    21  	AddGoroutine(*GoInfo)
    22  	RemoveGoroutine(*GoInfo)
    23  	StringDebug() string
    24  	SetMonitor(uint32)
    25  	LoadMonitor() uint32
    26  }
    27  
    28  //// Part 1.1: data struct for each channel
    29  
    30  // ChanInfo is 1-to-1 with every channel. It tracks a list of goroutines that hold the reference to the channel
    31  type ChanInfo struct {
    32  	Chan            *hchan               // Stores the channel. Can be used as ID of channel
    33  	IntBuffer       int                  // The buffer capability of channel. 0 if channel is unbuffered
    34  	MapRefGoroutine map[*GoInfo]struct{} // Stores all goroutines that still hold reference to this channel
    35  	StrDebug        string
    36  	OKToCheck       bool  // Disable oracle for not instrumented channels
    37  	BoolInSDK       bool  // Disable oracle for channels in SDK
    38  	IntFlagFoundBug int32 // Use atomic int32 operations to mark if a bug is reported
    39  	Mu              mutex
    40  	SpecialFlag     int8
    41  	Uint32Monitor   uint32 // Default: 0. When a bug is based on the assumption that this primitive won't execute again, set to 1.
    42  	// When it is 1 and still executed, print information to withdraw bugs containing it
    43  }
    44  
    45  const (
    46  	TimeTicker int8 = 1
    47  )
    48  
    49  type OpType uint8
    50  
    51  const (
    52  	ChSend   OpType = 1
    53  	ChRecv   OpType = 2
    54  	ChClose  OpType = 3
    55  	ChSelect OpType = 4
    56  )
    57  
    58  var MapChToChanInfo map[interface{}]PrimInfo
    59  var MuMapChToChanInfo mutex
    60  
    61  //var DefaultCaseChanInfo = &ChanInfo{}
    62  
    63  var strSDKPath string = gogetenv("GOROOT")
    64  
    65  func PrintSDK() {
    66  	println(strSDKPath)
    67  }
    68  
    69  // Initialize a new ChanInfo with a given channel
    70  func NewChanInfo(ch *hchan) *ChanInfo {
    71  	_, strFile, intLine, _ := Caller(2)
    72  	strLoc := strFile + ":" + Itoa(intLine)
    73  	newChInfo := &ChanInfo{
    74  		Chan:            ch,
    75  		IntBuffer:       int(ch.dataqsiz),
    76  		MapRefGoroutine: make(map[*GoInfo]struct{}),
    77  		StrDebug:        strLoc,
    78  		OKToCheck:       false,
    79  		BoolInSDK:       Index(strLoc, strSDKPath) < 0,
    80  		IntFlagFoundBug: 0,
    81  		SpecialFlag:     0,
    82  	}
    83  	if BoolPrintDebugInfo {
    84  		println("===Debug Info:")
    85  		println("\tMake of a new channel. The creation site is:", strLoc)
    86  		println("\tSDK path is:", strSDKPath, "\tBoolMakeNotInSDK is:", newChInfo.BoolInSDK)
    87  	}
    88  	AddRefGoroutine(newChInfo, CurrentGoInfo())
    89  
    90  	// If this channel is in some special API, set special flag
    91  	//creationFunc := MyCaller(1)
    92  	if Index(strLoc, "time") >= 0 {
    93  		newChInfo.SpecialFlag = TimeTicker
    94  	}
    95  
    96  	return newChInfo
    97  }
    98  
    99  func (chInfo *ChanInfo) StringDebug() string {
   100  	if chInfo == nil {
   101  		return ""
   102  	}
   103  	return chInfo.StrDebug
   104  }
   105  
   106  func (chInfo *ChanInfo) SetMonitor(i uint32) {
   107  	atomic.StoreUint32(&chInfo.Uint32Monitor, i)
   108  }
   109  
   110  func (chInfo *ChanInfo) LoadMonitor() uint32 {
   111  	return atomic.LoadUint32(&chInfo.Uint32Monitor)
   112  }
   113  
   114  func okToCheck(c *hchan) bool {
   115  	if c.chInfo != nil {
   116  		switch c.chInfo.SpecialFlag {
   117  		case TimeTicker:
   118  			return false
   119  		}
   120  	}
   121  	return true
   122  }
   123  
   124  func (chInfo *ChanInfo) Lock() {
   125  	if chInfo == nil {
   126  		return
   127  	}
   128  	lock(&chInfo.Mu)
   129  }
   130  
   131  func (chInfo *ChanInfo) Unlock() {
   132  	if chInfo == nil {
   133  		return
   134  	}
   135  	unlock(&chInfo.Mu)
   136  }
   137  
   138  // Must be called with chInfo.Mu locked
   139  func (chInfo *ChanInfo) MapRef() map[*GoInfo]struct{} {
   140  	if chInfo == nil {
   141  		return make(map[*GoInfo]struct{})
   142  	}
   143  	return chInfo.MapRefGoroutine
   144  }
   145  
   146  // FindChanInfo can retrieve a initialized ChanInfo for a given channel
   147  func FindChanInfo(ch interface{}) *ChanInfo {
   148  	lock(&MuMapChToChanInfo)
   149  	chInfo := MapChToChanInfo[ch]
   150  	unlock(&MuMapChToChanInfo)
   151  	if chInfo == nil {
   152  		return nil
   153  	} else {
   154  		return chInfo.(*ChanInfo)
   155  	}
   156  }
   157  
   158  func LinkChToLastChanInfo(ch interface{}) {
   159  	lock(&MuMapChToChanInfo)
   160  	primInfo := LoadLastPrimInfo()
   161  	MapChToChanInfo[ch] = primInfo
   162  	if chInfo, ok := primInfo.(*ChanInfo); ok {
   163  		chInfo.OKToCheck = true
   164  	}
   165  	unlock(&MuMapChToChanInfo)
   166  }
   167  
   168  // After the creation of a new channel, or at the head of a goroutine that holds a reference to a channel,
   169  // or whenever a goroutine obtains a reference to a channel, call this function
   170  // AddRefGoroutine links a channel with a goroutine, meaning the goroutine holds the reference to the channel
   171  func AddRefGoroutine(chInfo PrimInfo, goInfo *GoInfo) {
   172  	if chInfo == nil || goInfo == nil {
   173  		return
   174  	}
   175  	chInfo.AddGoroutine(goInfo)
   176  	goInfo.AddPrime(chInfo)
   177  }
   178  
   179  func RemoveRefGoroutine(chInfo PrimInfo, goInfo *GoInfo) {
   180  	if chInfo == nil || goInfo == nil {
   181  		return
   182  	}
   183  	chInfo.RemoveGoroutine(goInfo)
   184  	goInfo.RemovePrime(chInfo)
   185  }
   186  
   187  // When this goroutine is checking bug, set goInfo.BitCheckBugAtEnd to be 1
   188  func SetCurrentGoCheckBug() {
   189  	getg().goInfo.SetCheckBug()
   190  }
   191  
   192  func (goInfo *GoInfo) SetCheckBug() {
   193  	atomic.StoreUint32(&goInfo.BitCheckBugAtEnd, 1)
   194  }
   195  
   196  func (goInfo *GoInfo) SetNotCheckBug() {
   197  	atomic.StoreUint32(&goInfo.BitCheckBugAtEnd, 0)
   198  }
   199  
   200  // This means the goroutine mapped with goInfo holds the reference to chInfo.Chan
   201  func (chInfo *ChanInfo) AddGoroutine(goInfo *GoInfo) {
   202  	if chInfo == nil {
   203  		return
   204  	}
   205  	chInfo.Lock()
   206  	if chInfo.MapRefGoroutine == nil {
   207  		chInfo.Unlock()
   208  		return
   209  	}
   210  	chInfo.MapRefGoroutine[goInfo] = struct{}{}
   211  	chInfo.Unlock()
   212  }
   213  
   214  func (chInfo *ChanInfo) RemoveGoroutine(goInfo *GoInfo) {
   215  	if chInfo == nil {
   216  		return
   217  	}
   218  	chInfo.Lock()
   219  	if chInfo.MapRefGoroutine == nil {
   220  		chInfo.Unlock()
   221  		return
   222  	}
   223  	delete(chInfo.MapRefGoroutine, goInfo)
   224  	chInfo.Unlock()
   225  }
   226  
   227  // Only when BoolDelayCheck is true, this struct is used
   228  // CheckEntry contains information needed for a CheckBlockBug
   229  type CheckEntry struct {
   230  	CS              []PrimInfo
   231  	Uint32NeedCheck uint32 // if 0, delete this CheckEntry; if 1, check this CheckEntry
   232  }
   233  
   234  var VecCheckEntry []*CheckEntry
   235  var MuCheckEntry mutex
   236  var FnCheckCount = func(*uint32) {} // this is defined in gooracle/gooracle.go
   237  var PtrCheckCounter *uint32
   238  
   239  func LockCheckEntry() {
   240  	lock(&MuCheckEntry)
   241  }
   242  
   243  func UnlockCheckEntry() {
   244  	unlock(&MuCheckEntry)
   245  }
   246  
   247  func DequeueCheckEntry() *CheckEntry {
   248  	lock(&MuCheckEntry)
   249  	if len(VecCheckEntry) == 0 {
   250  		unlock(&MuCheckEntry)
   251  		return nil
   252  	} else {
   253  		result := VecCheckEntry[0]
   254  		VecCheckEntry = VecCheckEntry[1:]
   255  		unlock(&MuCheckEntry)
   256  		return result
   257  	}
   258  }
   259  
   260  func EnqueueCheckEntry(CS []PrimInfo) *CheckEntry {
   261  	lock(&MuCheckEntry)
   262  
   263  	if len(CS) == 1 {
   264  		if CS[0].StringDebug() == "/data/ziheng/shared/gotest/stubs/etcd/pkg/mod/github.com/prometheus/client_golang@v1.0.0/prometheus/registry.go:266" {
   265  			print()
   266  		}
   267  	}
   268  
   269  	FnCheckCount(PtrCheckCounter)
   270  	newCheckEntry := &CheckEntry{
   271  		CS:              CS,
   272  		Uint32NeedCheck: 1,
   273  	}
   274  	for _, entry := range VecCheckEntry {
   275  		if BoolCheckEntryEqual(entry, newCheckEntry) {
   276  			unlock(&MuCheckEntry)
   277  			return nil // It's OK to return nil
   278  		}
   279  	}
   280  	if BoolDebug {
   281  		if len(CS) == 1 {
   282  			if CS[0].StringDebug() == "/data/ziheng/shared/gotest/stubs/etcd/pkg/mod/github.com/prometheus/client_golang@v1.0.0/prometheus/registry.go:266" {
   283  				print()
   284  			}
   285  		}
   286  		print("Enqueueing:")
   287  		for _, c := range CS {
   288  			print("\t", c.StringDebug())
   289  		}
   290  		println()
   291  	}
   292  
   293  	VecCheckEntry = append(VecCheckEntry, newCheckEntry)
   294  	unlock(&MuCheckEntry)
   295  	return newCheckEntry
   296  }
   297  
   298  func BoolCheckEntryEqual(a, b *CheckEntry) bool {
   299  	if len(a.CS) != len(b.CS) {
   300  		return false
   301  	}
   302  	for _, primInfo1 := range a.CS {
   303  		boolFound := false
   304  		for _, primInfo2 := range b.CS {
   305  			if primInfo2 == primInfo1 {
   306  				boolFound = true
   307  				break
   308  			}
   309  		}
   310  		if boolFound == false {
   311  			return false
   312  		}
   313  	}
   314  	return true
   315  }
   316  
   317  // A blocking bug is detected, if all goroutines that hold the reference to a channel are blocked at an operation of the channel
   318  // finished is true when we are sure that CS doesn't need to be checked again
   319  func CheckBlockBug(CS []PrimInfo) (finished bool) {
   320  	mapCS := make(map[PrimInfo]struct{})
   321  	mapGS := make(map[*GoInfo]struct{}) // all goroutines that hold reference to primitives in mapCS
   322  	finished = false
   323  
   324  	if BoolDebug {
   325  		print("Checking primtives:")
   326  		for _, chI := range CS {
   327  			print("\t", chI.StringDebug())
   328  		}
   329  		println()
   330  	}
   331  
   332  	for _, primI := range CS {
   333  		if primI == (*ChanInfo)(nil) {
   334  			continue
   335  		}
   336  		if chI, ok := primI.(*ChanInfo); ok {
   337  			if chI.OKToCheck == false {
   338  				return true
   339  			}
   340  		}
   341  		if Index(primI.StringDebug(), strSDKPath) >= 0 {
   342  			if BoolDebug {
   343  				println("Abort checking because this prim is in SDK:", primI.StringDebug())
   344  			}
   345  			finished = true
   346  			return
   347  		}
   348  		primI.Lock()
   349  		for goInfo, _ := range primI.MapRef() {
   350  			mapGS[goInfo] = struct{}{}
   351  		}
   352  		primI.Unlock()
   353  		mapCS[primI] = struct{}{}
   354  	}
   355  
   356  	boolAtLeastOneBlocking := false
   357  loopGS:
   358  	if BoolDebug {
   359  		println("Going through mapGS whose length is:", len(mapGS))
   360  	}
   361  	for goInfo, _ := range mapGS {
   362  		if atomic.LoadUint32(&goInfo.BitCheckBugAtEnd) == 1 { // The goroutine is checking bug at the end of unit test
   363  			if BoolDebug {
   364  				println("\tGoID", goInfo.G.goid, "is checking bug at the end of unit test")
   365  			}
   366  			continue
   367  		}
   368  		lock(&goInfo.Mu)
   369  		if len(goInfo.VecBlockInfo) == 0 { // The goroutine is executing non-blocking operations
   370  			if BoolDebug {
   371  				println("\tGoID", goInfo.G.goid, "is executing non-blocking operations")
   372  				println("Aborting checking")
   373  			}
   374  			unlock(&goInfo.Mu)
   375  			return
   376  		}
   377  
   378  		boolAtLeastOneBlocking = true
   379  
   380  		if BoolDebug {
   381  			println("\tGoID", goInfo.G.goid, "is executing blocking operations")
   382  		}
   383  
   384  		for _, blockInfo := range goInfo.VecBlockInfo { // if it is blocked at select, VecBlockInfo contains multiple primitives
   385  
   386  			primI := blockInfo.Prim
   387  			if _, exist := mapCS[primI]; !exist {
   388  				if BoolDebug {
   389  					println("\t\tNot existing prim in CS:", blockInfo.Prim.StringDebug())
   390  				}
   391  				mapCS[primI] = struct{}{} // update CS
   392  				primI.Lock()
   393  				for goInfo, _ := range primI.MapRef() { // update GS
   394  					mapGS[goInfo] = struct{}{}
   395  				}
   396  				primI.Unlock()
   397  				unlock(&goInfo.Mu)
   398  				if BoolDebug {
   399  					println("Goto mapGS loop again")
   400  				}
   401  				goto loopGS // since mapGS is updated, we should run this loop once again
   402  			} else {
   403  				if BoolDebug {
   404  					println("\t\tExisting prim in CS:", blockInfo.Prim.StringDebug())
   405  				}
   406  			}
   407  		}
   408  		unlock(&goInfo.Mu)
   409  	}
   410  
   411  	if boolAtLeastOneBlocking {
   412  		ReportBug(mapCS)
   413  		finished = true
   414  	}
   415  
   416  	return
   417  }
   418  
   419  //func (chInfo *ChanInfo) CheckBlockBug() {
   420  //	if atomic.LoadInt32(&chInfo.intFlagFoundBug) != 0 {
   421  //		return
   422  //	}
   423  //
   424  //	if chInfo.intBuffer == 0 {
   425  //		countRefGo := 0 // Number of goroutines that hold the reference to the channel
   426  //		countBlockAtThisChanGo := 0 // Number of goroutines that are blocked at an operation of this channel
   427  //		f := func(key interface{}, value interface{}) bool {
   428  //			goInfo, _ := key.(*GoInfo)
   429  //
   430  //			boolIsBlock, _ := goInfo.IsBlockAtGivenChan(chInfo)
   431  //			if boolIsBlock {
   432  //				countBlockAtThisChanGo++
   433  //			}
   434  //			countRefGo++
   435  //			return true // continue Range
   436  //		}
   437  //		chInfo.mapRefGoroutine.Range(f)
   438  //
   439  //		if countRefGo == countBlockAtThisChanGo {
   440  //			if countRefGo == 0 {
   441  //				// debug code
   442  //				countRefGo2 := 0 // Number of goroutines that hold the reference to the channel
   443  //				countBlockAtThisChanGo2 := 0 // Number of goroutines that are blocked at an operation of this channel
   444  //				f := func(key interface{}, value interface{}) bool {
   445  //					goInfo, _ := key.(*GoInfo)
   446  //
   447  //					boolIsBlock, _ := goInfo.IsBlockAtGivenChan(chInfo)
   448  //					if boolIsBlock {
   449  //						countBlockAtThisChanGo2++
   450  //					}
   451  //					countRefGo2++
   452  //					return true // continue Range
   453  //				}
   454  //				chInfo.mapRefGoroutine.Range(f)
   455  //				fmt.Print()
   456  //
   457  //				return
   458  //			}
   459  //			ReportBug(chInfo)
   460  //			atomic.AddInt32(&chInfo.intFlagFoundBug, 1)
   461  //		}
   462  //
   463  //	} else { // Buffered channel
   464  //		if reflect.ValueOf(chInfo.Chan).Len() == chInfo.intBuffer { // Buffer is full
   465  //			// Check if all ref goroutines are blocked at send
   466  //			boolAllBlockAtSend := true
   467  //			countRefGo := 0
   468  //			countBlockAtThisChanGo := 0
   469  //			f := func(key interface{}, value interface{}) bool {
   470  //				goInfo, _ := key.(*GoInfo)
   471  //
   472  //				boolIsBlock, strOp := goInfo.IsBlockAtGivenChan(chInfo)
   473  //				if boolIsBlock {
   474  //					countBlockAtThisChanGo++
   475  //				}
   476  //				if strOp != Send {
   477  //					boolAllBlockAtSend = false
   478  //				}
   479  //				countRefGo++
   480  //				return true // continue Range
   481  //			}
   482  //			chInfo.mapRefGoroutine.Range(f)
   483  //
   484  //			if countRefGo == countBlockAtThisChanGo && boolAllBlockAtSend {
   485  //				ReportBug(chInfo)
   486  //				atomic.AddInt32(&chInfo.intFlagFoundBug, 1)
   487  //			}
   488  //
   489  //		} else if reflect.ValueOf(chInfo.Chan).Len() == 0 { // Buffer is empty
   490  //			// Check if all ref goroutines are blocked at receive
   491  //			boolAllBlockAtRecv := true
   492  //			countRefGo := 0
   493  //			countBlockAtThisChanGo := 0
   494  //			f := func(key interface{}, value interface{}) bool {
   495  //				goInfo, _ := key.(*GoInfo)
   496  //
   497  //				boolIsBlock, strOp := goInfo.IsBlockAtGivenChan(chInfo)
   498  //				if boolIsBlock {
   499  //					countBlockAtThisChanGo++
   500  //				}
   501  //				if strOp != Recv {
   502  //					boolAllBlockAtRecv = false
   503  //				}
   504  //				countRefGo++
   505  //				return true // continue Range
   506  //			}
   507  //			chInfo.mapRefGoroutine.Range(f)
   508  //
   509  //			if countRefGo == countBlockAtThisChanGo && boolAllBlockAtRecv {
   510  //				ReportBug(chInfo)
   511  //				atomic.AddInt32(&chInfo.intFlagFoundBug, 1)
   512  //			}
   513  //
   514  //		} else { // Buffer is not full or empty. Then it is not possible to block
   515  //			// do nothing
   516  //		}
   517  //	}
   518  //}
   519  
   520  func ReportBug(mapCS map[PrimInfo]struct{}) {
   521  
   522  	//for chInfo, _ := range mapCS {
   523  	//	atomic.AddInt32(&chInfo.IntFlagFoundBug, 1)
   524  	//}
   525  	//return
   526  	if BoolReportBug == false {
   527  		return
   528  	}
   529  	lock(&MuReportBug)
   530  	print("-----New Blocking Bug:\n")
   531  	print("---Primitive location:\n")
   532  	for primInfo, _ := range mapCS {
   533  		print(primInfo.StringDebug() + "\n")
   534  		primInfo.SetMonitor(1)
   535  	}
   536  	print("---Primitive pointer:\n")
   537  	for primInfo, _ := range mapCS {
   538  		print(FnPointer2String(primInfo) + "\n")
   539  	}
   540  	print("-----End Bug\n")
   541  	unlock(&MuReportBug)
   542  }
   543  
   544  func ReportNonBlockingBug() {
   545  	print("-----New NonBlocking Bug:\n")
   546  	const size = 64 << 10
   547  	buf := make([]byte, size)
   548  	buf = buf[:Stack(buf, false)]
   549  	print("---Stack:\n", string(buf), "\n")
   550  	print("-----End Bug\n")
   551  }
   552  
   553  // Part 1.2 Data structure for waitgroup
   554  
   555  // WgInfo is 1-to-1 with every WaitGroup.
   556  type WgInfo struct {
   557  	WgCounter       uint32
   558  	MapRefGoroutine map[*GoInfo]struct{}
   559  	StrDebug        string
   560  	EnableOracle    bool  // Disable oracle for channels in SDK
   561  	IntFlagFoundBug int32 // Use atomic int32 operations to mark if a bug is reported
   562  	Mu              mutex // Protects MapRefGoroutine
   563  	Uint32Monitor   uint32
   564  }
   565  
   566  func NewWgInfo() *WgInfo {
   567  	_, strFile, intLine, _ := Caller(2)
   568  	strLoc := strFile + ":" + Itoa(intLine)
   569  	wg := &WgInfo{
   570  		WgCounter:       0,
   571  		MapRefGoroutine: make(map[*GoInfo]struct{}),
   572  		StrDebug:        strLoc,
   573  		EnableOracle:    Index(strLoc, strSDKPath) < 0,
   574  		IntFlagFoundBug: 0,
   575  		Mu:              mutex{},
   576  	}
   577  	return wg
   578  }
   579  
   580  func (w *WgInfo) StringDebug() string {
   581  	if w == nil {
   582  		return ""
   583  	}
   584  	return w.StrDebug
   585  }
   586  
   587  func (w *WgInfo) SetMonitor(i uint32) {
   588  	atomic.StoreUint32(&w.Uint32Monitor, i)
   589  }
   590  
   591  func (w *WgInfo) LoadMonitor() uint32 {
   592  	return atomic.LoadUint32(&w.Uint32Monitor)
   593  }
   594  
   595  // FindChanInfo can retrieve a initialized ChanInfo for a given channel
   596  func FindWgInfo(wg interface{}) *WgInfo {
   597  	lock(&MuMapChToChanInfo)
   598  	wgInfo := MapChToChanInfo[wg]
   599  	unlock(&MuMapChToChanInfo)
   600  	return wgInfo.(*WgInfo)
   601  }
   602  
   603  func LinkWgToLastWgInfo(wg interface{}) {
   604  	lock(&MuMapChToChanInfo)
   605  	MapChToChanInfo[wg] = LoadLastPrimInfo()
   606  	unlock(&MuMapChToChanInfo)
   607  }
   608  
   609  func (w *WgInfo) Lock() {
   610  	lock(&w.Mu)
   611  }
   612  
   613  func (w *WgInfo) Unlock() {
   614  	unlock(&w.Mu)
   615  }
   616  
   617  // Must be called with lock
   618  func (w *WgInfo) MapRef() map[*GoInfo]struct{} {
   619  	return w.MapRefGoroutine
   620  }
   621  
   622  // This means the goroutine mapped with goInfo holds the reference to chInfo.Chan
   623  // Must be called when chInfo.Chan.lock is held
   624  func (w *WgInfo) AddGoroutine(goInfo *GoInfo) {
   625  	w.MapRefGoroutine[goInfo] = struct{}{}
   626  }
   627  
   628  // Must be called when chInfo.Chan.lock is held
   629  func (w *WgInfo) RemoveGoroutine(goInfo *GoInfo) {
   630  	delete(w.MapRefGoroutine, goInfo)
   631  }
   632  
   633  func (w *WgInfo) IamBug() {
   634  
   635  }
   636  
   637  // Part 1.3 Data structure for mutex
   638  
   639  // MuInfo is 1-to-1 with every sync.Mutex.
   640  type MuInfo struct {
   641  	MapRefGoroutine map[*GoInfo]struct{}
   642  	StrDebug        string
   643  	EnableOracle    bool  // Disable oracle for channels in SDK
   644  	IntFlagFoundBug int32 // Use atomic int32 operations to mark if a bug is reported
   645  	Mu              mutex // Protects MapRefGoroutine
   646  	Uint32Monitor   uint32
   647  }
   648  
   649  func NewMuInfo() *MuInfo {
   650  	_, strFile, intLine, _ := Caller(2)
   651  	strLoc := strFile + ":" + Itoa(intLine)
   652  	mu := &MuInfo{
   653  		MapRefGoroutine: make(map[*GoInfo]struct{}),
   654  		StrDebug:        strLoc,
   655  		EnableOracle:    Index(strLoc, strSDKPath) < 0,
   656  		IntFlagFoundBug: 0,
   657  		Mu:              mutex{},
   658  	}
   659  	return mu
   660  }
   661  
   662  func (m *MuInfo) StringDebug() string {
   663  	if m == nil {
   664  		return ""
   665  	}
   666  	return m.StrDebug
   667  }
   668  
   669  func (m *MuInfo) SetMonitor(i uint32) {
   670  	atomic.StoreUint32(&m.Uint32Monitor, i)
   671  }
   672  
   673  func (m *MuInfo) LoadMonitor() uint32 {
   674  	return atomic.LoadUint32(&m.Uint32Monitor)
   675  }
   676  
   677  // FindChanInfo can retrieve a initialized ChanInfo for a given channel
   678  func FindMuInfo(mu interface{}) *MuInfo {
   679  	lock(&MuMapChToChanInfo)
   680  	muInfo := MapChToChanInfo[mu]
   681  	unlock(&MuMapChToChanInfo)
   682  	return muInfo.(*MuInfo)
   683  }
   684  
   685  func LinkMuToLastMuInfo(mu interface{}) {
   686  	lock(&MuMapChToChanInfo)
   687  	MapChToChanInfo[mu] = LoadLastPrimInfo()
   688  	unlock(&MuMapChToChanInfo)
   689  }
   690  
   691  func (mu *MuInfo) Lock() {
   692  	lock(&mu.Mu)
   693  }
   694  
   695  func (mu *MuInfo) Unlock() {
   696  	unlock(&mu.Mu)
   697  }
   698  
   699  // Must be called with lock
   700  func (mu *MuInfo) MapRef() map[*GoInfo]struct{} {
   701  	return mu.MapRefGoroutine
   702  }
   703  
   704  // This means the goroutine mapped with goInfo holds the reference to chInfo.Chan
   705  // Must be called when chInfo.Chan.lock is held
   706  func (mu *MuInfo) AddGoroutine(goInfo *GoInfo) {
   707  	mu.MapRefGoroutine[goInfo] = struct{}{}
   708  }
   709  
   710  // Must be called when chInfo.Chan.lock is held
   711  func (mu *MuInfo) RemoveGoroutine(goInfo *GoInfo) {
   712  	delete(mu.MapRefGoroutine, goInfo)
   713  }
   714  
   715  // Part 1.4 Data structure for rwmutex
   716  
   717  // RWMuInfo is 1-to-1 with every sync.RWMutex.
   718  type RWMuInfo struct {
   719  	MapRefGoroutine map[*GoInfo]struct{}
   720  	StrDebug        string
   721  	EnableOracle    bool  // Disable oracle for channels in SDK
   722  	IntFlagFoundBug int32 // Use atomic int32 operations to mark if a bug is reported
   723  	Mu              mutex // Protects MapRefGoroutine
   724  	Uint32Monitor   uint32
   725  }
   726  
   727  func NewRWMuInfo() *RWMuInfo {
   728  	_, strFile, intLine, _ := Caller(2)
   729  	strLoc := strFile + ":" + Itoa(intLine)
   730  	mu := &RWMuInfo{
   731  		MapRefGoroutine: make(map[*GoInfo]struct{}),
   732  		StrDebug:        strLoc,
   733  		EnableOracle:    Index(strLoc, strSDKPath) < 0,
   734  		IntFlagFoundBug: 0,
   735  		Mu:              mutex{},
   736  	}
   737  	return mu
   738  }
   739  
   740  func (m *RWMuInfo) StringDebug() string {
   741  	if m == nil {
   742  		return ""
   743  	}
   744  	return m.StrDebug
   745  }
   746  
   747  func (m *RWMuInfo) SetMonitor(i uint32) {
   748  	atomic.StoreUint32(&m.Uint32Monitor, i)
   749  }
   750  
   751  func (m *RWMuInfo) LoadMonitor() uint32 {
   752  	return atomic.LoadUint32(&m.Uint32Monitor)
   753  }
   754  
   755  // FindChanInfo can retrieve a initialized ChanInfo for a given channel
   756  func FindRWMuInfo(rwmu interface{}) *RWMuInfo {
   757  	lock(&MuMapChToChanInfo)
   758  	muInfo := MapChToChanInfo[rwmu]
   759  	unlock(&MuMapChToChanInfo)
   760  	return muInfo.(*RWMuInfo)
   761  }
   762  
   763  func LinkRWMuToLastRWMuInfo(rwmu interface{}) {
   764  	lock(&MuMapChToChanInfo)
   765  	MapChToChanInfo[rwmu] = LoadLastPrimInfo()
   766  	unlock(&MuMapChToChanInfo)
   767  }
   768  
   769  func (mu *RWMuInfo) Lock() {
   770  	lock(&mu.Mu)
   771  }
   772  
   773  func (mu *RWMuInfo) Unlock() {
   774  	unlock(&mu.Mu)
   775  }
   776  
   777  // Must be called with lock
   778  func (mu *RWMuInfo) MapRef() map[*GoInfo]struct{} {
   779  	return mu.MapRefGoroutine
   780  }
   781  
   782  // This means the goroutine mapped with goInfo holds the reference to chInfo.Chan
   783  // Must be called when chInfo.Chan.lock is held
   784  func (mu *RWMuInfo) AddGoroutine(goInfo *GoInfo) {
   785  	mu.MapRefGoroutine[goInfo] = struct{}{}
   786  }
   787  
   788  // Must be called when chInfo.Chan.lock is held
   789  func (mu *RWMuInfo) RemoveGoroutine(goInfo *GoInfo) {
   790  	delete(mu.MapRefGoroutine, goInfo)
   791  }
   792  
   793  // Part 1.5 Data structure for conditional variable
   794  
   795  // CondInfo is 1-to-1 with every sync.Cond.
   796  type CondInfo struct {
   797  	MapRefGoroutine map[*GoInfo]struct{}
   798  	StrDebug        string
   799  	EnableOracle    bool  // Disable oracle for channels in SDK
   800  	IntFlagFoundBug int32 // Use atomic int32 operations to mark if a bug is reported
   801  	Mu              mutex // Protects MapRefGoroutine
   802  	Uint32Monitor   uint32
   803  }
   804  
   805  func NewCondInfo() *CondInfo {
   806  	_, strFile, intLine, _ := Caller(2)
   807  	strLoc := strFile + ":" + Itoa(intLine)
   808  	cond := &CondInfo{
   809  		MapRefGoroutine: make(map[*GoInfo]struct{}),
   810  		StrDebug:        strLoc,
   811  		EnableOracle:    Index(strLoc, strSDKPath) < 0,
   812  		IntFlagFoundBug: 0,
   813  		Mu:              mutex{},
   814  	}
   815  	return cond
   816  }
   817  
   818  func (c *CondInfo) StringDebug() string {
   819  	if c == nil {
   820  		return ""
   821  	}
   822  	return c.StrDebug
   823  }
   824  
   825  func (c *CondInfo) SetMonitor(i uint32) {
   826  	atomic.StoreUint32(&c.Uint32Monitor, i)
   827  }
   828  
   829  func (c *CondInfo) LoadMonitor() uint32 {
   830  	return atomic.LoadUint32(&c.Uint32Monitor)
   831  }
   832  
   833  // FindChanInfo can retrieve a initialized ChanInfo for a given channel
   834  func FindCondInfo(cond interface{}) *CondInfo {
   835  	lock(&MuMapChToChanInfo)
   836  	condInfo := MapChToChanInfo[cond]
   837  	unlock(&MuMapChToChanInfo)
   838  	return condInfo.(*CondInfo)
   839  }
   840  
   841  func LinkCondToLastCondInfo(cond interface{}) {
   842  	lock(&MuMapChToChanInfo)
   843  	MapChToChanInfo[cond] = LoadLastPrimInfo()
   844  	unlock(&MuMapChToChanInfo)
   845  }
   846  
   847  func (cond *CondInfo) Lock() {
   848  	lock(&cond.Mu)
   849  }
   850  
   851  func (cond *CondInfo) Unlock() {
   852  	unlock(&cond.Mu)
   853  }
   854  
   855  // Must be called with lock
   856  func (cond *CondInfo) MapRef() map[*GoInfo]struct{} {
   857  	return cond.MapRefGoroutine
   858  }
   859  
   860  // This means the goroutine mapped with goInfo holds the reference to chInfo.Chan
   861  // Must be called when chInfo.Chan.lock is held
   862  func (cond *CondInfo) AddGoroutine(goInfo *GoInfo) {
   863  	cond.MapRefGoroutine[goInfo] = struct{}{}
   864  }
   865  
   866  // Must be called when chInfo.Chan.lock is held
   867  func (cond *CondInfo) RemoveGoroutine(goInfo *GoInfo) {
   868  	delete(cond.MapRefGoroutine, goInfo)
   869  }
   870  
   871  //// Part 2.1: data struct for each goroutine
   872  
   873  // GoInfo is 1-to-1 with each goroutine.
   874  // Go language doesn't allow us to acquire the ID of a goroutine, because they want goroutines to be anonymous.
   875  // Normally, Go programmers use runtime.Stack() to print all IDs of all goroutines, but this function is very inefficient
   876  //, since it calls stopTheWorld()
   877  // Currently we use a global atomic int64 to differentiate each goroutine, and a variable currentGo to represent each goroutine
   878  // This is not a good practice because the goroutine need to pass currentGo to its every callee
   879  type GoInfo struct {
   880  	G            *g
   881  	VecBlockInfo []BlockInfo // Nil when normally running. When blocked at an operation of ChanInfo, store
   882  	// one ChanInfo and the operation. When blocked at select, store multiple ChanInfo and
   883  	// operation. Default in select is also also stored in map, which is DefaultCaseChanInfo
   884  	BitCheckBugAtEnd uint32                // 0 when normally running. 1 when this goroutine is checking bug.
   885  	MapPrimeInfo     map[PrimInfo]struct{} // Stores all channels that this goroutine still hold reference to
   886  	Mu               mutex                 // protects VecBlockInfo and MapPrimeInfo
   887  }
   888  
   889  type BlockInfo struct {
   890  	Prim  PrimInfo
   891  	StrOp string
   892  }
   893  
   894  const (
   895  	Send   = "Send"
   896  	Recv   = "Recv"
   897  	Close  = "Close"
   898  	Select = "Select"
   899  
   900  	MuLock   = "MuLock"
   901  	MuUnlock = "MuUnlock"
   902  
   903  	WgWait = "WgWait"
   904  
   905  	CdWait      = "CdWait"
   906  	CdSignal    = "CdSignal"
   907  	CdBroadcast = "CdBroadcast"
   908  )
   909  
   910  // Initialize a GoInfo
   911  func NewGoInfo(goroutine *g) *GoInfo {
   912  	newGoInfo := &GoInfo{
   913  		G:            goroutine,
   914  		VecBlockInfo: []BlockInfo{},
   915  		MapPrimeInfo: make(map[PrimInfo]struct{}),
   916  	}
   917  	return newGoInfo
   918  }
   919  
   920  func CurrentGoInfo() *GoInfo {
   921  	return getg().goInfo
   922  }
   923  
   924  func StoreLastPrimInfo(chInfo PrimInfo) {
   925  	getg().lastPrimInfo = chInfo
   926  }
   927  
   928  func LoadLastPrimInfo() PrimInfo {
   929  	return getg().lastPrimInfo
   930  }
   931  
   932  func CurrentGoID() int64 {
   933  	return getg().goid
   934  }
   935  
   936  // This means the goroutine mapped with goInfo holds the reference to chInfo.Chan
   937  func (goInfo *GoInfo) AddPrime(chInfo PrimInfo) {
   938  	if goInfo.MapPrimeInfo == nil {
   939  		goInfo.MapPrimeInfo = make(map[PrimInfo]struct{})
   940  	}
   941  	goInfo.MapPrimeInfo[chInfo] = struct{}{}
   942  }
   943  
   944  func (goInfo *GoInfo) RemovePrime(chInfo PrimInfo) {
   945  	if goInfo.MapPrimeInfo != nil {
   946  		delete(goInfo.MapPrimeInfo, chInfo)
   947  	}
   948  }
   949  
   950  func CurrentGoAddCh(ch interface{}) {
   951  	lock(&MuMapChToChanInfo)
   952  	chInfo, exist := MapChToChanInfo[ch]
   953  	unlock(&MuMapChToChanInfo)
   954  	if !exist {
   955  		return
   956  	}
   957  	AddRefGoroutine(chInfo, CurrentGoInfo())
   958  }
   959  
   960  // RemoveRef should be called at the end of every goroutine. It will remove goInfo from the reference list of every
   961  // channel it holds the reference to
   962  func (goInfo *GoInfo) RemoveAllRef() {
   963  
   964  	if goInfo.MapPrimeInfo == nil {
   965  		return
   966  	}
   967  	for chInfo, _ := range goInfo.MapPrimeInfo {
   968  		RemoveRefGoroutine(chInfo, goInfo)
   969  		if chInfo == nil {
   970  			continue
   971  		}
   972  		CS := []PrimInfo{chInfo}
   973  		if BoolDelayCheck {
   974  			EnqueueCheckEntry(CS)
   975  		} else {
   976  			CheckBlockBug(CS)
   977  		}
   978  	}
   979  }
   980  
   981  // SetBlockAt should be called before each channel operation, meaning the current goroutine is about to execute that operation
   982  // Note that we check bug in this function, because it's possible for the goroutine to be blocked forever if it execute that operation
   983  // For example, a channel with no buffer is held by a parent and a child.
   984  //              The parent has already exited, but the child is now about to send to that channel.
   985  //              Then now is our only chance to detect this bug, so we call CheckBlockBug()
   986  func (goInfo *GoInfo) SetBlockAt(prim PrimInfo, strOp string) {
   987  	goInfo.VecBlockInfo = append(goInfo.VecBlockInfo, BlockInfo{
   988  		Prim:  prim,
   989  		StrOp: strOp,
   990  	})
   991  }
   992  
   993  // WithdrawBlock should be called after each channel operation, meaning the current goroutine finished execution that operation
   994  // If the operation is select, remember to call this function right after each case of the select
   995  func (goInfo *GoInfo) WithdrawBlock(checkEntry *CheckEntry) {
   996  	goInfo.VecBlockInfo = []BlockInfo{}
   997  	if checkEntry != nil {
   998  		atomic.StoreUint32(&checkEntry.Uint32NeedCheck, 0)
   999  	}
  1000  }
  1001  
  1002  func (goInfo *GoInfo) IsBlock() (boolIsBlock bool, strOp string) {
  1003  	boolIsBlock, strOp = false, ""
  1004  	boolIsSelect := false
  1005  
  1006  	lock(&goInfo.Mu)
  1007  	defer unlock(&goInfo.Mu)
  1008  	if len(goInfo.VecBlockInfo) == 0 {
  1009  		return
  1010  	} else {
  1011  		boolIsBlock = true
  1012  	}
  1013  
  1014  	// Now we compute strOp
  1015  
  1016  	if len(goInfo.VecBlockInfo) > 1 {
  1017  		boolIsSelect = true
  1018  	} else if len(goInfo.VecBlockInfo) == 0 {
  1019  		print("Fatal in GoInfo.IsBlock(): goInfo.VecBlockInfo is not nil but lenth is 0\n")
  1020  	}
  1021  
  1022  	if boolIsSelect {
  1023  		strOp = Select
  1024  	} else {
  1025  		for _, blockInfo := range goInfo.VecBlockInfo { // This loop will be executed only one time, since goInfo.VecBlockInfo's len() is 1
  1026  			strOp = blockInfo.StrOp
  1027  		}
  1028  	}
  1029  
  1030  	return
  1031  }
  1032  
  1033  // This function checks if the goroutine mapped with goInfo is currently blocking at an operation of chInfo.Chan
  1034  // If so, returns true and the string of channel operation
  1035  func (goInfo *GoInfo) IsBlockAtGivenChan(chInfo *ChanInfo) (boolIsBlockAtGiven bool, strOp string) {
  1036  	boolIsBlockAtGiven, strOp = false, ""
  1037  
  1038  	lock(&goInfo.Mu)
  1039  	defer unlock(&goInfo.Mu)
  1040  	if goInfo.VecBlockInfo == nil {
  1041  		return
  1042  	}
  1043  
  1044  	for _, blockInfo := range goInfo.VecBlockInfo {
  1045  		if blockInfo.Prim == chInfo {
  1046  			boolIsBlockAtGiven = true
  1047  			strOp = blockInfo.StrOp
  1048  			break
  1049  		}
  1050  	}
  1051  
  1052  	return
  1053  }