Sign in Join

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

Mailing lists / fpc-devel / 2008-05

move(xx, ansistring[1] versus ansistring, len)

6 messages · 4 people · –

Reply by email Subscribe to this list Your subscription

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

Martin Friebe

Hi,

I am trying to find some info on how I can use move to archive the following:

I am looking for an equal replacement of
move(somepchar^, ansi_str_dest[1], len)

The problem with ansi_str_dest[1] is that if the above call happens with a len of 0, and an ansi string with 0 length => this leads to a range check exception.

  SetLength(as,0); copy(src^, as[1], 0);

Accessing the first of zero characters => range check. ( It will work without range-checking, since whatever address is returned by [1] is never accessed )

I could prefix it with "if length(dest) > 0 then ", but I would prefer something less noticeable...

I could do

  SetLength(as,0);  copy(src^, as, 0);

But from looking at the assembler produced during compilation, this does not check for fpc_ansistr_unique. Same for any type casting to PChar.

Anyone any idea?

Thanks
Martin

Reply by email

JoshyFun
to Martin Friebe

Hello Martin,

Monday, May 12, 2008, 11:27:08 PM, you wrote:

MF> Hi,
MF> I am trying to find some info on how I can use move to archive the MF> following:
MF> I am looking for an equal replacement of
MF> move(somepchar^, ansi_str_dest[1], len)
[...]
MF> I could prefix it with "if length(dest) > 0 then ", but I would prefer MF> something less noticeable...

I had not checked it but I think you can use the typecasting:

move(somepchar^,pchar(ansi_str_dest)^,len);

as typecasting an ansistring to a pchar should return (repeat "I think") a pointer to ansi_str_dest[1], and if length(ansi_str_dest)=0 then the pointer should be $00000001 :-? which should not raise any kind of range check.

Best regards, JoshyFun

Reply by email

Martin Friebe
to JoshyFun
move(somepchar^,pchar(ansi_str_dest)^,len);

doesn't check fpc_ansistr_unique. So it works only if ansi_str_dest has only one reference; or both strings will be modified (because no copy-on-write happens).

At least, that's what I get to see, if I compile with -al and look at the assembler.

JoshyFun wrote 23 lines
Hello Martin, Monday, May 12, 2008, 11:27:08 PM, you wrote: MF> Hi, MF> I am trying to find some info on how I can use move to archive the MF> following: MF> I am looking for an equal replacement of MF> move(somepchar^, ansi_str_dest[1], len) [...] MF> I could prefix it with "if length(dest) > 0 then ", but I would prefer MF> something less noticeable... I had not checked it but I think you can use the typecasting: move(somepchar^,pchar(ansi_str_dest)^,len); as typecasting an ansistring to a pchar should return (repeat "I think") a pointer to ansi_str_dest[1], and if length(ansi_str_dest)=0 then the pointer should be $00000001 :-? which should not raise any kind of range check.

Reply by email

Jonas Maebe
to Martin Friebe
Martin Friebe wrote 8 lines
move(somepchar^,pchar(ansi_str_dest)^,len); doesn't check fpc_ansistr_unique. So it works only if ansi_str_dest has only one reference; or both strings will be modified (because no copy-on-write happens). At least, that's what I get to see, if I compile with -al and look at the assembler.

You can call uniquestring(ansi_str_dest) before the move()

Jonas

Reply by email

Martin Friebe
to Jonas Maebe

Ah, ok, thanks.
that may work.

Is it documented somewhere, under which circumstances uniquestring is inserted by hte compiler, and when not? In other words, is there a way to be sure, that it will not be called twice in future versions? (Not that it would be a big issue, if it was called twice, but always eager to learn.)

The background for this question is motivated by:
http://bugs.freepascal.org/view.php?id=11280

Many of the occurrances look like

    SetLength(s, count);
    move(str^, s[1], count);

where "s" is a local variable, not used before. So currently it would be safe to skip uniquestring.
But I consider this as a trap, because future changes may act on "s" before, without the author being aware of the exact behaviour of move.

Since the issue is widespread throughout the code (the bug only shows a few samples), and the current access "s[1]" does work, except for the (falsely) triggered rang-check, I find it a bit over the top to prefix every line with "if length(s)>0"

---------------
I also see that (s: AnsiString)

    move(str^, s, count);

seems to work too. (again without implicit uniquestring)

Is there anything against this syntax?
It does not convert s to nil, in case of empty string, but since len is 0 nothing will happen.

Thanks a lot
Martin

Jonas Maebe wrote 19 lines
On 13 May 2008, at 00:17, Martin Friebe wrote: > move(somepchar^,pchar(ansi_str_dest)^,len); > > doesn't check fpc_ansistr_unique. So it works only if ansi_str_dest > has only one reference; or both strings will be modified (because no > copy-on-write happens). > > At least, that's what I get to see, if I compile with -al and look at > the assembler. You can call uniquestring(ansi_str_dest) before the move() Jonas _______________________________________________ fpc-devel maillist - http://lists.freepascal.org/mailman/listinfo/fpc-devel

Reply by email

Sergei Gorelkin
to Martin Friebe
Martin Friebe wrote 8 lines
... Many of the occurrances look like SetLength(s, count); move(str^, s[1], count); where "s" is a local variable, not used before. So currently it would be safe to skip uniquestring. But I consider this as a trap, because future changes may act on "s" before, without the author being aware of the exact behaviour of move.

After call to SetLength() the string is guaranteed to be unique, hence there is no trap here.
You may also wish to substitute both calls with a single

   SetString(s, str^, count);

which is shorter and does not treat the string in potentially unsafe way.

Best regards,
Sergei

Reply by email