- NSIS Discussion
- system plugin + GetPrivateProfileSectionNames crash
Archive: system plugin + GetPrivateProfileSectionNames crash
shadowpoa
28th August 2013 21:34 UTC
system plugin + GetPrivateProfileSectionNames crash
Hi Everyone,
I'm using a sample script to read ini files, especially to read section names, to determine if a section exist before try to delete it.
The problem is that the installer crashes randomically, I could check that the size of section is always right, but when the error shows, it is at below call:
System::Call `kernel32::lstrlen(i $pNextSection)i.r5`
$NOMESECTION is defined on another macro that calls this func, removing the callback gives the same error, so I choose put complete code here.
I dont know much about pointers, but I think it is all ok with the calls.
My function:
!define GSN_BufferSize 1024
VAR /GLOBAL lpszReturnBuffer
VAR /GLOBAL fncAddr
VAR /GLOBAL nSize
VAR /GLOBAL pNextSection
VAR /GLOBAL IniPath
VAR /GLOBAL iniSecSize
VAR /GLOBAL PTR_FNC
!define GetSectionNames `!insertmacro GetSectionNamesCall`
!macro GetSectionNamesCall _FILE _FUNC
StrCpy `$IniPath` `${_FILE}`
GetFunctionAddress $fncAddr `${_FUNC}`
Call GetSectionNames
!macroend
Function GetSectionNames
System::Call `*(&t${GSN_BufferSize})i.r2`
StrCpy $PTR_FNC $2
StrCpy $lpszReturnBuffer $2
System::Call `kernel32::GetPrivateProfileSectionNames(i,i,t) ($lpszReturnBuffer, ${GSN_BufferSize}, '$IniPath')`
StrCpy $pNextSection $lpszReturnBuffer
${Do}
System::Call `kernel32::lstrlen(i $pNextSection)i.r5`
StrCpy $iniSecSize $5
System::Call `*$pNextSection(&m${GSN_BufferSize} .r9)`
Call $fncAddr
${If} $9 == 'StopGetSectionName'
${ExitDo}
${Endif}
IntOp $pNextSection $pNextSection + $iniSecSize
IntOp $pNextSection $pNextSection + 1
System::Call `kernel32::lstrlen(i $pNextSection)i.r5`
StrCpy $iniSecSize $5
${LoopWhile} $iniSecSize != 0
System::Free $PTR_FNC
FunctionEnd
Function LISTASECTIONCALLBACK
${If} $9 == $NOMESECTION
StrCpy $9 'StopGetSectionName'
${Endif}
FunctionEnd
Anders
29th August 2013 13:54 UTC
If this is a unicode installer:
System::Call `*$pNextSection(&m${GSN_BufferSize} .r9)` should use t type.
IntOp $pNextSection $pNextSection + 1 needs to be + 2
shadowpoa
29th August 2013 15:21 UTC
Hi Anders,
I´m not using Unicode here, its not clear on MSDN if I'll need to call the function with A or W when not specific for one system or another, focus here is only pt-br, and using default chars (32-127).
Is there any problem with these conditions?
Anyway, I'll do some tests based on your post... I'll come back with the results.
shadowpoa
29th August 2013 17:17 UTC
Test Results...
Changing + 1 to + 2 on "IntOp $pNextSection $pNextSection + 1" cuts the first letter from the second section name and so on...
Calling GetPrivateProfileSectionNames or GetPrivateProfileSectionNamesA I have same result.
Calling GetPrivateProfileSectionNamesW gives a empty result on lstrlen call, but Unicode is not the focus , I'll just ignore this.
Changing "*$pNextSection(&m" to "*$pNextSection(&t" gives the same result, and the crashes (randomically) continues.
I Forgot to tell, at the point the function is called, the stack is empty.
The only thing I can tell is that the crash happens upon calling the line
"System::Call `*$pNextSection(&t${GSN_BufferSize} .r9)`"
the last error I´d get has on 3rd section of ini file (total sections is 14 for test file).
Hope this helps, many thanks in advance.
Edit:
Forgot to ask... is there any newer version os system plugin? cant find references on wiki... mine is from 5/12/2009 that come with nsis last nsis version.
Anders
29th August 2013 17:20 UTC
"System::Call `*$pNextSection(&t${GSN_BufferSize} .r9)`" is probably not OK if GSN_BufferSize is above 1024.
Try my version
shadowpoa
29th August 2013 18:54 UTC
Everything ok
Anders,
So far so good, everything ok.
Can you explain what´s wrong with the other implementation?
Í'll keep testing, but assume it is ok, tested a lot of times without crash.
I dont understand some points on new code like the lines below.
!ifdef IniGetSectionNames_StopEnum
${If} $3 == "$\n"
System::Call '*$0(&i${NSIS_CHAR_SIZE} 0)'
${EndIf}
!endif
Goto loop
This line is just to not test strlen = 1 for the 'newline' char?
I dont get how this pointer Works...
Thanks again, you have saved me a lot of time, and I think this function is useful to others on fórum... how we can update the wiki with this?
Anders
29th August 2013 19:07 UTC
The \n is not a valid section name so it is a good magic value, the system call just "ends" the string (In C this would be mystrptr[0] = '\0';) so lstrlen will return 0 and end the loop...
shadowpoa
29th August 2013 19:55 UTC
Many thanks
Anders,
I have imagined that 'magic value', but dunno how to put it in code.
Many thanks for the big Help and enlightment about your solution approach.
Moderator can mark this as solved if needed.