void DoFuzzDecomposedStruct()

in Tpm2Tester/TestSubstrate/TestFuzzer.cs [651:858]


        void DoFuzzDecomposedStruct(FuzzableMember[] fuzzableVals, FuzzStats cmdStat)
        {
            if (fuzzableVals.Length == 0)
            {
                return;
            }

            // Pick up the number of fuzzable values in the decomposed request to
            // actually fuzz. Probability of fuzzing more values decreases.
            int numValsToFuzz = fuzzableVals.Length < 8 ? fuzzableVals.Length : 8;
            double d = Globs.GetRandomDouble();
            double threshold = 0.5;
            for (int i = 1; i < numValsToFuzz; ++i )
            {
                if (d > threshold)
                {
                    numValsToFuzz = i;
                    break;
                }
                threshold /= 2;
            }
            if (numValsToFuzz == 0)
            {
                numValsToFuzz = fuzzableVals.Length;
            }

            //int numValsToFuzz = fuzzableVals.Length;

            var valsToFuzz = new FuzzableMember[numValsToFuzz];

            if (fuzzableVals.Length == 1)
            {
                valsToFuzz[0] = fuzzableVals[0];
            }
            else
            {
                // Select numValsToFuzz out of fuzzableVals.Length values
                int selected = 0;
                for (int i = 0;
                     selected < numValsToFuzz  && selected < fuzzableVals.Length - i;
                     ++i )
                {
                    double p = 1.0 - Math.Pow(1.0 - (double)fuzzableVals[i].Item3 / 
                                                    cmdStat.cmdComplexity, numValsToFuzz);
                    Debug.Assert(p <= 1.0);

                    double r = Globs.GetRandomDouble();
                    if (r <= p)
                    {
                        var memInfo = fuzzableVals[i];
                        object member = Globs.GetMember(memInfo.Item1, memInfo.Item2);
                        Type memType = Globs.GetMemberType(memInfo.Item1);

                        if (member != null || ValidStructs.ContainsKey(memType))
                        {
                            valsToFuzz[selected++] = memInfo;
                        }
                    }
                }
                while (selected < numValsToFuzz)
                {
                    valsToFuzz[selected] = fuzzableVals[fuzzableVals.Length
                                           - (numValsToFuzz - selected)];
                    ++selected;
                }
            }

            foreach (var memInfo in valsToFuzz)
            {
                Type memType = Globs.GetMemberType(memInfo.Item1);
                var containingObject = memInfo.Item2;
                object member = Globs.GetMember(memInfo.Item1, containingObject);
                var ti = memType.GetTypeInfo();
                int rnd = Globs.GetRandomInt();

                if (member == null)
                {
                    //Console.Write("'Nil' node: {0} {1} > ", memType, memInfo.Item1.Name);
                    if (memType == typeof(byte[]))
                    {
                        member = new byte[0];
                    }
                    else if (!ti.IsEnum && !ti.IsValueType)
                    {
                        //Console.Write("'Nil' struct: {0} {1} > ", memType, memInfo.Item1.Name);

                        if (ValidStructs.ContainsKey(memType))
                        {
                            //Console.WriteLine("Replacing...");
                            member = ValidStructs[memType];
                            // Use actual object type in case of members of an interface type
                            DoFuzzDecomposedStruct(
                                    TraverseTpmStructure(member.GetType(), member,
                                                         FieldFilter.Any).ToArray(),
                                    cmdStat);
                            ++CurFuzzStats.nullStructsResurrected;
                        }
                        //else
                        //    Console.WriteLine("No replacement...");
                        return;
                    }
                    else
                    {
                        member = Activator.CreateInstance(memType);
                    }
                    ++CurFuzzStats.nullLeafsResurrected;
                }

                if (ti.IsEnum)
                {
                    object fuzzedEnum = FuzzEnum(memType, member);
                    Globs.SetMember(memInfo.Item1, containingObject, fuzzedEnum);
                    ++CurFuzzStats.enumsFuzzed;
                }
                else if (memType == typeof(byte[]))
                {
                    var buf = member as byte[];
                    if (buf.Length > 0)
                    {
                        if (rnd % 17 != 0)
                        {
                            FuzzBuffer(ref buf, rnd);
                        }
                        else
                        {
                            buf = null;
                        }
                    }
                    else
                    {
                        // Pick up a random size for the fuzzed empty buffer, making 
                        // sure that the values from various ranges are selected.
                        int bufSize = 0;
                        switch (rnd % 5)
                        {
                        case 0:
                            bufSize = Substrate.RandomInt(TpmCfg.MinDigestSize - 1) + 1;
                            break;
                        case 1:
                            bufSize = Substrate.RandomInt(TpmCfg.MaxDigestSize - TpmCfg.MinDigestSize)
                                    + TpmCfg.MinDigestSize;
                            break;
                        case 2:
                            bufSize = TpmHash.DigestSize(Substrate.Random(TpmCfg.HashAlgs));
                            break;
                        case 3:
                            bufSize = Substrate.RandomInt(TpmCfg.MaxNvOpSize - TpmCfg.MaxDigestSize)
                                    + TpmCfg.MaxDigestSize;
                            break;
                        case 4:
                            var keySizes = new int[] { 16, 16, 16, 24, 32, 32, 32, 48,
                                                       64, 1024, 1024, 2048, 2048 };
                            bufSize = keySizes[Substrate.RandomInt(keySizes.Length)];
                            break;
                        case 5:
                            bufSize = Substrate.RandomInt(4 * TpmCfg.MaxNvIndexSize - TpmCfg.MaxNvOpSize)
                                    + TpmCfg.MaxNvOpSize;
                            break;
                        }
                        rnd /= 5;
                        buf = rnd % 2 == 0 ? Substrate.RandomBytes(bufSize)
                                           : Globs.GetZeroBytes(bufSize);
                    }
                    Globs.SetMember(memInfo.Item1, containingObject, buf);
                    ++CurFuzzStats.buffersFuzzed;
                }
                else if (containingObject.GetType() == typeof(TpmHandle))
                {
                    if (rnd % 4 == 0)
                    {
                        // Fuzz as TPM_RH
                        object fuzzedEnum = FuzzEnum(typeof(TpmRh), member);
                        Globs.SetMember(memInfo.Item1, containingObject, fuzzedEnum);
                    }
                    else if (rnd % 8 == 0)
                    {
                        // Fuzz as random value
                        Globs.SetMember(memInfo.Item1, containingObject,
                                        Globs.GetRandomUInt());
                    }
                    else
                    {
                        // TODO: Fuzz to defined handle values in PCR, transient,
                        //       persistent, NV, and session ranges
                        byte[] mso = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x040, 0x80, 0x81 };
                        rnd /= 29;
                        uint fuzzedVal = ((uint)mso[Globs.GetRandomInt(7)] << 24)
                                | (Globs.GetRandomUInt() & 
                                  (rnd % 4 == 0 ? 0x00FFFFFFu : rnd % 4 == 1 ? 0x3Fu : 0x07u));

                    }
                    ++CurFuzzStats.handlesFuzzed;
                }
                else
                {
                    Substrate.Assert(memType.GetTypeInfo().IsValueType);

                    byte[] val = null;
                    val = Globs.HostToNet(member);
                    // Select fuzzing mode that does not change buffer size to preserve
                    // value type
                    FuzzBuffer(ref val, rnd, false);
                    member = Globs.NetToHostValue(memType, val);
                    Globs.SetMember(memInfo.Item1, containingObject, member);
                    ++CurFuzzStats.valuesFuzzed;
                }
            }
        }