Lazarus

Programming => General => Topic started by: tennis on July 11, 2020, 03:37:07 pm

Title: [Solved] Simple string loop
Post by: tennis on July 11, 2020, 03:37:07 pm
I recently deflected from Python and are new to Object Pascal so bear with me.
Found some simple code with a behavior which baffles me:

 
program stringlooptest;
{$mode objfpc}{$H+}
var
  name : string;
begin
  for name in ['project','customer','supplier'] do
    WriteLn(name);
end.


this output:

project
custome
supplie


It seems the length of the string is capped to the length of
the first string in the array.

This compiles with out any warning.
Is this the intended behavior?
Title: Re: Simple string loop
Post by: howardpc on July 11, 2020, 04:09:36 pm
I doubt that it is intended behaviour.
The array constructor in this case behaves as if you had declared it like this:
Code: Pascal  [Select][+][-]
  1. program stringlooptest2;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. uses
  6.   SysUtils;
  7.  
  8. type
  9.   TS7Array = array of string[7];
  10.  
  11. var
  12.   name : String;
  13.   sa: TS7Array = ('project','customer','supplier');
  14. begin
  15.   for name in sa do
  16.     WriteLn(name);
  17.   ReadLn;
  18. end.
and this code, as expected, gives a compiler warning that two strings are longer than the allocated storage.
If you put the longest string first in your example, the problem goes away. So clearly the anonymous array the compiler constructs is predicated only on the first string in the series, and for some reason is also a shortstring, even though you specified {$H+}.
Looks like a bug to me.
Title: Re: Simple string loop
Post by: PascalDragon on July 11, 2020, 05:30:31 pm
This compiles with out any warning.
Is this the intended behavior?

This should indeed produce the correct result. Please report a bug (https://bugs.freepascal.org/my_view_page.php) with your code as an example so that it isn't forgotten.
Title: Re: Simple string loop
Post by: tennis on July 12, 2020, 01:05:34 pm
Thanks for the replies.

Bug filed in issue 37338 : https://bugs.freepascal.org/view.php?id=37338 (https://bugs.freepascal.org/view.php?id=37338)
Title: Re: [Solved] Simple string loop
Post by: MaxCuriosus on July 12, 2020, 01:30:08 pm
What version of fpc was it?
Title: Re: [Solved] Simple string loop
Post by: Leledumbo on July 12, 2020, 01:52:15 pm
I've reported this bug before: https://bugs.freepascal.org/view.php?id=32034
Nobody seems interested or it might be too difficult despite the easy look? Nevertheless, workaround exists so yeah this might be ignorable.
Title: Re: [Solved] Simple string loop
Post by: tennis on July 12, 2020, 02:10:52 pm
Version was FPC3.20

The behavior is no problem, but I would expect it should simple to
implement a compiler warning, otherwise it is easy to create
very hard bugs to find. A newbie would not expect this to
fail.
Title: Re: [Solved] Simple string loop
Post by: Leledumbo on July 12, 2020, 03:02:39 pm
Version was FPC3.20

The behavior is no problem, but I would expect it should simple to
implement a compiler warning, otherwise it is easy to create
very hard bugs to find. A newbie would not expect this to
fail.
I would against that "solution", as this is a code generator bug, i.e. by design it should not do so, but as we expected, so a warning should not be required in the first place.

Anyway, it's not difficult to find the cause. Using OP's program, I try seeing the difference between if the first element is 'project' and if it's 'projects', diff tells me this:
Code: ASM  [Select][+][-]
  1. # [6] for name in ['project','customer','supplier'] do        | # [6] for name in ['projects','customer','supplier'] do
  2.         movl    _$STRINGLOOPTEST$_Ld1,%eax                    |         movq    _$STRINGLOOPTEST$_Ld1,%rax
  3.         movl    %eax,24(%rsp)                                 |         movq    %rax,24(%rsp)
  4.         movw    _$STRINGLOOPTEST$_Ld1+4,%ax                   |         movq    _$STRINGLOOPTEST$_Ld2,%rax
  5.         movw    %ax,28(%rsp)                                  |         movq    %rax,32(%rsp)
  6.         movb    _$STRINGLOOPTEST$_Ld1+6,%al                   |         movq    _$STRINGLOOPTEST$_Ld3,%rax
  7.         movb    %al,30(%rsp)                                  |         movq    %rax,40(%rsp)
  8.         movl    _$STRINGLOOPTEST$_Ld2,%eax                    <
  9.         movl    %eax,31(%rsp)                                 <
  10.         movw    _$STRINGLOOPTEST$_Ld2+4,%ax                   <
  11.         movw    %ax,35(%rsp)                                  <
  12.         movb    _$STRINGLOOPTEST$_Ld2+6,%al                   <
  13.         movb    %al,37(%rsp)                                  <
  14.         movl    _$STRINGLOOPTEST$_Ld3,%eax                    <
  15.         movl    %eax,38(%rsp)                                 <
  16.         movw    _$STRINGLOOPTEST$_Ld3+4,%ax                   <
  17.         movw    %ax,42(%rsp)                                  <
  18.         movb    _$STRINGLOOPTEST$_Ld3+6,%al                   <
  19.         movb    %al,44(%rsp)                                  <
  20.         movl    40(%rsp),%eax                                 |         movq    40(%rsp),%rax
  21.         movl    %eax,16(%rsp)                                 |         movq    %rax,16(%rsp)
  22.         movb    44(%rsp),%al                                  <
  23.         movb    %al,20(%rsp)                                  <
  24.         movl    $6,%edx                                       |         movl    $7,%edx
  25.         imulq   $7,%rax,%rax                                  |         leaq    (%rsp,%rax,8),%rsi
  26.         leaq    (%rsp,%rax),%rsi                              <
  27.         .ascii  "project\000"                                 |         .ascii  "projects\000"
  28.  
The line after leaq before .ascii calls fpc_chararray_to_ansistr, but %edx which I suppose stores the char array length (tested by using 'projec' as first element, it then became $5), remains a constant. This makes fpc_chararray_to_ansistr always return the same length strings.
Title: Re: [Solved] Simple string loop
Post by: PascalDragon on July 12, 2020, 04:53:19 pm
I've reported this bug before: https://bugs.freepascal.org/view.php?id=32034
Nobody seems interested or it might be too difficult despite the easy look? Nevertheless, workaround exists so yeah this might be ignorable.

More like too many bugs to keep track of... :-[
Title: Re: [Solved] Simple string loop
Post by: Leledumbo on July 16, 2020, 11:32:42 am
More like too many bugs to keep track of... :-[
And lack of capable volunteers, I understand. Not sure if I can get my hands dirty to fix this myself, but let's see.
Title: Re: [Solved] Simple string loop
Post by: tennis on July 16, 2020, 11:55:34 am
Workaround posted by nanobit on bug tracker for anybody reading this:

Code: Pascal  [Select][+][-]
  1. // workaround with typecasting:
  2. type ta = array of string;
  3. var name : string;
  4. begin
  5. for name in ta(['project','customer','supplier']) do
  6. // or for name in [string('project'), string('customer'), string('supplier')] do
  7.     WriteLn(name);
  8. end.
  9.  
Title: Re: [Solved] Simple string loop
Post by: marcov on July 16, 2020, 12:00:27 pm
Dynamic array of string is predeclared in sysutils as https://www.freepascal.org/docs-html/rtl/sysutils/tstringarray.html
TinyPortal © 2005-2018