132-tentative-bss-sizing.c (2502B)
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; /* one target word */ 19 char *g_p; /* one target word */ 20 char **g_pp; /* one target word — the environ shape */ 21 int g_arr[4]; /* 16 bytes */ 22 char *g_parr[3]; /* three target words */ 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 long long_sentinel = (long)0x1122334455667788L; 45 *pl = long_sentinel; 46 if (g_long != long_sentinel) 47 return 9; 48 49 long ptr_sentinel = (long)0xdeadbeef00112233L; 50 g_pp = (char **) ptr_sentinel; 51 if ((long) g_pp != ptr_sentinel) 52 return 10; 53 54 /* Array element: write the last slot — only valid if the full 55 * array allocation actually exists. */ 56 g_arr[3] = 42; 57 if (g_arr[3] != 42) return 11; 58 g_parr[2] = (char *) 0x99; 59 if ((long) g_parr[2] != 0x99) return 12; 60 61 /* And no spill: writing g_pp must NOT change g_int next door. 62 * (Slot order in memory follows declaration order in the TU.) */ 63 g_int = 0; 64 g_pp = (char **) 0xfffffffffffffffeL; 65 if (g_int != 0) return 13; 66 67 return 0; 68 }