1

I'm looking at this piece of C code from Microsoft wincrypt.h header file

//+-------------------------------------------------------------------------
//  Attributes
//
//  Where the Value's PATTR_BLOBs are in their encoded representation.
//--------------------------------------------------------------------------
// certenrolls_begin -- CRYPT_ATTRIBUTE
typedef struct _CRYPT_ATTRIBUTE {
    LPSTR               pszObjId;
    DWORD               cValue;
    PCRYPT_ATTR_BLOB    rgValue;
} CRYPT_ATTRIBUTE, *PCRYPT_ATTRIBUTE;

typedef struct _CRYPT_ATTRIBUTES {
    DWORD                cAttr;
    PCRYPT_ATTRIBUTE     rgAttr;
} CRYPT_ATTRIBUTES, *PCRYPT_ATTRIBUTES;
// certenrolls_end

and I'm running this example How To Get Information from Authenticode Signed Executables. I can see in the code that both rgValue and rgAttr are accessed as arrays, e.g.

pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].pbData,
pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].cbData,

If I haven't seen the example, I'd never get this. Is it something Windows specific or my total ignorance about struct and type declarations in C?

vitr
  • 6,766
  • 8
  • 30
  • 50
  • 3
    That's why you shouldn't use typedef unless it increases code readability. – Raman May 11 '18 at 06:20
  • @David Heffernan You can't know that it is not an array, it' just some fragment of the code, in the next lines that you don't see there might be `rgValue[1].cbData`. – малин чекуров May 11 '18 at 07:54
  • 2
    @малинчекуров I quote my own comment, "it looks like". But actually we can know. We can read the documentation. Which says for `rgValue`, *Pointer to an array of CRYPT_INTEGER_BLOB structures.* In fact, we could just read the field names and see `cValue` and `rgValue` and infer that `cValue` was the count. – David Heffernan May 11 '18 at 07:58
  • 1
    1 element this is also array. always `T* pt` is pointer to array we can say and reference in as `*pt` or `pt[0]`. simply array can have single element or variable. if we have only `T* pt` this is mean pointer to single element (array). we have `T* pt; ULONG nt` - pointer to `nt` elements array – RbMm May 11 '18 at 08:28
  • 2
    @RbMm, I don't like this phrasing that conflates a scalar and a unit-length array. These are not the same types in C. `T*` is not a pointer to an array. It's a pointer to a scalar `T` value, i.e. when dereferenced, the result is a scalar value, not an array. `T*` may point to the first element of a `T[]` array. – Eryk Sun May 11 '18 at 10:51
  • 1
    @eryksun - in *c* very weak difference between pointer to object `T* a` and array of objects `T a[n]`. actually array is also pointer. may be const pointer if we declare as `T a[n]`. but if pass this as function arument - we can do this as `void fn (T a[])` where `a` already not const pointer to array. (can do `a++` say). or can declare function as `void fn(T* a)` - binary code will be the same as in first case. which src code form select most question of style. at least it seems to me so. I'm not at all *c/c++* programmer – RbMm May 11 '18 at 11:08
  • *`T*` is not a pointer to an array* - i mean by sense, by binary data - we can consider single element as 1 element array. not by formal language definitons – RbMm May 11 '18 at 11:13
  • 2
    @RbMm, an array is not a pointer; they are completely different at the binary level. A pointer variable is a symbol for a memory location that contains a machine-sized address, whereas an array is a symbol for a memory location of the first element of an array of values of the given type. Also, semantically, dereferencing a `T*` is a scalar `T`. You cannot pass or return the dereferenced value as a pointer, whereas a C array such as `T a[1]` degenerates as a pointer to the first element in this case. – Eryk Sun May 11 '18 at 11:51
  • 1
    @eryksun here `void fn(T a[])` - `a` pointer or array ? this i mean. here `a` is pointer size variable. but look like (by syntax `[]`) as array. in other case, when we declare `T a[n]` (in structure, stack, global data) - `a` of course already not hold any memory itself, but constant offset from register(this), stack, image base.. but initial question was `T* a` - a is pointer to single `T` data or to array of n `T`. by fact first is case of second (array of 1 T). actual count in `cAttr` - which can be and 0, and 1 and any – RbMm May 11 '18 at 13:03
  • 1
    @RbMn, in `void fn(T a[])`, the parameter `a` is a pointer, and, at the binary level, the indexing operation is fundamentally different from indexing an array, but both yield a `T` value. This is a convenience syntax for `T *a`, as a *hint* to the reader that `fn` is normally called with a pointer to an array, since C doesn't support passing or returning actual array aggregates. A `T *a` is a pointer to a `T`; that is all we know. It may point to a `T` that's the first element of an array, or the 42nd, or to a scalar `T` value. We cannot know the answer sans context in code and documentation. – Eryk Sun May 11 '18 at 13:58

3 Answers3

5

PCRYPT_ATTR_BLOB is CRYPT_ATTR_BLOB*, pointer to CRYPT_ATTR_BLOB. This can either be a pointer to a single value, or a pointer to an array. You can't tell from the type declaration and must read the documentation.

That documentation says:

cValue

A DWORD value that indicates the number of elements in the rgValue array.

rgValue

Pointer to an array of CRYPT_INTEGER_BLOB structures.

So in this case rgValue is a pointer to an array.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
2

rgAttr and rgValue are of type pointer to struct :

typedef struct _CRYPT_ATTRIBUTES *PCRYPT_ATTRIBUTES;
typedef struct _CRYPT_ATTRIBUTE *PCRYPT_ATTRIBUTE;

Now when you do PCRYPT_ATTRIBUTE rgAttr, it will be quivalent to struct _CRYPT_ATTRIBUTE *rgAttr and to CRYPT_ATTRIBUTE *rgAttr.

Generally speaking, using typedef on pointers has only drawbacks. The only case that typedef on pointer is actually helpful is when the pointer is a function pointer.

1

Notice that MS is pretty constant in the Hungarian-style name decoration, the "rg" prefix tells you it's an array even without going to the docs.

SoronelHaetir
  • 14,104
  • 1
  • 12
  • 23