Recent

Author Topic: Is there the difference for dll/so calling from console and LCL application?  (Read 12936 times)

mig-31

  • Sr. Member
  • ****
  • Posts: 305
Hi,

I would like to ask about if there is any difference, when I call function from dll/so library (c library), when I call it from console application and LCL application, created in Lazarus 1.1 FPC 2.6.0.

My test apllication, which have same code in main body of console application (begin end.) and LCL application in ButtonClick, behaive different: console app works correctly, but LCL crashed.

Thank you for some information.
Lazarus 2.2.6 - OpenSuse Leap 15.4, Mageia 8, CentOS 7

Leledumbo

  • Hero Member
  • *****
  • Posts: 8746
  • Programming + Glam Metal + Tae Kwon Do = Me
I would like to ask about if there is any difference, when I call function from dll/so library (c library), when I call it from console application and LCL application, created in Lazarus 1.1 FPC 2.6.0.
No. However, depending on the contents, you might need to call SetExceptionMask because some C libraries bypass those exception flags for certain conditions.

Ñuño_Martínez

  • Hero Member
  • *****
  • Posts: 1186
    • Burdjia
My test apllication, which have same code in main body of console application (begin end.) and LCL application in ButtonClick, behaive different: console app works correctly, but LCL crashed.
My magic mirror is in the 10000 predictions revision. ::)  Please, can you provide more information about the crash?  Such as source snipets, error messages, etc.  Thanks.
Are you interested in game programming? Join the Pascal Game Development community!
Also visit the Game Development Portal

mig-31

  • Sr. Member
  • ****
  • Posts: 305
Hi,

I appologize, that it taked me more time, but it was so close before Cristmas.

There is a code
Code: [Select]
procedure TForm1.StartBtnClick(Sender: TObject);
var
  resourceName:string = 'Dev3';
  vi:ViSession;
  actualRecordLength:ViInt32;
  actualSampleRate:viReal64;
  data:array of viReal64;
  channel:string = '0';
  wfmInfo:niScope_wfmInfo;
  procedure CheckError(AErrorCode: ViStatus; Avi: viSession);
var
  errorMessage:string;
begin
  SetLength(errorMessage,MAX_ERROR_DESCRIPTION);
  if (AErrorCode<>VI_SUCCESS) then begin
    niScope_GetErrorMessage(Avi,AErrorCode,Length(errorMessage),@errorMessage[1]);
    ShowMessage(errorMessage);
    if Avi<>VI_NULL then begin
        niScope_close(Avi);
    end;
    Halt;
  end;
 end;
begin
  //SetExceptionMask([exInvalidOp, exDenormalized, exZeroDivide, exOverflow, exUnderflow]);
  //Setup hardware
  //vi:=VI_NULL;
  //resourceName:='Dev3';
  //channel:='0';
  //Init Session
  CheckError(niScope_init(Pchar(@resourceName[1]),NISCOPE_VAL_FALSE,NISCOPE_VAL_FALSE,@vi),vi);

  //auto setup measurement
  CheckError(niScope_AutoSetup(vi),vi);

  //read the actual record length and sample rate setuped by autosetup
  CheckError(niScope_ActualRecordLength(vi,@actualRecordLength),vi);
  CheckError(niScope_SampleRate(vi,@actualSampleRate),vi);
  //DataMemo.Append('Record lenght: '+IntToStr(actualRecordLength));
  //DataMemo.Append('Sample Rate: '+FloatToStrF(actualSampleRate,ffFixed,6,2));

  //set buffer length(array) and read data
  if  actualRecordLength >1 then begin
    SetLength(data,actualRecordLength);
    niScope_Read(vi,@channel[1],5.0,ActualRecordLength,@data[1],@wfmInfo);
    //shows first 1000 samples
    //for i:=1 to 1000 do DataMemo.Append('Sample['+IntToStr(i)+'] = '+FloatToStrF(data[i],ffFixed,4,2));
  end;

  //close Session
  if vi<>VI_NULL then niScope_close(vi)
end;                                   

All fucntions starts with niScope called from dll/so library niscope32.dll (one of the library needs for operating with National Instruments digitazer cards ).

In console application code works, but in LCL application not.
There is a screenshot of assembler code in the attachment.

After debugging step by step I found out that code works, but  application crashed after code execution with External:SIGSEGV



« Last Edit: January 06, 2015, 05:45:53 pm by mig-31 »
Lazarus 2.2.6 - OpenSuse Leap 15.4, Mageia 8, CentOS 7

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11382
  • FPC developer.
Not generally. I would check for bugs first, that is the most likely reason for the difference.

The LCL version probably simply executes more code after the call finishes (GUI update, LCL shutdown), touching more data, and thus more chance to crash if a bug has written random memory.

Leledumbo

  • Hero Member
  • *****
  • Posts: 8746
  • Programming + Glam Metal + Tae Kwon Do = Me
Open call stack window, find the entry corresponding to your source.

mig-31

  • Sr. Member
  • ****
  • Posts: 305
After debugging step by step I found out that code works, but  application crashed after code execution with External:SIGSEGV

There is a stack window.
Lazarus 2.2.6 - OpenSuse Leap 15.4, Mageia 8, CentOS 7

Leledumbo

  • Hero Member
  • *****
  • Posts: 8746
  • Programming + Glam Metal + Tae Kwon Do = Me
After debugging step by step I found out that code works, but  application crashed after code execution with External:SIGSEGV

There is a stack window.
Line 92 in main.pas, what does it do?

mig-31

  • Sr. Member
  • ****
  • Posts: 305
