Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2009-10

PChar -> AnsiString -> PChar = memory leak?

21 messages · 8 people ·

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Graeme Geldenhuys

Hi,

Do I create a memory leak if I cast a PChar it a AnsiString. Then append text to the AnsiString and then cast it back to the original PChar?

eg:
var
Text: Pchar; <-- global var containing text.

procedure AppendText(const AText: string);
var
  s: string;
begin
  s := Text + AText;
  Text := PChar(s);
end;

I'm busy converting a old program from OS/2 days that used PChar exensively. I'm slowly but surely converting this code to AnsiString. But as a quick fix, am I allowed to do what is shown above? Without causing memory leaks or something else?

Regards, - Graeme - _______________________________________________ fpGUI - a cross-platform Free Pascal GUI toolkit http://opensoft.homeip.net/fpgui/
Aleksa Todorovic
to Graeme Geldenhuys
Graeme Geldenhuys wrote 18 lines
Hi, Do I create a memory leak if I cast a PChar it a AnsiString. Then append text to the AnsiString and then cast it back to the original PChar? eg: var  Text: Pchar;    <-- global var containing text. procedure AppendText(const AText: string); var  s: string; begin  s := Text + AText;  Text := PChar(s); end;

No, you don't create memory leak. But your code neither works, because s is local to AppendText, and PChar(s) becomes void after call to AppendText - memory used by s will be deallocated, and since PChar(s) = @s[1] Text would be invalid pointer. You will either need to convert Text to SomeString, or do manual (de)allocation.

Graeme Geldenhuys
to Graeme Geldenhuys: Do I create a memory leak if I cast a PChar it a AnsiString. Then append text to the…

The reason why I'm not sure, is because I created a simple console test application. Initially, running the program, I got the correct output. Then I thought I would enable 'heaptrc' (-gh compiler parameter) to make sure I am not leaking memory in the application. Now with heaptrc enabled, I get some strange output.. :-(

So now I'm confused.

---- with heaptrc enabled------------------------
$ ./project1
t=hello
Text=hello
Text=������������ᆳ
Heap dump by heaptrc unit
20 memory blocks allocated : 608/632
20 memory blocks freed : 608/632
0 unfreed memory blocks : 0
True heap size : 131072
True free heap : 131072

---- Without heaptrc enabled------------------------ tmp $ ./project1
t=hello
Text=hello
Text=hello world

I'm using FPC 2.3.1 (latest revision) using 64bit Linux.

Regards, - Graeme - _______________________________________________ fpGUI - a cross-platform Free Pascal GUI toolkit http://opensoft.homeip.net/fpgui/
Martin
to Graeme Geldenhuys: Do I create a memory leak if I cast a PChar it a AnsiString. Then append text to the…
Graeme Geldenhuys wrote 18 lines
Hi, Do I create a memory leak if I cast a PChar it a AnsiString. Then append text to the AnsiString and then cast it back to the original PChar? eg: var Text: Pchar; <-- global var containing text. procedure AppendText(const AText: string); var s: string; begin s := Text + AText; Text := PChar(s); end;

I don't think a memory leak. But a problem yes.

Text will have random content afterwards!

s := Text + AText;

"s" will be the new string. => new memory allocated

Text := PChar(s);

"Text" will be a pointer to the memory allocet by "s"

