powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Локальные процедуры. Баг 64-х битного компилятора или волшебное везение 32-х битного?
9 сообщений из 9, страница 1 из 1
Локальные процедуры. Баг 64-х битного компилятора или волшебное везение 32-х битного?
    #39578084
nicholaos
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Доброго времени суток.

Есть минимальный пример для воспроизведения, в нем процедура вызывает другую процедуру по переданному адресу, которая меняет var-параметр:

Код
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
interface

type

  TSomeProc = procedure(const NewValue: integer; var Value: integer);

...

implementation

procedure CallProc(Proc: TSomeProc; var Value: integer);
begin
  Proc(1, Value);
end;

procedure ExternalProc(const NewValue: integer; var Value: integer);
begin
  Value := NewValue;
end;

procedure TForm1.Button1Click(Sender: TObject);

  procedure InnerProc(const NewValue: integer; var Value: integer);
  begin
    Value := NewValue;
  end;

var
  Value: integer;
begin
  Value := -1;

  //Вариант 1
  //CallProc(@ExternalProc, Value);
  //Вариант 2
  CallProc(@InnerProc, Value);

  ShowMessage(IntToStr(Value));
end;




При компиляции 32-х битным компилятором (Delphi 2007 и Delphi XE8) без ошибок выполняется как вариант 1, так и вариант 2.
При компиляции 64-х битным компилятором (Delphi XE8) без ошибок выполняется только вариант 1.
Вариант 2 выдает ошибку:

Ошибка---------------------------
Debugger Exception Notification
---------------------------
Project Bug64.exe raised exception class $C0000005 with message 'c0000005 ACCESS_VIOLATION'.
---------------------------
Break Continue Help
---------------------------


Есть предположение, что проблема в том, что InnerProc вложена в метод класса , т.е. всегда имеет неявный аргумент Self.
Однако, тогда не понятно, почему при компиляции в 32 бита ошибки нет.

Возможно, что при компиляции в 32 бита "везет" на расположение аргументов (в регистре или на стеке), а в 64 - "не везет". Пробовал добавлять ко всем процедурам stdcall - тот же результат.

Подскажите, пожалуйста, что происходит на самом деле.

Без использования адреса
Насколько я понимаю, вызов с использованием адреса ("CallProc(@...") приводит к "обману" проверки типов компилятора, а вызов без @ приведет к ошибкам компиляции, т.е. дельфи старается не дать программисту отстрелить себе ногу:
dcc Error[dcc32 Error] uBug64.pas(52): E2094 Local procedure/function 'InnerProc' assigned to procedure variable
и
[dcc64 Error] uBug64.pas(52): E2094 Local procedure/function 'InnerProc' assigned to procedure variable



P.S. Проблема не выдумана, такой прием активно используется в одном стороннем компоненте.
...
Рейтинг: 0 / 0
Локальные процедуры. Баг 64-х битного компилятора или волшебное везение 32-х битного?
    #39578096
Кар-Кар
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Всё так, имеет Self - это стек, регистр rbp.
Чтобы можно было SuperValue достать в Button1Click и вообще контекст не терять, как-то так выйдет:
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
type
  TSomeProc = procedure(const Stack:UInt64;const NewValue: integer; var Value: integer);

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure CallProc(const Stack: UInt64;Proc: TSomeProc; var Value: integer);
begin
  Proc(Stack, 1, Value);
end;

procedure ExternalProc(const NewValue: integer; var Value: integer);
begin
  Value := NewValue;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
SuperValue : Integer;

  procedure InnerProc(const NewValue: integer; var Value: integer);
  begin
    Value := NewValue + SuperValue;
  end;

  function GetStack:UInt64;
  asm
    //.NOFRAME не работает в локальных оказывается
    mov       rax,rcx
  end;

var
  Value: integer;
begin
  Value := -1;
  SuperValue := 1000;

  //CallProc(@ExternalProc, Value);
  CallProc(GetStack, @InnerProc, Value);

  ShowMessage(IntToStr(Value));
end;
...
Рейтинг: 0 / 0
Локальные процедуры. Баг 64-х битного компилятора или волшебное везение 32-х битного?
    #39578107
Фотография X-Cite
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
...
Рейтинг: 0 / 0
Локальные процедуры. Баг 64-х битного компилятора или волшебное везение 32-х битного?
    #39578108
Фотография X-Cite
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Нельзя так делать...
На х32 вам просто везет..
...
Рейтинг: 0 / 0
Локальные процедуры. Баг 64-х битного компилятора или волшебное везение 32-х битного?
    #39578109
Фотография X-Cite
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Вместо этого используйте замыкания...
...
Рейтинг: 0 / 0
Локальные процедуры. Баг 64-х битного компилятора или волшебное везение 32-х битного?
    #39578125
kealon(Ruslan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
nicholaos,

волшебное везение 32-х битного

CallProc(@InnerProc, Value);
не используйте этот знак если нет чёткого понимания зачем это нужно
...
Рейтинг: 0 / 0
Локальные процедуры. Баг 64-х битного компилятора или волшебное везение 32-х битного?
    #39578157
GunSmoker
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Используя @, ты получаешь нетипизированный указатель, что отключает проверки компилятора. Убери @ - и компилятор сам скажет, что так делать нельзя .
...
Рейтинг: 0 / 0
Локальные процедуры. Баг 64-х битного компилятора или волшебное везение 32-х битного?
    #39578161
Фотография X-Cite
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
type
  TSomeProc = reference to procedure(const NewValue: Integer; var Value: Integer);

procedure CallProc(Proc: TSomeProc; var Value: integer);
begin
  Proc(1, Value);
end;

procedure TForm1.Test;
var
  Value: Integer;
begin
  Value := -1;
  CallProc (
    procedure(const NewValue: Integer; var Value: Integer)
    begin
      Value := NewValue;
    end,
    Value
  );
end;
...
Рейтинг: 0 / 0
Локальные процедуры. Баг 64-х битного компилятора или волшебное везение 32-х битного?
    #39578249
nicholaos
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Использование замыканий, судя по всему, и проще, и правильней.
Поменял объявление типов для процедур-коллбэков на "reference to procedure" - это позволило выловить все ошибки по время компиляции. Исправил все ошибки - все заработало.

Всем спасибо за ответы!
...
Рейтинг: 0 / 0
9 сообщений из 9, страница 1 из 1
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Локальные процедуры. Баг 64-х битного компилятора или волшебное везение 32-х битного?
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]