Line 92 is end for ButtonOnClick procedure
« Last Edit: January 05, 2015, 05:27:33 pm by mig-31 »
Lazarus 2.2.6 - OpenSuse Leap 15.4, Mageia 8, CentOS 7

engkin

  • Hero Member
  • *****
  • Posts: 3112
I believe it is a bug in your code. The 5th parameter in niScope_Read is a pointer to an array of type double. You passed a pointer to an array of type char. The size of the required array is bigger than the one you provided. Maybe if you pass the correct size:
Code: [Select]
  SetLength(data,actualRecordLength * SizeOf(double));

Leledumbo

  • Hero Member
  • *****
  • Posts: 8746
  • Programming + Glam Metal + Tae Kwon Do = Me
Line 92 is end for ButtonOnClick procedure
Indeed the error happens during automatic deallocation of managed variables then. A possibility is in:
Code: [Select]
SetLength(data,actualRecordLength);
niScope_Read(vi,@channel[1],5.0,ActualRecordLength,@data[1],@wfmInfo);
Most API (I haven't checked this niscope library API so I just use common sense when dealing with C libraries) will expect length (some APIs expect size, though) and address of the first element. But @data[1] is address of the second element, so try using @data[0].

mig-31

  • Sr. Member
  • ****
  • Posts: 305
Hi,

thank you for answer.

I corrected the code to
Code: [Select]
niScope_Read(vi,@channel[1],5.0,ActualRecordLength,@data[0],@wfmInfo);
and I also try to set array size
Code: [Select]
  SetLength(data,actualRecordLength * SizeOf(double));
and
Stack window is the same
Code: [Select]
#0 fpc_reraise at :0
#1 ?? at :0
#2 TFORM1__STARTBTNCLICK(0x102ec0, <error reading variable>) at main.pas:92
#3 TCONTROL__CLICK(<error reading variable>) at .\include\control.inc:2720
#4 TBUTTONCONTROL__CLICK(<error reading variable>) at .\include\buttoncontrol.inc:54
#5 TCUSTOMBUTTON__CLICK(<error reading variable>) at .\include\buttons.inc:169
#6 TBUTTONCONTROL__WMDEFAULTCLICKED({MSG = 66567, WPARAM = 0, LPARAM = 0, RESULT = 0, WPARAMLO = 0, WPARAMHI = 0, WPARAMFILLER = {}, LPARAMLO = 0, LPARAMHI = 0, LPARAMFILLER = {}, RESULTLO = 0, RESULTHI = 0, RESULTFILLER = {}}, <error reading variable>) at .\include\buttoncontrol.inc:20
#7 SYSTEM_TOBJECT_$__DISPATCH$formal at :0
#8 TBUTTONCONTROL__ISCHECKEDSTORED(<error reading variable>) at .\include\buttoncontrol.inc:16
#9 TWINCONTROL__WNDPROC({MSG = 66567, WPARAM = 0, LPARAM = 0, RESULT = 0, WPARAMLO = 0, WPARAMHI = 0, WPARAMFILLER = {}, LPARAMLO = 0, LPARAMHI = 0, LPARAMFILLER = {}, RESULTLO = 0, RESULTHI = 0, RESULTFILLER = {}}, <error reading variable>) at .\include\wincontrol.inc:5326
#10 DELIVERMESSAGE(0x102ec0, void) at lclmessageglue.pas:112
#11 WINDOWPROC(1049672, 273, 11968, 1180764) at win32callback.inc:2480
#12 CUSTOMFORMWNDPROC(1049672, 273, 11968, 1180764) at win32wsforms.pp:395
#13 USER32!IsWindowVisible at :0
#14 ?? at :0
#15 USER32!IsWindowVisible at :0
#16 ADJUSTFORMBOUNDS at win32wsforms.pp:316
#17 USER32!DestroyReasons at :0
#18 ?? at :0
When I commented the code and leave only three functions
Code: [Select]
niScope_init(...)
niScope_AutoSetup(...)
niScope_close(...)
program crashed with the same error.

In C code for measurement data (data array in my code) allocate by this code ViReal64 = double:
Code: [Select]
ViReal64 *waveformPtr = NULL;
waveformPtr = (ViReal64*) malloc (sizeof(ViReal64) * actualRecordLength);
niScope_Read(vi,channel,5.0,actualRecordLength,waveformPtr,&wfmInfo);
Probably it is not directly array.
« Last Edit: January 06, 2015, 11:09:32 am by mig-31 »
Lazarus 2.2.6 - OpenSuse Leap 15.4, Mageia 8, CentOS 7

Leledumbo

  • Hero Member
  • *****
  • Posts: 8746
  • Programming + Glam Metal + Tae Kwon Do = Me
I finally googled for the function. Its documentation says:
Quote
wfm   ViReal64 *   Returns an array whose length is the numSamples times number of waveforms. Call niScope_ActualNumWfms to determine the number of waveforms.
That bold part is what you have to call SetLength with.

mig-31

  • Sr. Member
  • ****
  • Posts: 305
If I understand you correctly. Using of open array of ViReal64 (data:array of ViReal64) variable is correct.
Error probably is in array length.
Lazarus 2.2.6 - OpenSuse Leap 15.4, Mageia 8, CentOS 7

engkin

  • Hero Member
  • *****
  • Posts: 3112
When I saw Data[1] I thought you were using a string as a buffer, sorry. You don't need to multiply with SizeOf(double).  As usual Leledumbo is right, you need to correct the size of the array.

 

TinyPortal © 2005-2018