At the end of the procedure "s" will be freed (because it's a local string, so it has no longer any references)
"Text" will then point to unallocated memory (still holding the string) => but as soon as your program does anything, the memory may be reused, and "text" points to random data.

If PChar points to a string, then the strig must be kept as long as pchar is used. (I run into that issue myself, last year....)

Martin

Mattias Gaertner
to Graeme Geldenhuys: Do I create a memory leak if I cast a PChar it a AnsiString. Then append text to the…
Show quoted text 15 lines
Hi, Do I create a memory leak if I cast a PChar it a AnsiString. Then append text to the AnsiString and then cast it back to the original PChar? eg: var Text: Pchar; <-- global var containing text. procedure AppendText(const AText: string); var s: string; begin s := Text + AText;

ok

Text := PChar(s);

wrong, because the local s is the only one having increased the ref count ...

end;

... therefore the 'end' will free the ansistring.

BTW 'text' is a system type.

I'm busy converting a old program from OS/2 days that used PChar exensively. I'm slowly but surely converting this code to AnsiString. But as a quick fix, am I allowed to do what is shown above? Without causing memory leaks or something else?

Mattias

Graeme Geldenhuys
to Graeme Geldenhuys: The reason why I'm not sure, is because I created a simple console test application.…
Graeme Geldenhuys wrote 6 lines
---- Without heaptrc enabled------------------------ tmp $ ./project1 t=hello Text=hello Text=hello world

Crap, I forgot to explain the output.

 t: string;
 Text: PChar

The last line is the result of Text after AppendText() was called. AppendText() is defined like in my first posting.

Regards, - Graeme - _______________________________________________ fpGUI - a cross-platform Free Pascal GUI toolkit http://opensoft.homeip.net/fpgui/
Henry Vermaak
to Graeme Geldenhuys: Do I create a memory leak if I cast a PChar it a AnsiString. Then append text to the…

2009/10/29 Graeme Geldenhuys :

Show quoted text 17 lines
Hi, Do I create a memory leak if I cast a PChar it a AnsiString. Then append text to the AnsiString and then cast it back to the original PChar? eg: var  Text: Pchar;    <-- global var containing text. procedure AppendText(const AText: string); var  s: string; begin  s := Text + AText;  Text := PChar(s); end;

This will only work if you make s global, too...

Henry

Vincent Snijders
to Graeme Geldenhuys: The reason why I'm not sure, is because I created a simple console test application.…
Graeme Geldenhuys wrote 31 lines
The reason why I'm not sure, is because I created a simple console test application. Initially, running the program, I got the correct output. Then I thought I would enable 'heaptrc' (-gh compiler parameter) to make sure I am not leaking memory in the application. Now with heaptrc enabled, I get some strange output.. :-( So now I'm confused. ---- with heaptrc enabled------------------------ $ ./project1 t=hello Text=hello Text=������������ᆳ Heap dump by heaptrc unit 20 memory blocks allocated : 608/632 20 memory blocks freed : 608/632 0 unfreed memory blocks : 0 True heap size : 131072 True free heap : 131072 ---- Without heaptrc enabled------------------------ tmp $ ./project1 t=hello Text=hello Text=hello world I'm using FPC 2.3.1 (latest revision) using 64bit Linux.

I guess heaptrc expose that you are looking at memory that is already freed.

Vincent

Martin Schreiber
to Graeme Geldenhuys: Do I create a memory leak if I cast a PChar it a AnsiString. Then append text to the…
Graeme Geldenhuys wrote 23 lines
Hi, Do I create a memory leak if I cast a PChar it a AnsiString. Then append text to the AnsiString and then cast it back to the original PChar? eg: var Text: Pchar; <-- global var containing text. procedure AppendText(const AText: string); var s: string; begin s := Text + AText; Text := PChar(s); end; I'm busy converting a old program from OS/2 days that used PChar exensively. I'm slowly but surely converting this code to AnsiString. But as a quick fix, am I allowed to do what is shown above? Without causing memory leaks or something else?

Text points to garbage after AppendText() because s will be freed at end of AppendText().

Martin

Mattias Gaertner
to Graeme Geldenhuys: Do I create a memory leak if I cast a PChar it a AnsiString. Then append text to the…
Show quoted text 16 lines
Hi, Do I create a memory leak if I cast a PChar it a AnsiString. Then append text to the AnsiString and then cast it back to the original PChar? eg: var Text: Pchar; <-- global var containing text. procedure AppendText(const AText: string); var s: string; begin s := Text + AText; Text := PChar(s);
Text:=strnew(PChar(s));
end;

Mattias

Henry Vermaak
to Mattias Gaertner

2009/10/29 Mattias Gaertner :

Show quoted text 21 lines
On Thu, 29 Oct 2009 15:00:53 +0200 Graeme Geldenhuys wrote: > Hi, > > Do I create a memory leak if I cast a PChar it a AnsiString. Then > append text to the AnsiString and then cast it back to the original > PChar? > > eg: > var >   Text: Pchar;    <-- global var containing text. > > procedure AppendText(const AText: string); > var >   s: string; > begin >   s := Text + AText; >   Text := PChar(s); Text:=strnew(PChar(s));

Won't this leak? You'll have to initialise text to null, then use strdispose before strnew if text is not null.

Henry

Mattias Gaertner
to Henry Vermaak
Show quoted text 25 lines
2009/10/29 Mattias Gaertner : > On Thu, 29 Oct 2009 15:00:53 +0200 > Graeme Geldenhuys wrote: > >> Hi, >> >> Do I create a memory leak if I cast a PChar it a AnsiString. Then >> append text to the AnsiString and then cast it back to the original >> PChar? >> >> eg: >> var >>   Text: Pchar;    <-- global var containing text. >> >> procedure AppendText(const AText: string); >> var >>   s: string; >> begin >>   s := Text + AText; >>   Text := PChar(s); > > Text:=strnew(PChar(s)); Won't this leak? You'll have to initialise text to null, then use strdispose before strnew if text is not null.

Right you are.
I hit the sent button too early.

Mattias

Graeme Geldenhuys
to Mattias Gaertner: On Thu, 29 Oct 2009 15:00:53 +0200 Text:=strnew(PChar(s)); Mattias
Mattias Gaertner wrote
Text:=strnew(PChar(s));

You read my mind. I was going to ask if it's ok to cast a PString to a PChar.

Trying what you suggested, I get the following compiler error.

project1.lpr(20,11) Error: Incompatible types: got "PString" expected "PChar"

Changing my test code to the following solves the compiler error, but now heaptrc reports that I have two memory leaks.

--------------------------
var
  Text: PChar;
procedure AppendText(const AText: string);
var
  s: string;
begin
  s := Text + AText;
  StrDispose(Text);
  Text := PChar(NewStr(s));
end;
var
  t: string;
begin
  t := 'hello';
  writeln('t=', t);
  Text := PChar(t);
  writeln('Text=', Text);
  AppendText(' world');
  writeln('Text=', Text);
end.
---------------------------

And the console output:

$ ./project1
t=hello
Text=hello
Text=P8
Heap dump by heaptrc unit
21 memory blocks allocated : 616/640
19 memory blocks freed : 580/600
2 unfreed memory blocks : 36
True heap size : 131072
True free heap : 130720
Should be : 130776
Call trace for block $00007F42BFFFB3E0 size 8
$0000000000400366 line 30 of project1.lpr
$0000000000400178
Call trace for block $00007F42C0003840 size 28
$0000000000400366 line 30 of project1.lpr
$0000000000400178

Line 30 being the call to AppendText()

Regards, - Graeme - _______________________________________________ fpGUI - a cross-platform Free Pascal GUI toolkit http://opensoft.homeip.net/fpgui/
Mattias Gaertner
to Graeme Geldenhuys
Show quoted text 7 lines
On 29/10/2009, Mattias Gaertner wrote: > > > Text:=strnew(PChar(s)); You read my mind. I was going to ask if it's ok to cast a PString to a PChar.

Yes.
But it will not change the reference count.

Trying what you suggested, I get the following compiler error. project1.lpr(20,11) Error: Incompatible types: got "PString" expected "PChar"

It compiles here. Probably you use some special units.

Show quoted text 14 lines
Changing my test code to the following solves the compiler error, but now heaptrc reports that I have two memory leaks. -------------------------- var Text: PChar; procedure AppendText(const AText: string); var s: string; begin s := Text + AText; StrDispose(Text); Text := PChar(NewStr(s));

ok
Not very fast, but ok.

Show quoted text 12 lines
end; var t: string; begin t := 'hello'; writeln('t=', t); Text := PChar(t); writeln('Text=', Text); AppendText(' world'); writeln('Text=', Text); end.

Graeme, why don't you just change the type of 'Text' to string?

This does not change the reference count:
Text := PChar(t);
The string is not duplicated. And StrDispose can not free that. And 'Text' is not freed at the end.

Mattias

Henry Vermaak
to Graeme Geldenhuys: You read my mind. I was going to ask if it's ok to cast a PString to a PChar. Trying what…

2009/10/29 Graeme Geldenhuys :

Show quoted text 10 lines
On 29/10/2009, Mattias Gaertner wrote: > > > Text:=strnew(PChar(s)); You read my mind. I was going to ask if it's ok to cast a PString to a PChar. Trying what you suggested, I get the following compiler error. project1.lpr(20,11) Error: Incompatible types: got "PString" expected "PChar"

This is probably dependant on compiler modes?

You may have to do it like this:

StrDispose(Text);
Text := StrAlloc(length(s) + 1);
StrPCopy(Text, s);

Henry

Graeme Geldenhuys
to Henry Vermaak

2009/10/29 Henry Vermaak :

This is probably dependant on compiler modes?

I'm using: $mode objfpc

Show quoted text 5 lines
You may have to do it like this: StrDispose(Text); Text := StrAlloc(length(s) + 1); StrPCopy(Text, s);

Ah, now it works plus no memory leaks.
Thanks! :-)

