Lazarus

Programming => General => Topic started by: Vodnik on January 10, 2019, 11:28:50 pm

Title: XMLConfig example causes SIGSEGV [BUG]
Post by: Vodnik on January 10, 2019, 11:28:50 pm
I just have tried to use TXMLConfig for saving Form size and position, as described in General method here: http://wiki.freepascal.org/Remember_form_position_and_size (http://wiki.freepascal.org/Remember_form_position_and_size). Following instructions, I have dropped TXMLConfig to the Form and copy-pasted the two procedures:
Code: Pascal  [Select][+][-]
  1. unit unit_spl;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, XMLConf, FileUtil, Forms, Controls, Graphics, Dialogs,
  9.   StdCtrls, ExtCtrls;
  10.  
  11. type
  12.  
  13.   { TForm1 }
  14.  
  15.   TForm1 = class(TForm)
  16.     Memo1: TMemo;
  17.     Memo2: TMemo;
  18.     Splitter1: TSplitter;
  19.     XMLConfig1: TXMLConfig;
  20.     procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
  21.     procedure FormShow(Sender: TObject);
  22.     procedure StoreFormState;
  23.     procedure RestoreFormState;
  24.   private
  25.  
  26.   public
  27.  
  28.   end;
  29.  
  30. var
  31.   Form1: TForm1;
  32.  
  33. implementation
  34.  
  35. {$R *.lfm}
  36. procedure TForm1.StoreFormState;
  37. begin
  38.   with XMLConfig1 do begin
  39.     SetValue('NormalLeft', Left);
  40.     SetValue('NormalTop', Top);
  41.     SetValue('NormalWidth', Width);
  42.     SetValue('NormalHeight', Height);
  43.  
  44.     SetValue('RestoredLeft', RestoredLeft);
  45.     SetValue('RestoredTop', RestoredTop);
  46.     SetValue('RestoredWidth', RestoredWidth);
  47.     SetValue('RestoredHeight', RestoredHeight);
  48.  
  49.     SetValue('WindowState', Integer(WindowState));
  50.   end;
  51. end;
  52.  
  53. procedure TForm1.FormShow(Sender: TObject);
  54. begin
  55.   RestoreFormState;
  56. end;
  57.  
  58. procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
  59. begin
  60.    StoreFormState;
  61. end;
  62.  
  63. procedure TForm1.RestoreFormState;
  64. var
  65.   LastWindowState: TWindowState;
  66. begin
  67.   with XMLConfig1 do begin
  68.     LastWindowState := TWindowState(GetValue('WindowState', Integer(WindowState)));
  69.  
  70.     if LastWindowState = wsMaximized then begin
  71.       WindowState := wsNormal;
  72.       BoundsRect := Bounds(
  73.         GetValue('RestoredLeft', RestoredLeft),
  74.         GetValue('RestoredTop', RestoredTop),
  75.         GetValue('RestoredWidth', RestoredWidth),
  76.         GetValue('RestoredHeight', RestoredHeight));
  77.       WindowState := wsMaximized;
  78.     end else begin
  79.       WindowState := wsNormal;
  80.       BoundsRect := Bounds(
  81.         GetValue('NormalLeft', Left),
  82.         GetValue('NormalTop', Top),
  83.         GetValue('NormalWidth', Width),
  84.         GetValue('NormalHeight', Height));
  85.     end;
  86.   end;
  87. end;
  88.  
  89. end.
  90.  
When executing, it cause a SIGSEGV exeption when calling XMLConfig1.GetValue procedure, as if XMLConfig1 was not initialized. But why? Did I missed something from the example?
Title: Re: XMLConfig example causes SIGSEGV
Post by: jamie on January 10, 2019, 11:46:25 pm
I assume you have dropped it on the form using OI and you have set the file name?

before reading you should test to see if the file is getting created...

if you have done this then try using "XMLConfig1.flush" to purge it to file after you
write the last one..


Also did you set the ROOTName ?

I also want to make note that you are calling this before a file is even created in the OnShow event...

