← board

An array of pointers to arrays has no pointee shape

Repro (gcc prints 16 6 6, pxx segfaults):

typedef float vec4[4]; typedef vec4 mat4[4];
static float mulN(mat4 *m[], int n) { float s = 0; int i;
  for (i = 0; i < n; i++) s += (*m[i])[i][i]; return s; }
int main(void) { mat4 a = {{1},{0,2}}, b = {{5},{0,6},{0,0,7}}, c = {{9},{0,9},{0,0,9},{0,0,0,9}};
  mat4 *arr[3] = {&a, &b, &c};
  printf("%g %g\n", mulN(arr, 3), (*arr[1])[1][1]); }

cglm's own shape is mul(*matrices[0], *matrices[1], dest), which needs only the decay.

Scope: this is a second level of pointee description. A symbol whose ELEMENT (for an array) or whose pointee's pointee (for a depth-2 pointer) is an array of known dims. The consumers are:

Stamped today, all at depth 1:

2026-09-27 (frankD): the sizeof consumer gives a SILENT wrong count, and that is cglm's first failure

Measured with the v441 pinned binary (sha256 4ebfa2d047a2, commit 5c1696ca79), tree ab1960b987, against gcc 15 on the same host:

typedef float vec4[4]; typedef vec4 mat4[4];
mat4 a, b, c; mat4 *m[] = { &a, &b, &c }; mat4 *p = &a;
printf("%d %d %d %d\n", (int)sizeof(m), (int)sizeof(m[0]), (int)sizeof(p), (int)(sizeof(m)/sizeof(m[0])));

gcc 24 8 8 3, pxx 128 128 8 1. With vec4 *m[] (one level of array typedef) pxx agrees with gcc WRONG, corrected 2026-09-27: those numbers were gcc's. The probe also contained float (*q[2])[4], which pxx refuses, so pxx's half of pxx ... && run; gcc ... && run printed nothing and gcc's line was read as pxx's. Measured separately, vec4 *m[2] gives pxx 32 32 8 against gcc 16 8 16: the one-level typedef was wrong the same way. cglm's own test suite (the v425 restamp kit's drv/cglm_all.c) now BUILDS on v441, where v425 refused it, and runs until mat4_mulN, which passes sizeof(matrices) / sizeof(matrices[0]) = 1 and trips cglm's len > 1 assertion (rc=134). So the observable reached first is a wrong count with no diagnostic, not the segfault in the repro above.

Re-ranked 45 -> 70 on 2026-09-27 (frankuser, coordinator): a silent wrong value on real code (cglm) ranks above a refusal. docs/reference/known-issues.md carries a "Silently wrong" row for it until the fix lands; remove that row in the fixing commit. Note the size is not a simple multiple: sizeof m is 128 for three elements (neither 3x8 nor 3x64), so do not assume "pointee size per element" without printing it.

2026-09-27 (frankD): fixed

Causes, both in the declaration and neither in the metadata readers alone:

  1. The local path folded the typedef's dims into the ARRAY even when the declarator had stars (mat4 *m[3] became float[3][4][4]). The global path was already guarded, but stamped only the OUTER length of a multi-dim typedef pointee (mat4 *g: sizeof *g 16, gcc 64).
  2. Nothing recorded an array ELEMENT's pointee, nor the base pointee of a depth-2 pointer (mat4 **pp, and the parameter mat4 *m[], whose stamp the parameter path deliberately cleared).

The carrier: the element's pointee shape is stamped on the array symbol (after the array's own spans when it is multi-dim, CPtrElemSpanOff), and a depth-2 pointer's stamp means its BASE pointee. The one reader is CPtrToArrShapeSym (ir.inc), for p, m[i], pp[i] and *pp; its consumers are CDerefDecayStride, the pointer-to-array subscript arm (which now also unwraps (*x)[i].. into x[0][i]..), IRPointerStride and the sizeof descriptor walk.

Found while varying the shape, fixed here because they are the same path:

Evidence, all x86-64 against gcc 15, compiler sha256 691d7e9ae082:

Filed, not fixed (backlog-cfront):

Log