Wow, something as simple as concatenating string and end up being so complex. Poor C programmers that have to constantly work with pointers and null terminated strings. ;-)

Regards, - Graeme - _______________________________________________ fpGUI - a cross-platform Free Pascal GUI toolkit http://opensoft.homeip.net/fpgui/
Graeme Geldenhuys
to Mattias Gaertner: On Thu, 29 Oct 2009 15:44:09 +0200 Yes. But it will not change the reference count. It…

2009/10/29 Mattias Gaertner :

It compiles here. Probably you use some special units.

Weird... As I mentioned, I'm using FPC 2.3.1 (64bit) under Linux and $mode objfpc.

Graeme, why don't you just change the type of 'Text' to string?

That's the plan - eventually. But the code is large and PChar is passed around all over the place. So changing that one field to String type has a snowball effect on parameter types etc... Something I don't have time for right now. But yes, I eventually want to change all the PChar's to String type. I already replace the PString types with standard String.

Regards, - Graeme - _______________________________________________ fpGUI - a cross-platform Free Pascal GUI toolkit http://opensoft.homeip.net/fpgui/
Mattias Gaertner
to Graeme Geldenhuys
Show quoted text 6 lines
2009/10/29 Mattias Gaertner : > > It compiles here. Probably you use some special units. Weird... As I mentioned, I'm using FPC 2.3.1 (64bit) under Linux and $mode objfpc.

I hope you mean {$mode objfpc}{$H+}

Mattias

Marco van de Voort
to Henry Vermaak: 2009/10/29 Graeme Geldenhuys : This is probably dependant on compiler modes? You may have…

In our previous episode, Henry Vermaak said:

Show quoted text 6 lines
> > Trying what you suggested, I get the following compiler error. > > project1.lpr(20,11) Error: Incompatible types: got "PString" expected "PChar" This is probably dependant on compiler modes?

No, probably mixed sysutils and strings(?) use. pstring is defined in both TP and Delphi. Once to short, once to ansistring

Graeme Geldenhuys
to Marco van de Voort
Marco van de Voort wrote
No, probably mixed sysutils and strings(?) use. pstring is defined in both TP and Delphi. Once to short, once to ansistring

That that must be FPC that is getting confused. In Lazurus I when "Project > New > Free Pascal application". That's as basic as you can get. The uses clause only had Classes and SysUtils in it. No TCustomApplication descendant or nothing, just a plain begin.... end. in the project file with the code I posted before.

Regards, - Graeme - _______________________________________________ fpGUI - a cross-platform Free Pascal GUI toolkit http://opensoft.homeip.net/fpgui/