4

Today I have met very strange bug.

I have the next code:

var i: integer;
...
for i := 0 to FileNames.Count - 1 do
begin
  ShowMessage(IntToStr(i) + ' from ' + IntToStr(FileNames.Count - 1));
  FileName := FileNames[i];
  ...
end; 
ShowMessage('all');

FileNames list has one element. So, I consider then loop will be executed once and I see

0 from 0
all

It is a thing I did thousands times :). But in this case I see the second loop iteration when code optimization is switched on.

0 from 0
1 from 0
all

Without code optimization loop iterates right. For the moment I don't know even the direction to move with this issue (and upper loop bound stays unchanged, yes).

So any suggestion will be very helpful. Thanks.

I use Delphi 2005 (Upd2) compiler.

16
  • D2005 has not the best reputation. Try using a for-in loop if that works better. edn.embarcadero.com/article/33050 Commented Jan 12, 2015 at 17:40
  • 4
    Please edit to provide a complete, compilable test application that reproduces this problem. Commented Jan 12, 2015 at 17:44
  • 1
    @Downvoter, I really don't believe in downvoting a new user's first question. I think the question is fine, just needs to be elaborated upon a bit more. Commented Jan 12, 2015 at 18:01
  • 1
    @Jerry I believe in voting on the content of the question rather than empathy with the asker. Should the asker fix the question I will vote up with enthusiasm. Commented Jan 12, 2015 at 18:22
  • 2
    @user246408, see qc.embarcadero.com/wc/qcmain.aspx?d=23849. Reported for D2005 and resolved by cannot reproduce in D2006. Commented Jan 12, 2015 at 18:27

2 Answers 2

3

Considering the QC report referred to by LU RD, and my own experience with D2005, here is a few workarounds. I recall using the while loop solution myself.

1.Rewrite the for loop as a while loop

var
  i: integer;
begin
  i := 0;
  while i < FileNames.Count do
  begin
    ...
    inc(i);
  end;
end;

2.Leave the for loop control variable alone from any other processing and use a separate variable, that you increment in the loop, for string manipulation and FileNames indexing.

var
  ctrl, indx: integer;
begin
  indx := 0;
  for ctrl := 0 to FileNames.Count-1 do
  begin
    // use indx for string manipulation and FileNames indx
    inc(indx);
  end;
end;

3.You hinted at a workaround in saying Without code optimization loop iterates right. Assuming you have optimization on turn it off ( {$O-} ) before the procedure/function and on ( {$O+} ) again after. Note! The Optimization directive can only be used around at least whole procedures/functions.

Sign up to request clarification or add additional context in comments.

12 Comments

While technically this may work, I would never consider it an appropriate solution.
@Jerry Considering the QC report referred to by LU RD, what is an appropriate solution? Upgrading to D2006 or later? Yes. Would any workaround (an other one could be rewriting with a separate variable for the string manipulation and indexing) staying in D2005 be inappropriate?
Plus 1. I think the d/v from wherever is a bit harsh, considering that you (as usual) are only trying to help and Borland/Emb have never been entirely forthcoming about what "Optimisation" actually means in terms of Delphi/OP codegen beyond asserting that it will not change the semantics of the generated code (some joke!).
@MartynA Thanks for the support. Jerry Thanks for the comment. I really don't care who dv, but the reason is important, how can one otherwise improve.
I got my D2005 (9.0.1935.22056 Update 3) up and running and made some tests. Miamys code in the original post doesn't fail, neither with or without optimisation, but I understand now that it was incomplete mockup code. His problem was in a .dll. I also checked the two QC entries, that LU RD brought up, and they both fail as reported by their posters in QC. Unfortunately, D2005 doesn't support copying the CPU view, but I took snapshots of the disassembly if somebody is interested. As a conclusion, it is not entirely far fetched to suspect a compiler fault if a for loop behaves wrong in D2005.
|
0

Ok, it seems to me I solved the problem and can explain it. Unfortunately, I cannot make test to reproduce the bug, and I cannot show the real code, which under NDA. So I must use simplified example again.

Problem is in dll, which used in my code. Consider the next data structure:

type
  TData = packed record
    Count: integer;
  end;
  TPData = ^TData;

and function, which defined in dll:

Calc: function(Data: TPData): integer; stdcall;

In my code I try to proceed data records which are taken from list (TList):

var
  i: integer;
  Data: TData;
begin
  for i := 0 to List.Count - 1 do
  begin
    Data := TPData(List[i])^;
    Calc(@Data);
  end;

and in case when optimization is on I see second iteration in loop from 0 to 0. If rewrite code as

var
  i: integer;
  Data, Data2: TData;
begin
  for i := 0 to List.Count - 1 do
  begin
    Data := TPData(List[i])^;
    Data2 := TPData(List[i])^;
    Calc(@Data2);
  end;

all works as expected.

Dll itself was developed by another programmer, so I asked him to take care about it.

What was unexpected for me - that local procedure's stack can be corruped in so unusual way without access violations or other similar errors. BTW, Data and Data2 variables contains correct values.

Maybe, my experience will be useful to someone. Thanks all who helps me and please sorry my unconscious mistakes.

2 Comments

Expecting Access Violations to prevent corrupting of local stack is a misunderstanding of what they are and how they work. Within the context of your program, you have access to all memory allocated to the program. An access violation tells you your program is trying to access memory not allowed by any part of your program. Basically, an AV tells you that an attempted "illegal memory operatin" has been detected. But it's possible to perform many illegal memory opertaion without detection. (Which is why you should count yourself lucky to get an AV.)
In other words, there is nothing wrong with the compiler, but the call to Calc is corrupting the stack

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.