Re: [fpc-pascal] AnsiString address changed

2024-03-18 Thread Sven Barth via fpc-pascal
Hairy Pixels via fpc-pascal  schrieb am
Mo., 18. März 2024, 13:30:

>
>
> > On Mar 18, 2024, at 5:29 PM, Michael Van Canneyt via fpc-pascal <
> fpc-pascal@lists.freepascal.org> wrote:
> >
> > Of course there must be, that's the whole point of copy-on-write.
> >
> > As soon as one reference is changed, a copy is made if the reference
> count
> > is larget than 1, and this copy is changed.
>
> Oh, it does copy on write. I see now that by looking at the pointer
> addresses.
>
> So what happens if you do this? s2 is pointing to s1 but then you change
> the size of s1 and ReAllocMem gets called and invalidates the pointer to
> the original s1. How does s2 know this and not access corrupted memory now?
>
>   s1 := '123';
>   s2 := s1;
>   s1 := '';
>


Your description is inaccurate: s2 does not point to s1. Instead both point
to the string data with a reference count of 2. If you now change one of
the two (e.g. with SetLength) then a copy of the string data will be
created and that copy will be manipulated.
The memory of the string data will only be reallocated if only one
reference to that data exists.

Regards,
Sven

>
___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal


Re: [fpc-pascal] AnsiString address changed

2024-03-18 Thread Tomas Hajny via fpc-pascal

On 2024-03-18 13:29, Hairy Pixels via fpc-pascal wrote:
On Mar 18, 2024, at 5:29 PM, Michael Van Canneyt via fpc-pascal 
 wrote:


Of course there must be, that's the whole point of copy-on-write.

As soon as one reference is changed, a copy is made if the reference 
count

is larget than 1, and this copy is changed.


Oh, it does copy on write. I see now that by looking at the pointer 
addresses.


So what happens if you do this? s2 is pointing to s1 but then you
change the size of s1 and ReAllocMem gets called and invalidates the
pointer to the original s1. How does s2 know this and not access
corrupted memory now?

  s1 := '123';
  s2 := s1;
  s1 := '';


From user point of view, the result is the same as when s1 and s2 are 
declared as shortstring (i.e. s2 = '123' and s1 = 'x'). From 
technical point of view, the original location is used for s2 (with 
reference count 1), whereas s1 points to a new location (with reference 
count also 1 at that point in time).


Tomas
___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal


Re: [fpc-pascal] AnsiString address changed

2024-03-18 Thread Hairy Pixels via fpc-pascal


> On Mar 18, 2024, at 5:29 PM, Michael Van Canneyt via fpc-pascal 
>  wrote:
> 
> Of course there must be, that's the whole point of copy-on-write.
> 
> As soon as one reference is changed, a copy is made if the reference count
> is larget than 1, and this copy is changed.

Oh, it does copy on write. I see now that by looking at the pointer addresses.

So what happens if you do this? s2 is pointing to s1 but then you change the 
size of s1 and ReAllocMem gets called and invalidates the pointer to the 
original s1. How does s2 know this and not access corrupted memory now?

  s1 := '123';
  s2 := s1;
  s1 := '';


Regards,
Ryan Joseph

___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal


Re: [fpc-pascal] AnsiString address changed

2024-03-18 Thread Michael Van Canneyt via fpc-pascal



On Mon, 18 Mar 2024, Hairy Pixels via fpc-pascal wrote:





On Mar 18, 2024, at 3:27 PM, Hairy Pixels  wrote:

Oh, it's a pointer to a pointer? I guess that explains how it can resize itself 
and not invalidate shared references, if those are even possible with 
AnsiString.


Wait, that's totally wrong. :) @s is the address of the local variable of 
course. I didn't think before I did that. I just wanted the address of the 
AnsiString.

That still doesn't explain how they resize though. There must be not be more 
than 1 reference to any AnsiString at a time.


Of course there must be, that's the whole point of copy-on-write.

As soon as one reference is changed, a copy is made if the reference count
is larget than 1, and this copy is changed.

Michael.___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal


Re: [fpc-pascal] AnsiString address changed

2024-03-18 Thread Marco van de Voort via fpc-pascal



