Delphi Pages Forums  

Go Back   Delphi Pages Forums > Delphi Forum > General

Lost Password?

Reply
 
Thread Tools Display Modes
  #1  
Old 05-11-2016, 05:47 AM
Badger Badger is offline
Member
 
Join Date: Aug 2013
Location: Sheffield, Tasmania (Aust)
Posts: 76
Default Memory being overwritte??

Sorry, this question is a bit convoluted.

I have recently modified a unit for an application and the modified Procedure is causing problems.

Code:
procedure TLetterForm.CheckBox1Click(Sender: TObject);
var
  OldPageTop:Integer ;  //THE NEW ADDITION
  dog:integer;             // AN ADDITIONAL VARIABLE TO TEST THE 'LOGIC'
begin
  If CheckBox1.Checked then
  begin
    //get old page top
    OldPageTop:=Page1.top;            
    dog:=300;
    //set new top
    Page1.top:=dog;//300;
    //recalculate page height
    Page1.Height:=Page1.Height-(300-OldPageTop);
    //add address advice
    Page1.Lines[0]:='Put recipient''s name and address here ' +Page1.Lines[0];

  end
  else
  begin
    Page1.top:=OldPageTop;
    Page1.Height:=Page1.Height+(300-OldPageTop);
    //remove address advice
    Page1.lines[0]:=Copy(Page1.lines[0],length('Put recipient''s name and address here')+1,length(Page1.lines[0])-length('Put recipient''s name and address here'));
  end;
end;
I can see nothing wrong with the code. When you click Checkbox1 the first time all is OK. However, on the second click Page1 disappears in stead of reverting to its original position.

I put a break on the first line of the procedure. On stepping through the program I noticed that first time through, OldPageTop starts out at some high number (77262224) rather than zero (dog is zero) then gets changed to 147 as expected (dog is set to 300) and stays this way till the program exits the procedure.

If I then click on the checkbox again immediately (no other code is called) the procedure opens with OldPageTop set to 1697872 and dog is set to 131126. So obviously the page disappears off the bottom of the form.

I suspect that the program is trying to write two values to one address. The only way I can see this happening is for a dynamic variable to be 'leaking' into the two variables allocated in the procedure.

If I move the OldPageTop and dog to the global variables the problem goes away but I suspect it is just being moved to some other piece of code and may well crop up when I write more code so I want to solve it now when I know I can make it happen.

The program is compiled with {$R *.dfm} directive. Is there any 'simple' way to find this leak?

The program has 24+ units and many thousands of lines of code and I am guessing the overlap could come from anywhere in any of the other units.
Reply With Quote
  #2  
Old 05-11-2016, 08:40 AM
Norrit Norrit is offline
Moderator
 
Join Date: Aug 2001
Location: Landgraaf
Posts: 7,333
Default

Since OldPageTop:Integer is part of your checkbox routine it's never initialized when called with CheckBox unchecked. Move it to your form and don't forget to initialize it (FormCreate/FormShow)
Same goes for "dog", if you validate it before it's set to 300 it will give you a random number
Reply With Quote
  #3  
Old 05-12-2016, 12:53 AM
Badger Badger is offline
Member
 
Join Date: Aug 2013
Location: Sheffield, Tasmania (Aust)
Posts: 76
Default

Thanks for the reply Norrit

I appreciate that it will be a random number when the procedure is first called. However, as I said in my original post, I would have thought it would have retained its new value when called again but it doesn't.

Badger
Reply With Quote
  #4  
Old 05-12-2016, 01:32 AM
rojam rojam is offline
Senior Member
 
Join Date: Jun 2015
Posts: 198
Default

Quote:
Originally Posted by Badger View Post
I would have thought it would have retained its new value when called again but it doesn't.
You can in fact have a local variable that retains its value between calls by using a compiler directive to turn writeable constants on {$J+}
Code:
procedure TForm1.CheckBox1Click(Sender: TObject);
{$J+}
const
   PersistentLocalInt: Integer = 100;
{$J-}
begin
   Inc(PersistentLocalInt);
   ShowMessage('My Local Integer now equals:  '+IntToStr(PersistentLocalInt));
end;
I would not recommend you use this however, writeable constants are there for backwards compatibility.
Reply With Quote
  #5  
Old 05-12-2016, 03:33 AM
Badger Badger is offline
Member
 
Join Date: Aug 2013
Location: Sheffield, Tasmania (Aust)
Posts: 76
Default

As a non-expert, can I clarify how Delphi compiles.

I understand that at the start of the program ALL variables that are used in the program, with a few exceptions such as dynamic arrays and lists, are allocated a specific memory address which doesn't change throughout the execution of the program and the contents shouldn't change unless written to by the program.

Since nothing is written to 'OldPageTop' between one call to the onClick procedure and the next its value should not change. However, SOMETHING is overwriting its value. Because the error occurs even when the checkbox clicks are consecutive my only explaination is that the program reconfiguring the Page1 properties is overwriting the values.

Is there anything else that could be doing it?
Reply With Quote
  #6  
Old 05-12-2016, 07:07 AM
Norrit Norrit is offline
Moderator
 
Join Date: Aug 2001
Location: Landgraaf
Posts: 7,333
Default

I already posted the solution between the lines
Quote:
Move it to your form
So you have something like:
Code:
type
  TLetterForm = class(TForm)
    ...
  private
    oldPageTop: Integer; 
    dog: Integer;   
  end;

procedure TLetterForm.CheckBox1Click(Sender: TObject);
// NOT NEEDED ANYMORE!!!
//var
//  OldPageTop:Integer ;  //THE NEW ADDITION
//  dog:integer;             // AN ADDITIONAL VARIABLE TO TEST THE 'LOGIC'
begin
  ... your code ...
end;
Reply With Quote
  #7  
Old 05-12-2016, 07:27 AM
Badger Badger is offline
Member
 
Join Date: Aug 2013
Location: Sheffield, Tasmania (Aust)
Posts: 76
Default

Hi Norrit

I did try more or less what you are suggesting (5th para of my original post - I did put it in the public declarations rather than the private as a temp measure just to get it out of the way and see if it worked) and it works fine but it worries me that in moving the declaration the problem might shift to another variable that I use in future that gets put in that same memory address.

As I say, I'm no expert but surely unless there is a problem, a variable shouldn't get overwritten without a directive from the program.

Last edited by Badger; 05-12-2016 at 07:31 AM.
Reply With Quote
  #8  
Old 05-12-2016, 08:10 AM
Norrit Norrit is offline
Moderator
 
Join Date: Aug 2001
Location: Landgraaf
Posts: 7,333
Default

Since I moved it into the form it's only accessible from that form (that's why it's private)
But why you worry about this, since there's no difference to CheckBox1 on that form. I can call CheckBox1.Caption/.Text := 'test' works from everywhere. So here you have the same problem.

Since the IDE prevents you from having 2 the same names for variables your as safe as it gets.
But don't make the mistake to create the variables as global var (placed under the form1: TForm. I see a lot of beginners putting extra variables there. That's the absolute no-go place.
So if you use my suggestion you're good to go...
Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is On

Forum Jump


All times are GMT. The time now is 11:36 PM.


Powered by vBulletin® Version 3.8.8
Copyright ©2000 - 2019, vBulletin Solutions, Inc.