Forum > General

"Ghost Lining"

(1/4) > >>

RedOctober:
This is not a bug report.  It is merely an observation, and a question to see if anyone else has run into this.  My platform is Lazarus 2.0.10, FPC 3.2.0, Windows Server 2016.  This exact same problem occurred in Delphi (years ago), and now Lazarus (yesterday).

Description of problem:

During run time, in the production environment, a bug appears, with error dialog displayed. Bug can be recreated consistently.  Should be easy to find, just retrace steps.  Open project in dev environment, Release mode, run, retrace steps, bug appears as expected.  Close, switch compiler to Default mode, retrace steps, app works perfectly, no bug.  Repeat this several times, ensuring there are no compiler directives that would remove or add lines of code between the Release and Default modes. 

After several minutes, several iterations, it is determined that the only difference is the compiler mode.  Source code is correct.

Cure:

Simply add at least ONE line of code, even if it does nothing.  Recompile, in Release mode, bug goes away.

Conclusion:

Something in the compiler (Delphi or Lazarus) is skipping a line of source code, or, compiling it wrong.

In my Delphi project I had the following code:

--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---  if Length(s) > 5 then  // <-- THIS LINE    begin      ShowMessage('I am greater than five');    end 
The line marked THIS LINE would ALWAYS resolve to FALSE even if the length of s was more than five.  The cure was to add a comment line above this section, like this.


--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---  // By adding this comment, above the IF, the line below started working  if Length(s) > 5 then  // <-- THIS LINE    begin      ShowMessage('I am greater than five');    end 
In the Lazarus example:

  (in the database the AVL field is defined as NOT NULL with constraint IN('N','Y')


--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---  qryStock.ParamByName('STOCK_NUMBER').AsString := my_stock_nmbr;  qryStock.ParamByName('DSC').AsString := my_item_description;  qryStock.ParamByName('AVL').AsString := my_item_available;  // <-- THIS LINE   ... commit to database   
In dev environment, compiling to Default mode, run, everything works.  Compiling to Release mode, run, the line marked THIS LINE is skipped, the AVL parameter is left NULL and an error is displayed upon attempt to commit to database.

Cure:


--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---  qryStock.ParamByName('STOCK_NUMBER').AsString := my_stock_nmbr;  qryStock.ParamByName('DSC').AsString := my_item_description;  qryStock.ParamByName('AVL').AsString := my_item_available;     // I add this section AFTER the lines above  Screen.Cursor := crHourGlass;  Application.ProcessMessages;  try    ... commit to database   finally    Screen.Cursor := crDefault;    Application.ProcessMessages;  end;  
Now, this app works when compiled to Default mode OR Release mode.  All I did was add a few lines of code, or a comment, which SHIFTED the lines of code, and changed the total line count, then everything worked reliably.

Now that I am aware of this, I am not stumped for hours trying to resolve it.  If none of my code has changed, and there are no compiler directives that are used or changed between Default and Release modes... I just add a comment or a few lines of code, and the problem goes away.

This has happened to me once in Delphi and now twice in Lazarus, about a year or more apart.

Just wondering if anyone else has run into this, and what, if anything, I am doing wrong, or not looking for that I should be looking for.







SymbolicFrank:
Yes, after some serious debugging, sometimes things go wrong. Resetting the debugger after each use can help, otherwise restarting Lazarus. Sometimes rebooting, but that is rare. Most of the time, it works very well.

My main complaint with debugging is the limited view of the insides of objects.

And a new, native FPC debugger is in the works, I understand. So feel free to jump in :)

jamie:
Years ago using TP I encountered an issue where the code in a unit would have a code generation error but not a compile error if the amount of code generated was crossing over a page boundary and the fix was to just add some more code at the end and the compiler then properly generated the correct code.

 I really don't think this is happening here however, but you never know ? I haven't seen this ever in any version of Delphi so there you go.

 You may need to dig deeper to examine memory floods because using things like the heap trace isn't going to help you here if you are splashing over in memory..

 For example, Writeable constants etc.

RedOctober:
Interesting Jamie, thanks. That kinda sounds close to what is going on.

Martin_fr:
Well first of all the info about the issue is rather vague.

The usual suspects....

- Release / Debug mode have diff optimizer settings.
It is possible that faulty user code works with one optimizer setting but not another. Memory layout changes can lead to the exposure of bugs with dangling data or invalid/incorrect pointers or range violation... E.g. the data *after* an array may be allocated, unused and hold a value that matches the expected value. Or not.
Inserting dummy code, can fix such bugs (because the also change memory layout). Comments would have no effect on this.


In the same way, bug in the compilers optimizer can be triggered. And valid code is suddenly incorrectly compiled. (There is one of those in 3.2.0 and 3.2.2, fixed in 3.2.3 - but that is really hard to trigger - it's in the peephole opt, so -OoNoPeephole or whatever the opt is.)
Here too, dummy code can make a diff, because it changes what can be optimize.

- Cross unit compiler issues.
If for some obscure reason some unit wasn't recompiled, but another unit used by the first was changed (and compiled), then that not recompiled unit is in trouble. In that case, even inserting comments could trigger the recompilation.
Monitor the timestamps of your ppu files.

Note: There is a real danger of that going wrong, if your project, or any package has custom path for: searching units, libs, inc, or outputing ppu (other than including target/buildmode in the ppu output).
I have seen that happen to many people. As soon as any directory  is accessed by more that a single package (the project counting as single package too).

----
You can always save the bad exe. Add the comments, and compare the files. Disassemble with objdump or the like.

Navigation

[0] Message Index

[#] Next page

Go to full version