Для доступа к ~ 2 ГБ памяти вам нужен только 31-битный адрес. Однако в 32-битных системах адреса имеют длину 32 бита и, следовательно, указатели имеют длину 32 бита.
Как описано в книге, в ранних версиях windows разработчики могли использовать только 2 ГБ памяти, поэтому последний бит в каждом 32-битном указателе можно было использовать для других целей, так как он ВСЕГДА был нулевым. Однако перед использованием адреса этот дополнительный бит нужно было снова очистить, по-видимому, чтобы программа не взломала sh, потому что она пыталась получить доступ к адресу размером более 2 ГБ.
Код, вероятно, выглядел как-то вот так:
int val = 1;
int* p = &val;
// ...
// Using the last bit of p to set a flag, for some purpose
p |= 1UL << 31;
// ...
// Then before using the address in some way, the bit has to be cleared again:
p &= ~(1UL << 31);
*p = 3;
Теперь, если вы можете быть уверены, что ваши указатели будут указывать только на адрес, где старший бит (MSB) равен нулю, то есть в адресном пространстве ~ 2 ГБ, это хорошо. Однако, если адресное пространство увеличивается, некоторые указатели будут иметь 1 в своем старшем разряде, и, очистив его, вы установите указатель на неправильный адрес в памяти. Если вы затем попытаетесь читать или писать по этому адресу, у вас будет неопределенное поведение, и ваша программа, скорее всего, выйдет из строя в результате пожара .