Op 18-3-2024 om 09:27 schreef Hairy Pixels via fpc-pascal:

  do that, you'll have the same output 3 times.
Oh, it's a pointer to a pointer?


No, it is a pointer variable, but you take the address (@) of that 
pointer, which causes the second indirection



___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal


Re: [fpc-pascal] AnsiString address changed

2024-03-18 Thread Hairy Pixels via fpc-pascal


> On Mar 18, 2024, at 3:27 PM, Hairy Pixels  wrote:
> 
> Oh, it's a pointer to a pointer? I guess that explains how it can resize 
> itself and not invalidate shared references, if those are even possible with 
> AnsiString.

Wait, that's totally wrong. :) @s is the address of the local variable of 
course. I didn't think before I did that. I just wanted the address of the 
AnsiString.

That still doesn't explain how they resize though. There must be not be more 
than 1 reference to any AnsiString at a time.

Regards,
Ryan Joseph

___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal


Re: [fpc-pascal] AnsiString address changed

2024-03-18 Thread Hairy Pixels via fpc-pascal


> On Mar 18, 2024, at 1:52 PM, Michael Van Canneyt via fpc-pascal 
>  wrote:
> 
> An ansistring is a pointer to a memory block.
> 
> You are printing the address of S1 and the address of S, i.e. the address of
> the pointer itself, not the address of what S (or s1) points to. Obviously 
> the address of the s is different of s1.
> 
> What you want to do is print hexstr(pointer(s))
> if you do that, you'll have the same output 3 times.

Oh, it's a pointer to a pointer? I guess that explains how it can resize itself 
and not invalidate shared references, if those are even possible with 
AnsiString.

Regards,
Ryan Joseph

___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal


Re: [fpc-pascal] AnsiString address changed

2024-03-18 Thread Michael Van Canneyt via fpc-pascal




On Mon, 18 Mar 2024, Hairy Pixels via fpc-pascal wrote:


Curious, why did the address of "s" change here? Shouldn't the AnsiString be 
incrementing a reference  count and not actually changing the actual pointer or copying?

Correct me if I'm wrong, AnsiString is ref counted when passing in/out 
functions but copies on assignment so technically no two AnsiStrings can be 
shared in two locations, which makes sense because if they were resized they 
would invalidate each others memory anyways when ReAllocMem is called.

I guess if that's true then there must be only pointer to any AnsiString in any 
given scope otherwise they could resize and corrupt their memory.

Not sure if that makes sense, I'm struggling to understand myself. :)



 procedure PassString(s: AnsiString);
 begin
   writeln(hexstr(@s));
 end;

var
 s1: AnsiString;
begin
 s1 := '123';
 writeln(hexstr(@s1));
 PassString(s1);
 writeln(hexstr(@s1));
end.

Output:

00010259AC00
00016DBC2F80
00010259AC00


An ansistring is a pointer to a memory block.

You are printing the address of S1 and the address of S, i.e. the address of
the pointer itself, not the address of what S (or s1) points to. 
Obviously the address of the s is different of s1.


What you want to do is print hexstr(pointer(s))
if you do that, you'll have the same output 3 times.

Michael.
___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal


[fpc-pascal] AnsiString address changed

2024-03-18 Thread Hairy Pixels via fpc-pascal
Curious, why did the address of "s" change here? Shouldn't the AnsiString be 
incrementing a reference  count and not actually changing the actual pointer or 
copying?

Correct me if I'm wrong, AnsiString is ref counted when passing in/out 
functions but copies on assignment so technically no two AnsiStrings can be 
shared in two locations, which makes sense because if they were resized they 
would invalidate each others memory anyways when ReAllocMem is called.

I guess if that's true then there must be only pointer to any AnsiString in any 
given scope otherwise they could resize and corrupt their memory.

Not sure if that makes sense, I'm struggling to understand myself. :)



  procedure PassString(s: AnsiString); 
  begin
writeln(hexstr(@s));
  end;

var
  s1: AnsiString;
begin
  s1 := '123';
  writeln(hexstr(@s1));
  PassString(s1);
  writeln(hexstr(@s1));
end.

Output:

00010259AC00
00016DBC2F80
00010259AC00

Regards,
Ryan Joseph

___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal