Dealing with windows' ANYSIZE_ARRAY

Issue #170 resolved
simonzack
created an issue

Windows defines ANYSIZE_ARRAY = 1 in many structs, for example:

typedef struct _TOKEN_PRIVILEGES {
  DWORD               PrivilegeCount;
  LUID_AND_ATTRIBUTES Privileges[ANYSIZE_ARRAY];
} TOKEN_PRIVILEGES, *PTOKEN_PRIVILEGES;

ANYSIZE_ARRAY here is a placeholder, and the struct's actual Privileges may have length more than 1. Now if I wanted to create a new struct using cffi, I would use ffi.new, but this only allows for allocating structs using their sizes, so in this case, only one privilege may be stored.

A simple workaround is pass a buffer around which can hold more than one element, and casting it when needed, but this seems rather inconvenient to me.

I propose that ffi.new take in an additional argument specifying the size of the struct to allocate, so we can pass more than one element around. Is this reasonable?

Comments (6)

  1. simonzack reporter

    I've found a better workaround inspired from the docs, which is to cast a buffer to the desired type, then store the cdata object with the buffer in a global WeakKeyDictionary, so that the buffer is only freed once the cdata object is.

    Given this, I think a better way is to use the proposed from_buffer method from #47 instead, but with the option of using a copy of the entire buffer if it's a bytes object.

  2. Armin Rigo

    You can fix it by using C99's variable arrays if you replace [ANYSIZE_ARRAY] with [ ]. Then indeed ffi.new() works like an array, allowing you to specify the length that you want. You have to specify this length as initializer for the Privileges field:

     ffi.new("PTOKEN_PRIVILEGES", [20, 20])
    

    which is the same as the following:

     ffi.new("PTOKEN_PRIVILEGES", {
         "PrivilegeCount": 20,
         "Privileges": 20})
    

    As usual for arrays you can also list items here (assuming a LUID_AND_ATTRIBUTES has three fields):

     ffi.new("PTOKEN_PRIVILEGES", [2, 
          [[10, 20, 30],
           [15, 25, 35]]])
    
  3. simonzack reporter

    Many thanks! I never knew that arrays could be used this way. In that case I'll be very happy if from_buffer ends up working with variable arrays.

  4. Log in to comment