// Standalone validator for the size_t -> int truncation arithmetic in
// media/base/mac/channel_layout_util_mac.cc:119-120.
//
// This mirrors the CoreAudio struct layout (UInt32 == uint32_t,
// Float32 == float) and computes:
//   int output_layout_size =
//       offsetof(AudioChannelLayout, mChannelDescriptions[input_channels]);
// for input_channels = 214748365.
//
// Expected: offsetof yields 12 + 214748365*20 = 0x1_00000010 (size_t),
// which truncates to int = 16. A 16-byte allocation is then asked to hold
// 214748365 AudioChannelDescription entries (20 bytes each).
//
// This program does NOT exercise the OOB write itself (that requires the
// real Chromium HeapArray/span code on macOS). It only proves the
// arithmetic precondition is correct on a 64-bit LP64 toolchain.

#include <stdint.h>
#include <stddef.h>
#include <stdio.h>
#include <assert.h>

typedef uint32_t UInt32;
typedef float Float32;
typedef UInt32 AudioChannelLayoutTag;
typedef UInt32 AudioChannelLabel;
typedef UInt32 AudioChannelFlags;
typedef UInt32 AudioChannelBitmap;

// Mirror of CoreAudioBaseTypes.h::AudioChannelDescription (20 bytes).
struct AudioChannelDescription {
  AudioChannelLabel mChannelLabel;
  AudioChannelFlags mChannelFlags;
  Float32 mCoordinates[3];
};

// Mirror of CoreAudioBaseTypes.h::AudioChannelLayout
// (12-byte header + flexible array).
struct AudioChannelLayout {
  AudioChannelLayoutTag mChannelLayoutTag;
  AudioChannelBitmap mChannelBitmap;
  UInt32 mNumberChannelDescriptions;
  struct AudioChannelDescription mChannelDescriptions[1];
};

int main(void) {
  printf("sizeof(AudioChannelDescription) = %zu (expect 20)\n",
         sizeof(struct AudioChannelDescription));
  printf("offsetof(AudioChannelLayout, mChannelDescriptions) = %zu "
         "(expect 12)\n",
         offsetof(struct AudioChannelLayout, mChannelDescriptions));

  assert(sizeof(struct AudioChannelDescription) == 20);
  assert(offsetof(struct AudioChannelLayout, mChannelDescriptions) == 12);

  // The value AudioToolbox would have to return in mChannelsPerFrame.
  int input_channels = 214748365;

  // *** Exact source line under test ***
  // media/base/mac/channel_layout_util_mac.cc:119-120
  int output_layout_size =
      offsetof(struct AudioChannelLayout, mChannelDescriptions[input_channels]);

  // What it *should* have been without truncation:
  size_t untruncated =
      offsetof(struct AudioChannelLayout, mChannelDescriptions) +
      (size_t)input_channels * sizeof(struct AudioChannelDescription);

  printf("\ninput_channels             = %d\n", input_channels);
  printf("untruncated size (size_t)  = %zu (0x%zx)\n", untruncated,
         untruncated);
  printf("output_layout_size (int)   = %d\n", output_layout_size);
  printf("=> HeapArray::Uninit(%d) allocates %d bytes\n", output_layout_size,
         output_layout_size);
  printf("=> mNumberChannelDescriptions set to %d\n", input_channels);
  printf("=> span<AudioChannelDescription> extent = %d entries (%zu bytes)\n",
         input_channels,
         (size_t)input_channels * sizeof(struct AudioChannelDescription));
  printf("=> first OOB store: descriptions[0].mChannelFlags @ alloc+16 "
         "(alloc is 16 bytes)\n");

  if (output_layout_size == 16 && untruncated == 0x100000010ULL) {
    printf("\n[+] Truncation arithmetic CONFIRMED: 0x%zx -> %d\n",
           untruncated, output_layout_size);
    return 0;
  }
  printf("\n[-] Unexpected result\n");
  return 1;
}
