Repository: dotnet/runtime
File: src/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/ReadyToRunSignature.cs (C#)

Code before:
                        ParseType();
                    ParseMethod(builder);
                    if (fixupType == ReadyToRunFixupKind.Check_IL_Body)
                        builder.Append(" (CHECK_IL_BODY)");
                    else
                        builder.Append(" (VERIFY_IL_BODY)");
                    break;

                case ReadyToRunFixupKind.ContinuationLayout:
                    var typeBuilder = new StringBuilder();
                    ParseType(typeBuilder);
                    builder.Append($"{typeBuilder.ToString()}");
                    ReadyToRunTypeLayoutFlags layoutFlags2 = (ReadyToRunTypeLayoutFlags)ReadUInt();
                    builder.Append($" Flags {layoutFlags2}");
                    int actualSize2 = (int)ReadUInt();
                    builder.Append($" Size {actualSize2}");

                    if(layoutFlags2.HasFlag(ReadyToRunTypeLayoutFlags.READYTORUN_LAYOUT_HFA))
                    {
                        throw new BadImageFormatException("ContinuationLayout fixup should not have READYTORUN_LAYOUT_HFA flag set");
                    }

                    if (layoutFlags2.HasFlag(ReadyToRunTypeLayoutFlags.READYTORUN_LAYOUT_Alignment)
                        && !layoutFlags2.HasFlag(ReadyToRunTypeLayoutFlags.READYTORUN_LAYOUT_Alignment_Native))
                    {
                        throw new BadImageFormatException("ContinuationLayout fixup should not have non-native alignment");
                    }

                    if (!layoutFlags2.HasFlag(ReadyToRunTypeLayoutFlags.READYTORUN_LAYOUT_GCLayout))
                    {
                        throw new BadImageFormatException("ContinuationLayout fixup should have GCLayout");
                    }

                    if (!layoutFlags2.HasFlag(ReadyToRunTypeLayoutFlags.READYTORUN_LAYOUT_GCLayout_Empty))
                    {
                        int cbGCRefMap = (actualSize2 / _contextReader.TargetPointerSize + 7) / 8;
                        builder.Append(" GCLayout 0x");
                        for (int i = 0; i < cbGCRefMap; i++)
                        {
                            builder.Append(ReadByte().ToString("X"));
                        }
                    }
                    else
                    {
                        builder.Append(" GCLayout 0x00 (Empty)");
                    }
                    builder.Append(" (ContinuationLayout)");
                    break;

                default:
                    throw new BadImageFormatException();

Review comment (suggestion):
The validation logic is inconsistent between the encoder and the parser/decoder. The encoder always sets READYTORUN_LAYOUT_Alignment flag (line 145 in TypeFixupSignature.cs), but the parser checks that if READYTORUN_LAYOUT_Alignment is set, then READYTORUN_LAYOUT_Alignment_Native must also be set (lines 1491-1495). However, the runtime decoder in jitinterface.cpp only checks that READYTORUN_LAYOUT_Alignment_Native is set, without requiring READYTORUN_LAYOUT_Alignment to be set (line 13759). Since the encoder always sets both flags together, this works, but the validation logic should be consistent. Either require both flags to be set together, or only require READYTORUN_LAYOUT_Alignment_Native.
```suggestion
                        != layoutFlags2.HasFlag(ReadyToRunTypeLayoutFlags.READYTORUN_LAYOUT_Alignment_Native))
                    {
                        throw new BadImageFormatException("ContinuationLayout fixup alignment flags must be either both set or both unset");
```

Code after:
            if (PeekElementType() == CorElementType.ELEMENT_TYPE_MODULE_ZAPSIG)
            {
                var currentOffset = Offset;

                ReadElementType();
                int moduleIndex = (int)ReadUInt();
                IAssemblyMetadata refAsmReader = _contextReader.OpenReferenceAssembly(moduleIndex);

                UpdateOffset(currentOffset);

                return refAsmReader;
            }
            return null;
        }

        /// <summary>
        /// Parse an arbitrary method signature.
        /// </summary>
        /// <param name="builder">Output string builder to receive the textual signature representation</param>
        private void ParseMethod(StringBuilder builder)
        {
            builder.Append(ParseMethod());
        }

        private void ParseTypeLayout(StringBuilder builder)
        {
            ReadyToRunTypeLayoutFlags layoutFlags = (ReadyToRunTypeLayoutFlags)ReadUInt();
            builder.Append($" Flags {layoutFlags}");
            int actualSize = (int)ReadUInt();
            builder.Append($" Size {actualSize}");

            if (layoutFlags.HasFlag(ReadyToRunTypeLayoutFlags.READYTORUN_LAYOUT_HFA))
            {
                builder.Append($" HFAType {ReadUInt()}");
            }

            if (layoutFlags.HasFlag(ReadyToRunTypeLayoutFlags.READYTORUN_LAYOUT_Alignment))
            {
                if (!layoutFlags.HasFlag(ReadyToRunTypeLayoutFlags.READYTORUN_LAYOUT_Alignment_Native))
                {
                    builder.Append($" Align {ReadUInt()}");
                }
                else
                {
                    builder.Append(" Align native");
                }
            }

            if (layoutFlags.HasFlag(ReadyToRunTypeLayoutFlags.READYTORUN_LAYOUT_GCLayout))
            {
                if (!layoutFlags.HasFlag(ReadyToRunTypeLayoutFlags.READYTORUN_LAYOUT_GCLayout_Empty))