Неточное совмещение стека Delphi + com упорядочивающий = неправильно маршалинг

Это не точно верный вопрос, потому что я только что решил его, но больше как "я получающий его правильный" тип вопроса и напоминания для тех, кто мог бы застрять в это.

Оказывается, Delphi не выравнивает переменные на стеке и нет никаких директив/опций для управления этим поведением. Значение по умолчанию COM marshaller на моем XP SP3, кажется, требует 4-байтового выравнивания при маршалинге записей все же. Хуже, когда это встречается с невыровненным указателем, это не возвращает ошибку, о нет: это округляет указатель в меньшую сторону до ближайшей 4-байтовой границы и продолжается как этот.

Поэтому при передаче записи, Вы выделили на стеке в COM-упорядоченную функцию ссылкой, Вы завинчены, и Вы не будете даже знать.

Проблема может быть решена при помощи Нового/располагать для выделения записей, поскольку диспетчеры памяти имеют тенденцию выравнивать все на уровне 8 байтов или лучше, но бог, это является раздражающим, и часть неточного совмещения и "trim-down-pointers" часть.

Это - действительно причина или является мной неправильно где-нибудь?

Обновление: Как воспроизвести (Delphi 2007 для Win32).

uses SysUtils;

type
  TRec = packed record
    a, b, c, d, e: int64;
  end;

  TDummy = class
  protected
    procedure Proc(param1: integer);
  end;

procedure TDummy.Proc(param1: integer);
var a, b, c: byte;
  rec: TRec;
begin
  a := 5;
  b := 9;
  c := 100;

  rec.a := param1;
  rec.b := a;
  rec.c := b;
  rec.d := c;
  writeln(IntToHex(integer(@rec), 8));
  readln;
end;

var Obj: TDummy;
begin
  obj := TDummy.Create;
  try
    obj.Proc(0);
  finally
    FreeAndNil(obj);
  end;
end.

Это дает нечетный адрес результата, ясно не выровненный на чем-либо. Если это не делает, попытайтесь добавить больше переменных байта к "a, b, c: байт" (и не забывают моделировать некоторую работу с ними в конце функции).

Часть с COM легче воспроизвести, но дольше объяснить. Создайте новое приложение VCL под названием Демонстрационный Сервер, добавьте COM-объект реализация SampleObject ISampleObject с библиотекой типов, единственный экземпляр со свободными потоками (удостоверьтесь, что проверили, что ISampleObject отмечен как Ole Automation в библиотеке типов). Откройте библиотеку типов, объявите новый SampleRecord с пять __ int64 поля. Добавьте SampleFunction с единственным SampleRecord* параметр к ISampleObject. Реализуйте SampleFunction в TSampleObject путем возвращения фиксированных значений:

function TSampleObject.SampleFunction(out rec: SampleRecord): HResult;
begin
  rec.a := 1291;
  rec.b := 742310;
  //...
  Result := S_OK;
end;

Отметьте, как Delphi объявляет SampleRecord как "упакованная запись" в автоматически сгенерированном коде заголовка библиотеки типов:

SampleRecord = packed record
  a: Int64;
  b: Int64;
  //...
end;

Я проверил, и это, по крайней мере, было зафиксировано в Delphi 2010. Автоматически сгенерированные записи не упаковываются там.

Зарегистрируйте сервер COM. Выполните его.

Теперь измените источник выше (демонстрационный 1) для вызова этого сервера вместо того, чтобы просто делать writeln:

uses SysUtils, Windows, ActiveX, SampleServer_TLB;

procedure TDummy.Proc(param1: integer);
var a, b, c: byte;
  rec: SampleRecord;
  Server: ISampleObject;
begin
  a := 5;
  b := 9;
  c := 100;

  rec.a := param1;
  rec.b := a;
  rec.c := b;
  rec.d := c;
  Server := CoSampleObject.Create;
  hr := Server.SampleFunction(rec);
  writeln('@: 'IntToHex(integer(@rec), 8)+', rec.a='+IntToStr(rec.a));
  readln;
end;

var Obj: TDummy;
begin
  CoInitializeEx(nil, COINIT_MULTITHREADED);
  obj := TDummy.Create;
  try
    obj.Proc(0);
  finally
    FreeAndNil(obj);
    CoUninitialize();
  end;
end.

Заметьте, что, когда адрес rec не выровненный, значения rec полей являются неправильными (а именно, bitshifted к 8, 16 или 24 бита, иногда перенесенные законченный к следующему значению).

7
задан himself 25 June 2010 в 16:48
поделиться

1 ответ

У вас есть пример неправильного выравнивания стека? Delphi должен выравнивать все по границам 4 байт. Единственный случай, который я могу представить, который может привести к смещению, это если где-то в цепочке вызовов есть какой-то ассемблерный код, который явно сделал что-то со стеком, чтобы выровнять его неправильно.

8
ответ дан 7 December 2019 в 05:18
поделиться
Другие вопросы по тегам:

Похожие вопросы: