132-tentative-bss-sizing.c (2414B)
1 /* C 6.9.2 — tentative defs reserve sizeof(T) bytes of zero-init 2 * storage. Companion to 124-tentative-static.c, which only exercised 3 * `int`. tcc-boot2 needs the wide-pointer / array cases too: 4 * mes/globals.c declares `char **environ;`, `int errno;`, etc. 5 * cc.scm has been emitting too few or too many bytes for these 6 * (see :environ → 1 byte, :errno → 16 bytes in libc.P1pp). 7 * 8 * Each global is sized differently and probed via address-of so the 9 * compiler can't fold the read. Wrong sizing manifests as either: 10 * - reads past the slot return 0xff... or stale data → mismatch 11 * - 8-byte stores to a 1-byte slot scribble adjacent globals 12 * (so writing g_pp = X then reading g_int near it shows X 13 * bleeding through). */ 14 15 char g_char; /* 1 byte */ 16 short g_short; /* 2 bytes */ 17 int g_int; /* 4 bytes */ 18 long g_long; /* 8 bytes */ 19 char *g_p; /* 8 bytes */ 20 char **g_pp; /* 8 bytes — the environ shape */ 21 int g_arr[4]; /* 16 bytes */ 22 char *g_parr[3]; /* 24 bytes */ 23 24 int 25 main (void) 26 { 27 /* Tentative defs must zero-init. */ 28 if (g_char != 0) return 1; 29 if (g_short != 0) return 2; 30 if (g_int != 0) return 3; 31 if (g_long != 0) return 4; 32 if (g_p != 0) return 5; 33 if (g_pp != 0) return 6; 34 if (g_arr[0] || g_arr[1] || g_arr[2] || g_arr[3]) 35 return 7; 36 if (g_parr[0] || g_parr[1] || g_parr[2]) 37 return 8; 38 39 /* Each slot must be addressable for its full sizeof(T). 40 * Write a sentinel through the address, read it back. If the 41 * slot is undersized, the high bytes spill into the next global 42 * and the read returns a truncated value. */ 43 long *pl = &g_long; 44 *pl = 0x1122334455667788L; 45 if (g_long != 0x1122334455667788L) 46 return 9; 47 48 g_pp = (char **) 0xdeadbeef00112233L; 49 if ((long) g_pp != (long) 0xdeadbeef00112233L) 50 return 10; 51 52 /* Array element: write the last slot — only valid if the full 53 * 16-byte / 24-byte allocation actually exists. */ 54 g_arr[3] = 42; 55 if (g_arr[3] != 42) return 11; 56 g_parr[2] = (char *) 0x99; 57 if ((long) g_parr[2] != 0x99) return 12; 58 59 /* And no spill: writing g_pp must NOT change g_int next door. 60 * (Slot order in memory follows declaration order in the TU.) */ 61 g_int = 0; 62 g_pp = (char **) 0xfffffffffffffffeL; 63 if (g_int != 0) return 13; 64 65 return 0; 66 }