[PB5.0, x64] Stock constant and structure definition

Windows specific forum
Inf0Byt3
PureBasic Fanatic
PureBasic Fanatic
Posts: 2236
Joined: Fri Dec 09, 2005 12:15 pm
Location: Elbonia

[PB5.0, x64] Stock constant and structure definition

Post by Inf0Byt3 »

Been playing with a code for creating a mutex on x64 and I think I found a bug.

First problem: It seems that in both x86 and x64 PureBasic, #SECURITY_DESCRIPTOR_MIN_LENGTH is equal to 20. On x86, this is valid, but on x64, the value should be (?) 40 as the size of structure SECURITY_DESCRIPTOR is 40 bytes (longs become integers and there are 4 extra bytes of padding). More info here: http://bugs.freepascal.org/view.php?id=12619).

See my edit below and disregard the following.

Second problem: In PureBasic x64, the structure SECURITY_ATTRIBUTES has 8 bytes of padding. When using it in my code and compile with purifier enabled, the mutex is not created and GetLastError_() returns 998 (Invalid access to memory location). If I disable the purifier, the mutex is successfully created. The strange thing is that if I redefine the structure and eliminate the padding, it works with purifier enabled or disabled. In my opinion, this structure maybe doesn't need padding? I doubt it is a purifier bug.

Here's my code:

Code: Select all

Structure SECURITY_ATTRIBUTES_ ;Redefined and eliminated padding
  nLength.l
  ;PB_Alignment1.b[4]
  *lpSecurityDescriptor.l
  bInheritHandle.l
  ;PB_Alignment2.b[4]
EndStructure

#SECURITY_DESCRIPTOR_MIN_LENGTH_ = SizeOf(SECURITY_DESCRIPTOR)

Procedure.i CreateMyMutex(Name.s)
  Protected Security.SECURITY_ATTRIBUTES  ;Replace with Security.SECURITY_ATTRIBUTES_ to make it work with purifier enabled
  Protected *Descriptor, hMutex.i, Result.i
  *Descriptor = AllocateMemory(#SECURITY_DESCRIPTOR_MIN_LENGTH) ;Replace with #SECURITY_DESCRIPTOR_MIN_LENGTH_ and it works
  If *Descriptor <> 0
    Security\nLength = SizeOf(SECURITY_ATTRIBUTES) ;Replace with Security.SECURITY_ATTRIBUTES_ to make it work with purifier enabled
    Security\bInheritHandle = #False
    Security\lpSecurityDescriptor = *Descriptor
    If InitializeSecurityDescriptor_(Security\lpSecurityDescriptor, #SECURITY_DESCRIPTOR_REVISION) <> 0
      If SetSecurityDescriptorDacl_(Security\lpSecurityDescriptor, #True, 0, #False) <> 0
        hMutex = CreateMutex_(@Security, 0, @Name) ;Will overflow due to bad definition of #SECURITY_DESCRIPTOR_MIN_LENGTH
        Error = GetLastError_()
        Debug "Error: "+Str(Error)
        If hMutex <> 0
          Result = hMutex
        EndIf
      EndIf
    EndIf
    FreeMemory(*Descriptor)
  EndIf
  ProcedureReturn Result
EndProcedure

Debug "Result: "+Str(CreateMyMutex("test"))
[Edit]

I am baffled. The mutex gets created when using the unpadded structure but then OpenMutex fails when trying to open the mutex from another process (denoting bad initialization of the security attributes). 32-bit exes made on x86 from the exact code do work when being run on x64. It's hard to sum it up but there is a problem with memory access somewhere. I got back to using the original, padded PureBasic structure because that's how it should be defined. In the end, found out that if I replace AllocateMemory with LocalAlloc_(), the code works with the purifier enabled. Could it be because of this?
http://msdn.microsoft.com/en-us/library/windows/desktop/aa379561%28v=vs.85%29.aspx wrote:Several functions that use the SECURITY_DESCRIPTOR structure require that this structure be aligned on a valid pointer boundary in memory. These boundaries vary depending on the type of processor used. Memory allocation functions such as malloc and LocalAlloc return properly aligned pointers.
Here's a sample:

Code: Select all

#SECURITY_DESCRIPTOR_MIN_LENGTH_ = SizeOf(SECURITY_DESCRIPTOR)

Procedure.i CreateMyMutex(Name.s)
  Protected Security.SECURITY_ATTRIBUTES
  Protected *Descriptor, hMutex.i, Result.i
  ;With AllocateMemory and Purifier -> error code 998 (invalid memory access)
  *Descriptor = AllocateMemory(#SECURITY_DESCRIPTOR_MIN_LENGTH_)
  ;But this works
  ;*Descriptor = LocalAlloc_(#LPTR,#SECURITY_DESCRIPTOR_MIN_LENGTH_)
  If *Descriptor <> 0
    Security\nLength = SizeOf(SECURITY_ATTRIBUTES)
    Security\bInheritHandle = #False
    Security\lpSecurityDescriptor = *Descriptor
    If InitializeSecurityDescriptor_(Security\lpSecurityDescriptor, #SECURITY_DESCRIPTOR_REVISION) <> 0
      If SetSecurityDescriptorDacl_(Security\lpSecurityDescriptor, #True, 0, #False) <> 0
        hMutex = CreateMutex_(@Security, 0, @Name)
        Error = GetLastError_()
        Debug "Error: "+Str(Error)
        If hMutex <> 0
          Result = hMutex
        EndIf
      EndIf
    EndIf
    ;FreeMemory(*Descriptor)
  EndIf
  ProcedureReturn Result
EndProcedure

Debug "Result: "+Str(CreateMyMutex("test"))
I'd appreciate any input on this issue.
None are more hopelessly enslaved than those who falsely believe they are free. (Goethe)
Fred
Administrator
Administrator
Posts: 18360
Joined: Fri May 17, 2002 4:39 pm
Location: France
Contact:

Re: [PB5.0, x64] Stock constant and structure definition

Post by Fred »

Fixed the #SECURITY_DESCRIPTOR_MIN_LENGTH value on x64. AllocateMemory() uses the regular HeapAlloc() which returns 8-bytes aligned memory, which isn't enough for your needs, so yes you need to use LocalAlloc() here. I moved the thread to Windows forum so we keep this answer for future reference.
Inf0Byt3
PureBasic Fanatic
PureBasic Fanatic
Posts: 2236
Joined: Fri Dec 09, 2005 12:15 pm
Location: Elbonia

Re: [PB5.0, x64] Stock constant and structure definition

Post by Inf0Byt3 »

Thank you for the explanation Fred, much appreciated.
None are more hopelessly enslaved than those who falsely believe they are free. (Goethe)
Post Reply