如何泄漏在Delphi中的字符串(How to leak a string in Delphi)

2019-06-26 00:57发布

我的同事讲那天你如何能在Delphi中,如果你真的把事情搞得一团糟泄漏的字符串。 默认情况下,字符串是引用计数和自动分配的,所以他们通常只是没有任何的思想工作 - 无需手动配置,尺寸计算,或内存管理。

不过,看完记得曾经有直接泄漏的字符串(不包括其在被泄露的对象)的方式。 现在看来似乎有一些东西需要用引用传递一个字符串,然后从它被传递到程序中,从更大范围内访问它。 是的,我知道这是模糊的,这就是为什么我在这里问这个问题。

Answer 1:

事实上,经过串为const或非const的是在引用计数项相同的德尔福2007年和2009年曾经有一个字符串为const传递是导致访问冲突的情况下。 这里是一个问题

type
  TFoo = class
    S: string;
    procedure Foo(const S1: string);
  end;

procedure TFoo.Foo(const S1: string);
begin
  S:= S1; //access violation
end;

var
  F: TFoo;
begin
  F:= TFoo.create;
  try
    F.S := 'S';
    F.Foo(F.S);
  finally
    F.Free;
  end;
end.


Answer 2:

我不知道在你的第二段的问题,但我被记录泄露串咬一次。

如果您在包含字符串的记录调用FillChar()您覆盖裁判计数和使用零动态分配的内存地址。 除非该字符串为空,这将泄漏内存。 解决这个问题的办法是清除它占用的内存之前调用的Finalize()上的记录。

不幸的是调用的Finalize()时,有需要最后确定没有记录部件会导致编译器提示。 它发生在我身上,我注释掉最后确定()调用沉默暗示,但后来当我添加了一个字符串成员我错过了在取消对通话记录,引入这样的泄漏。 幸运的是,我通常用在调试模式下最详细和偏执设定FastMM内存管理器,所以泄漏并没有被忽视。

编译器提示可能不是这样的好事,默默省略最后确定(),如果它是没有必要的会好得多恕我直言称。



Answer 3:

不,我不认为这样的事情会发生。 这是可能的一个字符串变量来获得你没想到的值,但它不会泄漏内存。 试想一下:

var
  Global: string;

procedure One(const Arg: string);
begin
  Global := '';

  // Oops. This is an invalid reference now. Arg points to
  // what Global used to refer to, which isn't there anymore.
  writeln(Arg);
end;

procedure Two;
begin
  Global := 'foo';
  UniqueString(Global);
  One(Global);
  Assert(Global = 'foo', 'Uh-oh. The argument isn''t really const?');
end;

这里One的参数声明为const,所以推测,它不会改变。 但随后One规避,通过改变实际参数代替形式参数。 步骤Two “知道” One “的说法是常量,所以预计实际参数保留其原始值。 断言失败。

串并没有泄露,但是这个代码不演示了如何得到一个字符串悬挂参考Arg是一个本地别名Global 。 虽然我们已经改变了GlobalArg的价值保持不变,因为它被声明为const,该字符串的引用计数并没有在进入功能增加。 重新分配Global下跌的引用计数为零,该字符串被摧毁。 声明Arg为VAR将有同样的问题; 按值传递,将解决这个问题。 (所述的呼叫UniqueString只是以确保字符串是引用计数否则,它可能是一个非参考计数字符串文字。)所有编译器管理的类型是容易受到此问题; 简单类型有免疫力。

泄漏字符串的唯一方法是把它当作字符串以外的东西,或者使用非感知类型的内存管理功能。 Mghie的回答说明了如何将一个字符串通过使用字符串以外的东西FillChar给揍一个字符串变量。 无感知类型的内存功能包括GetMemFreeMem 。 例如:

type
  PRec = ^TRec;
  TRec = record
    field: string;
  end;

var
  Rec: PRec;
begin
  GetMem(Rec, SizeOf(Rec^));
  // Oops. Rec^ is uninitialized. This assignment isn't safe.
  Rec^.field := IntToStr(4);
  // Even if the assignment were OK, FreeMem would leak the string.
  FreeMem(Rec);
end;

有两种方法来解决它。 一个是调用InitializeFinalize

GetMem(Rec, SizeOf(Rec^));
Initialize(Rec^);
Rec^.field := IntToStr(4);
Finalize(Rec^);
FreeMem(Rec);

另一种是使用类型感知功能:

New(Rec);
Rec^.field := IntToStr(4);
Dispose(Rec);


Answer 4:

我想这可能是类似我在想什么的。 这是一个字符串泄漏,那被收集早期字符串的反向:

var
  p : ^String;

procedure InitString;
var
  s, x : String;
begin
  s := 'A cool string!';
  x := s + '. Append something to make a copy in' +
             'memory and generate a new string.';

  p := @x;
end;

begin
  { Call a function that will generate a string }
  InitString();

  { Write the value of the string (pointed to by p) }
  WriteLn(p^); // Runtime error 105!


  { Wait for a key press }
  ReadLn;
end.


Answer 5:

泄漏的字符串的另一种方法是将其声明为线程变量。 见我的问题的详细信息。 而对于解决方案,看看如何把它打扫干净的解决方案 。



文章来源: How to leak a string in Delphi