奇怪的修改阻止了这种访问冲突的原因是什么?
What is the reason of this access violation prevented by weird modifications?
我在 windows 10.
使用西雅图
我尝试打印public ip地址和网关地址。
最后一行发生访问冲突。
当我删除第 1 行时,它运行良好。
uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, System.Win.ComObj, Vcl.StdCtrls, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, IdHTTP, winapi.iphlpapi, winapi.iptypes, winapi.winsock;
type
TForm1 = class(TForm)
Label1: TLabel;
Label2: TLabel;
IdHTTP1: TIdHTTP;
procedure FormCreate(Sender: TObject);
end;
procedure TForm1.FormCreate(Sender: TObject);
var
_IPAdapterAddresses: PIP_ADAPTER_ADDRESSES;
_SizePointer: Integer;
begin
Label2.Caption := Label2.Caption + ' ' + IdHTTP1.Get'http://ipinfo.io/ip'); // line 1
_IPAdapterAddresses := AllocMem(_SizePointer);
GetAdaptersAddresses(2, 128, nil, _IPAdapterAddresses, @_sizepointer);
Label1.Caption := Label1.Caption + ' ' + string(inet_ntoa(_IPAdapterAddresses^.FirstGatewayAddress.Address.lpSockaddr.sin_addr)); // access violation
end;
当我如下修改最后一行时,效果很好。
Label1.Caption := {Label1.Caption + ' ' + }string(inet_ntoa(_IPAdapterAddresses^.FirstGatewayAddress.Address.lpSockaddr.sin_addr));
end;
_IPAdapterAddresses := AllocMem(_SizePointer);
此时_SizePointer
是一个未初始化的变量。它的价值是不确定的。谁知道你分配了多少内存?你当然不知道。由于该值不确定,因此代码中的任何更改都可能导致使用不同的值。
GetAdaptersAddresses(2, 128, nil, _IPAdapterAddresses, @_sizepointer);
您未能检查此调用的 return 值。所以你不知道它是否成功。如果调用失败,那么您就没有理由期望 _IPAdapterAddresses
包含任何有用的东西。无论如何,您可能没有为 _IPAdapterAddresses
.
分配足够的内存
最重要的是,您已经分配了堆内存但未能释放它,因此泄漏了它。
您正在寻找以下内容:
{$APPTYPE CONSOLE}
uses
System.SysUtils,
Winapi.IpHlpApi,
Winapi.IpTypes,
Winapi.WinSock,
Winapi.Windows;
const
GAA_FLAG_INCLUDE_GATEWAYS = [=12=]80;
procedure Main;
var
Addresses: PIP_ADAPTER_ADDRESSES;
OutBufLen: ULONG;
Retval: ULONG;
begin
OutBufLen := 15*1024; // MSDN recommendation is to use a 15kB buffer
GetMem(Addresses, OutBufLen);
try
Retval := GetAdaptersAddresses(AF_INET, GAA_FLAG_INCLUDE_GATEWAYS, nil, Addresses,
@OutBufLen);
if Retval = ERROR_BUFFER_OVERFLOW then
begin
ReallocMem(Addresses, OutBufLen);
Retval := GetAdaptersAddresses(AF_INET, GAA_FLAG_INCLUDE_GATEWAYS, nil, Addresses,
@OutBufLen);
end;
if Retval <> ERROR_SUCCESS then
RaiseLastOSError(Retval, '');
Writeln(inet_ntoa(Addresses^.FirstGatewayAddress.Address.lpSockaddr.sin_addr));
finally
FreeMem(Addresses);
end;
end;
begin
try
Main;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
Readln;
end.
我在 windows 10.
使用西雅图我尝试打印public ip地址和网关地址。
最后一行发生访问冲突。
当我删除第 1 行时,它运行良好。
uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, System.Win.ComObj, Vcl.StdCtrls, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, IdHTTP, winapi.iphlpapi, winapi.iptypes, winapi.winsock;
type
TForm1 = class(TForm)
Label1: TLabel;
Label2: TLabel;
IdHTTP1: TIdHTTP;
procedure FormCreate(Sender: TObject);
end;
procedure TForm1.FormCreate(Sender: TObject);
var
_IPAdapterAddresses: PIP_ADAPTER_ADDRESSES;
_SizePointer: Integer;
begin
Label2.Caption := Label2.Caption + ' ' + IdHTTP1.Get'http://ipinfo.io/ip'); // line 1
_IPAdapterAddresses := AllocMem(_SizePointer);
GetAdaptersAddresses(2, 128, nil, _IPAdapterAddresses, @_sizepointer);
Label1.Caption := Label1.Caption + ' ' + string(inet_ntoa(_IPAdapterAddresses^.FirstGatewayAddress.Address.lpSockaddr.sin_addr)); // access violation
end;
当我如下修改最后一行时,效果很好。
Label1.Caption := {Label1.Caption + ' ' + }string(inet_ntoa(_IPAdapterAddresses^.FirstGatewayAddress.Address.lpSockaddr.sin_addr));
end;
_IPAdapterAddresses := AllocMem(_SizePointer);
此时_SizePointer
是一个未初始化的变量。它的价值是不确定的。谁知道你分配了多少内存?你当然不知道。由于该值不确定,因此代码中的任何更改都可能导致使用不同的值。
GetAdaptersAddresses(2, 128, nil, _IPAdapterAddresses, @_sizepointer);
您未能检查此调用的 return 值。所以你不知道它是否成功。如果调用失败,那么您就没有理由期望 _IPAdapterAddresses
包含任何有用的东西。无论如何,您可能没有为 _IPAdapterAddresses
.
最重要的是,您已经分配了堆内存但未能释放它,因此泄漏了它。
您正在寻找以下内容:
{$APPTYPE CONSOLE}
uses
System.SysUtils,
Winapi.IpHlpApi,
Winapi.IpTypes,
Winapi.WinSock,
Winapi.Windows;
const
GAA_FLAG_INCLUDE_GATEWAYS = [=12=]80;
procedure Main;
var
Addresses: PIP_ADAPTER_ADDRESSES;
OutBufLen: ULONG;
Retval: ULONG;
begin
OutBufLen := 15*1024; // MSDN recommendation is to use a 15kB buffer
GetMem(Addresses, OutBufLen);
try
Retval := GetAdaptersAddresses(AF_INET, GAA_FLAG_INCLUDE_GATEWAYS, nil, Addresses,
@OutBufLen);
if Retval = ERROR_BUFFER_OVERFLOW then
begin
ReallocMem(Addresses, OutBufLen);
Retval := GetAdaptersAddresses(AF_INET, GAA_FLAG_INCLUDE_GATEWAYS, nil, Addresses,
@OutBufLen);
end;
if Retval <> ERROR_SUCCESS then
RaiseLastOSError(Retval, '');
Writeln(inet_ntoa(Addresses^.FirstGatewayAddress.Address.lpSockaddr.sin_addr));
finally
FreeMem(Addresses);
end;
end;
begin
try
Main;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
Readln;
end.