示例#1
0
        /// <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, ThreadSafetyInterceptionPoint threadSafetyInterceptionPoint, Dictionary <Guid, HashSet <Trap> > trapObjects, TrapPlan trapPlan, object instance, out bool bugFound)
        {
            int       danger           = -1;
            Semaphore semaphore        = null;
            double    prob             = 1.0;
            int       sleepDuration    = 0;
            Guid      objectId         = interceptionPoint.ObjID;
            bool      continueAfterBug = false;

            bugFound = false;
            Trap newTrap = null;

            lock (trapObjects)
            {
                // Check if a thread-safety bug is found
                if (trapObjects.ContainsKey(objectId))
                {
                    foreach (Trap trap in trapObjects[objectId])
                    {
                        ThreadSafetyInterceptionPoint runningTP = this.GetThreadSafetyInterceptionPoint(trap.InterceptionPoint);
                        if (threadSafetyInterceptionPoint.IsWriteAPI || runningTP.IsWriteAPI)
                        {
                            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))
                {
                    // DebugLog.Log("HIt Bug and exit " + InterceptionPoint.Tostring());
                    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) || threadSafetyInterceptionPoint.IsWriteAPI))
                    {
                        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,
                            };

                            ControllerHelper.WriteTrap(newTrap);

                            if (!trapObjects.ContainsKey(objectId))
                            {
                                trapObjects.Add(objectId, new HashSet <Trap>());
                            }

                            trapObjects[objectId].Add(newTrap);

                            this.isTrapActive = true;
                        }
                    }
                }
            }

            return(newTrap);
        }
        /// <inheritdoc/>
        public void InterceptionPointStart(InterceptionPoint interceptionPoint, object instance = null, object[] parameters = null)
        {
            /*
             * if (!this.isTrapActive && bugFound)
             *  throw new Exception("ThreadSafety bugs detected by Torch");
             */
            bool newTrapsAllowed = true;
            bool newBugFound     = false;

            if (this.configuration == null || this.configuration.ThreadSafetyGroups == null)
            {
                return;
            }

            ThreadSafetyInterceptionPoint threadSafetyInterceptionPoint = ControllerHelper.GetThreadSafetyInterceptionPoint(this.configuration.ThreadSafetyGroups, interceptionPoint);

            if (threadSafetyInterceptionPoint == null)
            {
                return;
            }

            if (!threadSafetyInterceptionPoint.ThreadSafetyGroup.IsStatic && instance == null)
            {
                return;
            }

            string groupName = threadSafetyInterceptionPoint.ThreadSafetyGroup.Name;
            Dictionary <Guid, Trap> trapObjects = null;

            lock (this.trapPoints)
            {
                if (!this.trapPoints.ContainsKey(groupName))
                {
                    this.trapPoints.Add(groupName, new Dictionary <Guid, Trap>());
                    if (threadSafetyInterceptionPoint.IsWriteAPI)
                    {
                        this.writeTrapPoints.Add(groupName);
                    }
                }

                trapObjects = this.trapPoints[groupName];
            }

            Semaphore semaphore     = null;
            int       sleepDuration = 0;
            Guid      keyInstance   = ObjectId.GetRefId(null);

            lock (trapObjects)
            {
                if (!threadSafetyInterceptionPoint.ThreadSafetyGroup.IsStatic)
                {
                    keyInstance = ObjectId.GetRefId(instance);
                }

                // Check if a trap on this object is live
                Trap trap = null;
                trapObjects.TryGetValue(keyInstance, out trap);

                // A bug is found if there is a trap on this object and
                // either this access or trapped access is a write
                if (trap != null &&
                    (threadSafetyInterceptionPoint.IsWriteAPI ||
                     trap.ThreadSafetyInterceptionPoint.IsWriteAPI))
                {
                    // Get stack track when a bug is found.
                    interceptionPoint.StackTrace = Environment.StackTrace;
                    ControllerHelper.WriteBug(trap, interceptionPoint);
                    newBugFound = true;

                    try
                    {
                        trap.Semaphore.Release();
                    }
                    catch (SemaphoreFullException)
                    {
                    }
                }
                else if (newTrapsAllowed)
                {
                    // prepare to set up a trap
                    if (!this.isTrapActive)
                    {
                        if (threadSafetyInterceptionPoint.IsWriteAPI && this.random.NextDouble() <= this.DelayProbability)
                        {
                            // Get stack trace only if setting up a trap.
                            interceptionPoint.StackTrace = Environment.StackTrace;

                            semaphore     = new Semaphore(0, 1);
                            sleepDuration = this.random.Next(this.MaxDelayPerInterceptionPoint);

                            trap = new Trap
                            {
                                ObjectId                      = keyInstance.ToString(),
                                Semaphore                     = semaphore,
                                InterceptionPoint             = interceptionPoint,
                                ThreadSafetyInterceptionPoint = threadSafetyInterceptionPoint,
                                Delay = sleepDuration,
                            };

                            ControllerHelper.WriteTrap(trap);
                            trapObjects.Add(keyInstance, trap);
                            this.isTrapActive = true;
                        }
                    }
                }
            }

            if (semaphore != null)
            {
                semaphore.WaitOne(sleepDuration);

                lock (trapObjects)
                {
                    trapObjects.Remove(keyInstance);
                }

                this.isTrapActive = false;
            }

            if (this.configuration.ThrowExceptionOnRace && newBugFound)
            {
                throw new Exception("ThreadSafety bugs detected by Torch");
            }

            return;
        }