tags:

views:

141

answers:

4

I appear to have created code that is trashing memory.

Having never had such problems before, i am now settign an Invalid Pointer Operation.

In the following the value of the const string sFilename gets trashed after my call to PromptForXYZPropertiesSettings.

// Allow the user to quickly display the properties of XYZ without needing to display the full Editor
function PromptForXYZProperties(const sFilename:string; var AXYZProperties: TXYZProperties): boolean;
var
  PropEditor: TdlgEditor;
begin
  PropEditor:= TdlgEditor.create(nil);
  try
    PropEditor.LoadFromFile(sFilename);                   <-- sFilename = 'C:\My Folder\Some Folder.txt'
    PropEditor.SelectedXYZProperties := AXYZProperties;

    // Bypass PropEditor to show form owned by it
    Result := PropEditor.PromptForXYZPropertiesSettings;  

    if Result then
    begin
      PropEditor.SaveToFile(sFilename);                   <-- sFilename now somethign like 'B'#1#0#0'ë' or value of a different var
    end;
  finally
    PropEditor.free;      
  end;
end;

Other Details:

  • Delphi 2007, Windows 7 64 bit, but can reproduce when testing EXE on XP
  • REMOVING CONST STOPS PROBLEM FROM EXHIBITING (but presumably the problem is thus just lurking)
  • PropEditor.PromptForXYZPropertiesSettings creates and shows a form. If I disable the ShowModal call then the memory is not trashed. Even though i have REMOVED ALL CONTROLS AND CODE from the form

So I would like some advice on how to debug the issue. I was thinking perhaps watching the memory pointer where the sFilename var exists to see where it gets trashed, but not sure how i would do that (obviously needs to be done within the app so is owned memory).

Thanks

A: 

Usually Invalid Pointer Operation occurs when you pass invalid pointer to MM's routines. Like freeing memory twice. Memory corruption usually results in access violation.

I think that you should start with using debugging memory manager in debug mode.

Alexander
I tried using EurekaLog with memory leak options and it did not encounter any problems.I also checked the data at the memory location of "sFilename" and it doesn't appear to change despite the sFilename change :-S
Xanyx
+1  A: 

I'd suspect some code in the TdlgEditor.LoadFromFile (or further down the call stack) accesses the string via pointer (in which case the compiler can't enforce the const-ness).
string/AnsiString variables are in fact ref-counted records handled by compiler intrinsic and should never be changed via pointer access.
As long as you can't change the TdlgEditor class, your solution may be actually right - you make a local copy of the string and so you don't have to care if it gets thrashed in the process, you just have to remember to not assume anything about the contents of the local string after the call.

Viktor Svub
A: 

I presume that your PromptForXYZPropertiesSettings internally calls ShowModal() and if TdlgEditor is set to Free on close (FormClose event setting CloseAction := caFree) then when the flow of execution returns to your code, the dlgEditor object is already destroyed and therefore invalid.

This might also explain the invalid pointer operation, since you would be attempting to free an already Free'd object in the finally dlgEditor.Free code.

If that is the case then you should change your TdlgEditor to only hide when closed, setting CloseAction := caHide in the FormClose event.

Deltics
That's a very good point, but it doesn't explain why the string gets trashed.
Mason Wheeler
Also a very good point, but this looks to me like a simplified example, not actual code so it's difficult to say what is going on precisely in the *real* code that might explain the corruption of sFilename since we can't actually see the real code. It's hard to say for sure.
Deltics
+4  A: 

Sounds to me like something's trashing your stack. From a casual look at your code I can't see any obvious correctness problems. You've got the right idea: To track this down you need to monitor the value of your string and see when it changes. Here's how you do that:

  • Place a breakpoint at the first line of your method.
  • When it breaks, look at your Local Variables view in the debugger. Find sFilename and double-click on it.
  • The Debug Inspector window will open. At the top it'll say something like this: sFileame: string $18FEA8 : $4A0E5C. Those two hex values are the locations of the reference to the string and the string data itself, respectively.
  • Hit CTRL-ALT-B to bring up the Breakpoint List. It has a little toolbar, and the first button on the toolbar has a dropdown arrow.
  • Click this arrow and select Data Breakpoint from the list. You'll want to create two breakpoints, one for each of the two values in the Debug Inspector window. (If it warns you about putting a data breakpoint on the stack, do it anyway, but you'll want to remember to clear it afterwards.)
  • Once you've got the two data breakpoint values set, hit F9. The system will watch those memory locations and break when they're modified. From there you should be able to track down what's corrupting your string.
Mason Wheeler
Thank you, Mason, your advice was on the money. The breakthrough was realizing i could put a breakpoint on the memory location of the string data. It revealed I was changing the value of the string field that had been passed to the method (as a const). Thus the reference had not changed but the data it was pointing to had.
Xanyx
@Xanyx: Yeah, that's a good trick that isn't as well-known as it should be. Glad I could help!
Mason Wheeler