Title: Re: XMLConfig example causes SIGSEGV
Post by: lucamar on January 10, 2019, 11:52:39 pm
Scant as it is, there is some documentation in the wiki beyond that example; see: xmlconf (http://wiki.freepascal.org/xmlconf)

But if I were you I would use TXMLPropStorage; easier and more useful.
Title: Re: XMLConfig example causes SIGSEGV
Post by: Blaazen on January 11, 2019, 12:00:41 am
I cannot see
Code: Pascal  [Select][+][-]
  1.   XMLConfig1:=TXMLConfig.Create;
anywhere in your example.
Title: Re: XMLConfig example causes SIGSEGV
Post by: lucamar on January 11, 2019, 12:06:45 am
I cannot see
Code: Pascal  [Select][+][-]
  1.   XMLConfig1:=TXMLConfig.Create;
anywhere in your example.

It's declared in line 19 and, shouldn't it be auto-created with the form? Isn't it a component?

ETA: Yeah, a component in the "System" tab of the palette.
Title: Re: XMLConfig example causes SIGSEGV
Post by: Blaazen on January 11, 2019, 12:09:30 am
Yes, sorry, it is component on the form. I was confused because there are units XMLConf and XMLCfg, both have class TXMLConfig.
Title: Re: XMLConfig example causes SIGSEGV
Post by: Blaazen on January 11, 2019, 12:18:16 am
There are some demos in ..lazarus/examples. Demo "xmlstreaming" works with TXMLConfig (from Laz2_XMLCfg), created at runtime.
Title: Re: XMLConfig example causes SIGSEGV
Post by: Vodnik on January 11, 2019, 09:32:02 am
@jamie,"yes" to all your questions.
Even when onShow event handler is disabled, SIGSEGV appears at  XMLConfig1.SetValue call.
File is not created.
Title: Re: XMLConfig example causes SIGSEGV
Post by: Vodnik on January 11, 2019, 10:38:16 am
I have fixed the problem. Issue is with XMLConfig1.Filename property. Being assigned via OI, it appears empty during runtime (other defined in OI properties are OK). So I add string Filename:='config.xml' at the beginning of both procedures StoreFormState and RestoreFormState.
Now example works as expected.
Title: Re: XMLConfig example causes SIGSEGV [FIXED]
Post by: jamie on January 12, 2019, 12:04:29 am
You are absolutely correct, it also fails on 1.8.4

 I don't know what release you are using but that is where I am currently installed here.
 
 Are you with the 2.0 CR 3?

 Can someone else verify if this issue exists with Trunk Too?, I did this test on Windersssss 64
Title: Re: XMLConfig example causes SIGSEGV [FIXED]
Post by: jamie on January 12, 2019, 12:40:55 am
Looks like there is a bug in the loading process
Code: Pascal  [Select][+][-]
  1. procedure TXMLConfig.DoSetFilename(const AFilename: String; ForceReload: Boolean);
  2. begin
  3.   if (not ForceReload) and (FFilename = AFilename) then
  4.     exit;
  5.    
  6.   Flush;
  7.   FreeAndNil(Doc);
  8.   if csLoading in ComponentState then
  9.     exit;
  10.   if FileExists(AFilename) and not FStartEmpty then
  11.     LoadFromFile(AFilename)
  12.   else if not Assigned(Doc) then
  13.     begin
  14.     FFileName:=AFileName;
  15.     Doc := TXMLDocument.Create;
  16.     Doc.AppendChild(Doc.CreateElement(FRootName))
  17.     end;
  18. end;                      
  19.  

 it skips out on loading and does not set the name'
Title: Re: XMLConfig example causes SIGSEGV [FIXED]
Post by: lucamar on January 12, 2019, 12:51:16 am
it skips out on loading and does not set the name'

I must be dense today but I don't see where it skips out; unless it's when the component is still loading?

ETA: Yeah, of course, while it's loading it should at least set FFileName = AFileName; else the Filename is lost. My head is murky today :-[
Title: Re: XMLConfig example causes SIGSEGV [FIXED]
Post by: jamie on January 12, 2019, 01:05:26 am
Ok, if this is in the Trunk release maybe someone should report it ?

I find it hard to believe this hasn't been seen before..
Title: Re: XMLConfig example causes SIGSEGV [FIXED]
Post by: lucamar on January 12, 2019, 01:43:47 am
It's exactly the same in trunk's xmlconf.pp (https://svn.freepascal.org/svn/fpc/trunk/packages/fcl-xml/src/xmlconf.pp). No change.

It seems that either nobody has ever used this class or every one who used it did so from code.
Title: Re: XMLConfig example causes SIGSEGV [FIXED]
Post by: Vodnik on January 12, 2019, 07:06:08 am
So I was lucky to be the first who met this bug.
Lazarus 1.8.4, win32.
Should I try to report it to Bugtracker or you guys know better how to proceed with it?
Title: Re: XMLConfig example causes SIGSEGV [FIXED]
Post by: Vodnik on January 12, 2019, 09:19:39 am
Bug report 0034854
Title: Re: XMLConfig example causes SIGSEGV [BUG]
Post by: jamie on January 12, 2019, 02:27:30 pm
Yes you are one LUCKY dude!  :D

Better buy your LOTTO tickets now!
Title: Re: XMLConfig example causes SIGSEGV [FIXED]
Post by: lucamar on January 12, 2019, 03:34:52 pm
So I was lucky to be the first who met this bug.

Probably not, but it looks like any others who did find it were silent. It's the Microsoft way: find a bug, work around it and never tell a soul about it.  :D
Title: Re: XMLConfig example causes SIGSEGV [BUG]
Post by: Blaazen on January 12, 2019, 03:59:09 pm
Quote
Probably not, but it looks like any others who did find it were silent. It's the Microsoft way: find a bug, work around it and never tell a soul about it.  :D

Maybe. However, I never used TXMLConfig from FCL. I always use Laz2_DOM and Laz2_XML... alternatives, they play better with Lazarus because of UTF8.
http://wiki.freepascal.org/XML_Tutorial (http://wiki.freepascal.org/XML_Tutorial)
Title: Re: XMLConfig example causes SIGSEGV [BUG]
Post by: Vodnik on January 12, 2019, 06:24:42 pm
Blaazen, thank you for the info! I start using TXMLConfig just because I have come across a ready made example of how to save/restore form size.  Laz2_DOM and Laz2_XML... looks more powerful and file format is nicer.
Title: Re: XMLConfig example causes SIGSEGV [BUG]
Post by: lucamar on January 12, 2019, 07:18:05 pm
You should really investigate TXMLPropStorage (http://wiki.freepascal.org/TXMLPropStorage): it can save/reload automatically almost any property you care about and it also allows saving/restoring other configuration values. I use it in almost all my applications and it works like a charm.

Although slightly, the page you cited, Remember form position and size (http://wiki.freepascal.org/Remember_form_position_and_size), talks about it too.
Title: Re: XMLConfig example causes SIGSEGV [BUG]
Post by: jamie on January 12, 2019, 07:38:12 pm
Yes I agree 100%, currently where you are at it does exactly what you want.

Not only that, it looks like you can also insert additional items using the same instance supplying
different sections not related to the FORM for example..

--
 More digging, I find that not only does it have this problem but it also calls the Flush and FreeAndNil on a
DOC object that has not yet been created or the DOC variable initialize to Nil..

 I am assuming the heap space for each instance of a Class does not auto-clear the memory to 0 ?

 If this is the case then I can see this component and any one that inherits from it generating a random
Segfault or maybe just corrupting other parts of code..

 In the constructor the inherited constructor is called which is Tcomponent, that takes care of reading the
Properties from file and assigning them. So the DoSetFIleName method gets called during this process and
a Flush, FreeAndNil(DOC) is done, However, the DOC member does not get set until the top constructor completes
, even the overridden method LOADED gets called which also then Sets the filename will hit the same wall
before the Top level constructor completes which is where the actual DOC is initially created.

Code: Pascal  [Select][+][-]
  1. constructor TXMLConfig.Create(AOwner: TComponent);
  2. begin
  3.   inherited Create(AOwner); // This will call the DoSetFileName method for the filename string.
  4.   FRootName := 'CONFIG'; // This looks like it is overriding the property in the OI
  5.   Doc := TXMLDocument.Create;
  6.   Doc.AppendChild(Doc.CreateElement(FRootName));
  7. end;                              
  8.  

Maybe I don't understand the loading procedures of a component with published properties in Lazarus, I know
that is how they work in Delphi as I layout.

 The Constructor in TComponent will do all the fancy stuff to assign the properties

 Maybe the Inherited Create should be called at the end instead ?

Did I over look something here?

Nope: Scratch that last one, I forgot the ReadState is called well after..
Title: Re: XMLConfig example causes SIGSEGV [BUG]
Post by: Vodnik on January 13, 2019, 09:04:48 pm
lucamar, I have tried TXMLPropStorage.
I would definitely use it if not for one nuance: it set the properties at program startup only. In my application I want some control settings to be set depending upon which DB will user open. E.g. list of checkboxes is loaded from DB (list of sites), I would like those of them to be checked, that were checked last time this DB was opened. So I'm planning to store DB name as a section/level and list of controls settings, specific for it in XML file. Maybe not very nice idea from the programming point of view, but convenient for users. Anticipating logical suggestion to store settings in DB itself, I will say that it is not allowed to write or change anything in it.
So, using TXMLPropStorage to store form size, splitter position, etc. and XMLConfig for other controls I don't want. Just one component for all purposes.
Title: Re: XMLConfig example causes SIGSEGV [BUG]
Post by: jamie on January 13, 2019, 09:38:22 pm
You are not restricted to the form or control settings..

you can also set StoredValues and Read them using the OnSaveSaving and OnRestoring events that do not
otherwise get taken care of..

go to the items and click on it, you can add storedValues..

These values must be set during saving and Loading using the events, so if gives you a chance to put in
custom values.

 Also you think you can force an update early
Title: Re: XMLConfig example causes SIGSEGV [BUG]
Post by: lucamar on January 13, 2019, 09:48:10 pm
lucamar, I have tried TXMLPropStorage.
I would definitely use it if not for one nuance: it set the properties at program startup only. In my application I want some control settings to be set depending upon which DB will user open. E.g. list of checkboxes is loaded from DB (list of sites), I would like those of them to be checked, that were checked last time this DB was opened. So I'm planning to store DB name as a section/level and list of controls settings, specific for it in XML file. Maybe not very nice idea from the programming point of view, but convenient for users. Anticipating logical suggestion to store settings in DB itself, I will say that it is not allowed to write or change anything in it.
So, using TXMLPropStorage to store form size, splitter position, etc. and XMLConfig for other controls I don't want. Just one component for all purposes.

Huh? XMLPropStorage has methods to save or load the configuration at any time, not just on start. Moreover, you can use it to store/retrieve any value you want, not just published properties, under however many levels you want. In fact TXMLPropStorage uses XMLConfig at bottom so almost anything that can be done with XMLConfig can also be done with TXMLPropStorage.

But each to its own, I guess; whatever you're comfortable with. :)
TinyPortal © 2005-2018