Tôi đã có một số vi phạm truy cập không mong muốn đối với mã Delphi mà tôi nghĩ là chính xác, nhưng có vẻ bị sai. Tôi có thể giảm số này thànhMã sai khi kết hợp các thủ tục ẩn danh và lồng nhau
procedure Run(Proc: TProc);
begin
Proc;
end;
procedure Test;
begin
Run(
procedure
var
S: PChar;
procedure Nested;
begin
Run(
procedure
begin
end);
S := 'Hello, world!';
end;
begin
Run(
procedure
begin
S := 'Hello';
end);
Nested;
ShowMessage(S);
end);
end;
Điều gì xảy ra với tôi là S := 'Hello, world!'
đang lưu trữ ở vị trí sai. Do đó, hoặc vi phạm quyền truy cập được nâng lên hoặc ShowMessage(S)
hiển thị "Xin chào" (và đôi khi, vi phạm quyền truy cập được nâng lên khi giải phóng các đối tượng được sử dụng để thực hiện các thủ tục ẩn danh).
Tôi đang sử dụng Delphi XE, tất cả các bản cập nhật đã được cài đặt.
Làm thế nào tôi có thể biết nơi này sẽ gây ra vấn đề? Tôi biết cách viết lại mã của mình để tránh các thủ tục ẩn danh, nhưng tôi gặp khó khăn trong việc xác định chính xác tình huống nào dẫn đến mã sai, vì vậy tôi không biết phải tránh chúng ở đâu. Nó sẽ là thú vị với tôi để biết nếu điều này là cố định trong các phiên bản sau của Delphi, nhưng không có gì thú vị hơn, nâng cấp không phải là một lựa chọn vào thời điểm này.
Trên QC, báo cáo gần đây nhất tôi có thể tìm thấy số #91876 tương tự, nhưng điều đó được giải quyết trong XE Delphi.
Cập nhật:
Dựa trên ý kiến AlexSC, với một sửa đổi nhỏ:
...
procedure Nested;
begin
Run(
procedure
begin
S := S;
end);
S := 'Hello, world!';
end;
...
làm việc.
Mã máy tạo ra cho
S := 'Hello, world!';
trong chương trình thất bại là
ScratchForm.pas.44: S := 'Hello, world!';
004BD971 B89CD94B00 mov eax,$004bd99c
004BD976 894524 mov [ebp+$24],eax
trong khi phiên bản chính xác là
ScratchForm.pas.45: S := 'Hello, world!';
004BD981 B8B0D94B00 mov eax,$004bd9b0
004BD986 8B5508 mov edx,[ebp+$08]
004BD989 8B52FC mov edx,[edx-$04]
004BD98C 89420C mov [edx+$0c],eax
Các mã được tạo trong chương trình thất bại không nhìn thấy rằng S
đã được chuyển đến một lớp được tạo bởi trình biên dịch, [ebp+$24]
là cách các biến cục bộ bên ngoài của các phương thức lồng nhau được truy cập cách các biến cục bộ được truy cập.
Trong các thử nghiệm của tôi, tôi nhận được cảnh báo này "Đơn vị cảnh báo [DCC ]1.pas (45): W1036 Biến '$ frame' có thể chưa được khởi tạo". Vì tôi đã không khai báo bất kỳ biến $ frame nào, tôi giả sử nó được tạo bởi trình biên dịch khi khai báo các giao diện thực hiện các phương thức nặc danh. Cảnh báo cho thấy rằng không phải mọi thứ đã được thực hiện một cách chính xác bởi trình biên dịch, vì vậy nó có vẻ là một lỗi. Thay đổi mã để biến S tuyên bố là chuỗi làm cho vấn đề hiển thị trước đó. Gỡ lỗi cho thấy biến S không được xử lý đúng cách bởi mã được tạo. – AlexSC
@AlexSC Phát hiện "có thể chưa được khởi tạo" nổi tiếng là xấu, có rất nhiều các lỗi tích cực không trỏ đến bất kỳ vấn đề thực sự nào và không ảnh hưởng đến mã được tạo, vì vậy đó là một cảnh báo cần được bỏ qua. Tôi cũng có thể nhận được cảnh báo đó (bao gồm cả biến biên dịch tạo ra '$ frame') trong mã đơn giản hơn, hoạt động chính xác. – hvd
Biên dịch và hoạt động ok trong XE2 –