C++ program is crashing on re-assigning const static member variable using an int pointer

Hi,

Can any one tell me why my following program is crashing?

#include <iostream>
using namespace std;

class CA {
public:
    const static int i;
};

const int CA::i = 10;

int main() {
    int* pi = const_cast<int*>(&CA::i);
    *pi = 9;
    cout << CA::i << endl;
}

Because the static constant value is probably in a read-only memory segment.

Patient: Doctor, it hurts when I do this.
Doctor: Don't do it.

Global constants get hardware write-protection on lots of OSes. The program literally cannot write to them, memory map settings prevent it, the CPU itself knows you shouldn't and throws an exception if you try.

A static variable is as good as a global variable in most respects, this included.

Trying to get around this with trickery isn't a good idea. Even if you alter page protection to let you write, the program might ignore it when you do! The compiler, knowing the variable is a constant, will think "hmm, this variable will never change -- I can save 2 instructions per go by hardcoding it everywhere instead of reading it from memory..."

#include <stdio.h>

static char			 _g_testChar[10] = "-GLOBAL";
static int			 _g_testInt = 1;

static const char	*_g_testConstChar = "-CONSTGLOBAL";
static const int	 _g_testConstInt = 2;

void main(int argc, char **argv)
{
	char				*testConstChar = "-CONSTCHAR";
	char				 testChar[10] = "-STACKCHAR";
	
	const int			 testConstInt = 3;
	int			 		 testInt = 4;
	
	char				*cPtr;
	int					*iPtr;
	
	cPtr = (argc > 1) ?
			( (argv[1][0] == 'c') ? testConstChar :
			  (argv[1][0] == 'C') ? _g_testConstChar : 
			  (argv[1][0] == 'g') ? _g_testChar : testChar )
			: testChar;
			
	iPtr = (argc > 2) ?
			( (argv[2][0] == 'c') ? &testConstInt :
			  (argv[2][0] == 'C') ? &_g_testConstInt :
			  (argv[2][0] == 'g') ? &_g_testInt : &testInt )
			: &testInt;
	
	printf("               Char            Int\n"
		   "Constant:      %-15p %p\n"
		   "Stack:         %-15p %p\n"
		   "Const Global:  %-15p %p\n"
		   "Global:        %-15p %p\n",
		   testConstChar, &testConstInt,
		   testChar, &testInt,
		   _g_testConstChar, &_g_testConstInt,
		   _g_testChar, &_g_testInt);
	
	printf("Trying char [%s]...\n", cPtr);
	*cPtr = '!';
	
	printf("Trying int [%d]...\n", *iPtr);
	*iPtr = 0;
	
	printf("%s\n"
		   "%d\n",
		   cPtr, *iPtr);
}

Play with this...it'll show you what your compiler "protects" and what it doesn't. Then look closely at the address table printed and look for the address space of your OS (for Linux it's here). What you'll probably see is that the variables you aren't allowed to change get put into the text segment, which can't be modified during runtime (easily).

On an aside, I have history with this because HP-UX was much more relaxed in this area. When we ported our HP-UX code to Linux we found out the hard way because our programs started crashing. It seemed innocent enough to us to have the essence of this:

void do_something(char *d)
{
  char *p;

  p = strtok(p, ":");
}

main()
{
  char *data = "this:is:some:data";

  do_something(data);
}

in the code.... Of course, since "this:is:some:data" is stored in the text segment, Linux crashed with the, not so helpful in this case, "segment violation". It dawned on us that the pointer was always in the 0x08 segment when it crashed, then we looked at the Linux address space and found that we were being bit by the compiler putting the string data in the text segment...always. Even worse, for strings it doesn't matter to the compiler whether the data is const or not. For integers, it seems to use const as a hint to go in the text segment if it's global, however stack constants aren't protected (and I suppose really can't be).

As far as Linux is concerned, it seems any quoted string in a source file is immutable and any static const is immutable. Any non-static const is only immutable if you follow the compiler's warnings if you're assigning a const variable's address to a non-const pointer variable.

There's a gcc option to let you write to strings, but this is generally considered a bad idea anyway.

Wish I would have know that back then, lol...would have saved us some re-work on a few applications.

Do you mean, the write-protected char* and global data (BSS area) are put into text segment? I guess it is all part of "Data Segment". Please correct me.