/// <summary> /// Checks for bugs and start trap. /// </summary> /// <param name="interceptionPoint">The InterceptionPoint.</param> /// <param name="threadSafetyInterceptionPoint">The thread safety InterceptionPoint.</param> /// <param name="trapObjects">The trap objects.</param> /// <param name="trapPlan">The trap plan.</param> /// <param name="instance">The instance.</param> /// <param name="bugFound">If set to <see langword="true" /> then a bug has been found.</param> /// <returns>Trap.</returns> private Trap CheckForBugsAndStartTrap(InterceptionPoint interceptionPoint, string groupName, Dictionary <string, HashSet <Trap> > trapObjects, TrapPlan trapPlan, object instance, out bool bugFound) { int danger = -1; Semaphore semaphore = null; double prob = 1.0; int sleepDuration = 0; string objectId = interceptionPoint.ObjID; bool continueAfterBug = false; bugFound = false; Trap newTrap = null; lock (trapObjects) { // Check if a thread-safety bug is found from random torch if (trapObjects.ContainsKey(objectId)) { foreach (Trap trap in trapObjects[objectId]) { //ThreadSafetyInterceptionPoint runningTP = this.GetThreadSafetyInterceptionPoint(trap.InterceptionPoint); if (interceptionPoint.IsWrite || trap.InterceptionPoint.IsWrite) { bugFound = true; interceptionPoint.StackTrace = Environment.StackTrace; // DebugLog.Log("HitBug " + InterceptionPoint.Tostring() + " " + runningt.InterceptionPoint.Tostring()); ControllerHelper.WriteBug(trap, interceptionPoint); this.LogBugForNextRun(interceptionPoint, trap.InterceptionPoint); // For some InterceptionPoints, keep execution even hitting a bug. It may expose more bugs. if ((trapPlan != null) && (!trapPlan.Repeat)) { continueAfterBug = true; } } } } if (bugFound && (!continueAfterBug)) { return(null); } // else { // check if the InterceptionPoint match with dangerous list danger = this.IsInsideDangerList(interceptionPoint.Location); if ((danger < 0) && (!interceptionPoint.IsInPlan)) { // exit when not matching and not in the plan return(null); } // prepare to set up a trap if (threadSafetyInterceptionPoint.IsWriteAPI && !this.isTrapActive) if ((!this.isTrapActive || (danger >= 0) || interceptionPoint.IsInPlan) && ((trapPlan != null) || interceptionPoint.IsWrite)) { prob = trapPlan != null ? trapPlan.DelayProbability : this.DelayProbability; if (danger >= 0) { prob = this.DelayProbabilityAtDangerousInterceptionPoint - (this.DecayFactor * danger); } if (this.random.NextDouble() <= prob) { // Get stack trace only if setting up a trap. interceptionPoint.StackTrace = Environment.StackTrace; semaphore = new Semaphore(0, 1); sleepDuration = trapPlan == null? this.random.Next(this.MaxDelayPerInterceptionPoint) : trapPlan.FixedDelayMs; if (danger >= 0) { sleepDuration = this.DelayPerDangerousInterceptionPoint; } newTrap = new Trap { ObjectId = objectId, Semaphore = semaphore, InterceptionPoint = interceptionPoint, Delay = sleepDuration, }; if (!trapObjects.ContainsKey(objectId)) { trapObjects.Add(objectId, new HashSet <Trap>()); } trapObjects[objectId].Add(newTrap); this.isTrapActive = true; } } } } return(newTrap); }
/// <summary> /// Converts to rchpointstart. /// </summary> /// <param name="interceptionPoint">The InterceptionPoint.</param> /// <param name="instance">The instance.</param> /// <param name="parameters">The parameters.</param> /// <inheritdoc /> public void InterceptionPointStart(InterceptionPoint interceptionPoint, object instance = null, object[] parameters = null) { /* * I add more field variables to help the analysis. They are initialized in the constructor. * when hitting a new InterceptionPoint here are the procedures in the implementation: * 1.assign the hit-seq for InterceptionPoint * 2.assign the global id for InterceptionPoint. It is duplicated with InterceptionPoint.id. * 3.update the InterceptionPoints history to infer the concurrent threads. * 4.find the dangerous pair for this InterceptionPoint * 5.find the the opeartion set that happens-before this InterceptionPoint * 6.check if find a bug * 7.construct the trap * 8.execute the trap * 9.locate the threads that are blocked by this trap */ var newBugFound = false; if (this.configuration == null || this.configuration.ThreadSafetyGroups == null) { return; } this.UpdateTPHitCounts(interceptionPoint); TrapPlan trapPlan = this.TrapPlans.FindMatchingPlan(interceptionPoint, this.GlobalHitcountWindow, this.LocalHitcountWindow); interceptionPoint.IsInPlan = trapPlan != null; this.UpdateTPHistory(interceptionPoint); // Locate the APIs bypass the lock operation //ThreadSafetyInterceptionPoint threadSafetyInterceptionPoint = this.GetThreadSafetyInterceptionPoint(interceptionPoint); //if (threadSafetyInterceptionPoint == null || // (!threadSafetyInterceptionPoint.ThreadSafetyGroup.IsStatic && instance == null)) //{ // return; //} // update the write/read InterceptionPoint //interceptionPoint.IsWrite = threadSafetyInterceptionPoint.IsWriteAPI; //interceptionPoint.ObjID = threadSafetyInterceptionPoint.ThreadSafetyGroup.IsStatic ? ObjectId.GetRefId(null) : ObjectId.GetRefId(instance); // this block will looking for the near-miss pair and learn the dependency. if ((interceptionPoint.IsInPlan == false) && (this.DetectDangerousPairs == true)) { this.FindRacingTP(interceptionPoint); this.RemoveDependentInterceptionPoints(interceptionPoint); } var trapObjects = this.GetTrapObjects(interceptionPoint.GroupName); Trap trap = this.CheckForBugsAndStartTrap(interceptionPoint, interceptionPoint.GroupName, trapObjects, trapPlan, instance, out newBugFound); if (trap == null) { return; } this.FinishTrap(trapObjects, trap, interceptionPoint); if (this.configuration.ThrowExceptionOnRace & newBugFound) { throw new Exception("ThreadSafety bugs detected by Torch"); } return; }