Thread: Referencing outside the bounds of an array does not generate an error

  1. #1
    Registered User
    Join Date
    Jun 2009
    Posts
    26

    Referencing outside the bounds of an array does not generate an error

    Hi all,

    When I accidentaly tried to reference outside the bounds of an array in C, I surprisingly discovered that not only the compiler (GCC) didn't generate an error, but the reference indeed seemed valid as I got the assigned value with printf.

    In particular, I had the following:

    Code:
    uint32_t ArrayA[10][2];
    
    void test_wrong_referece(void);
    
    void test_wrong_referece(void)
    {
      uint32_t x=100;
    
      ArrayA[0][1]=x;
      ArrayA[0][2]=x+100;
      ArrayA[0][3]=x+200;
    
      printf("ArrayA[0][1] = %d\n", ArrayA[0][1]);
      printf("ArrayA[0][2] = %d\n", ArrayA[0][2]);
      printf("ArrayA[0][3] = %d\n", ArrayA[0][3]);
    }
    
    main(){
      test_wrong_referece();
      return 0;
      }
      
      
    Output:
      ArrayA[0][1] = 100
      ArrayA[0][2] = 200
      ArrayA[0][3] = 300
    The 'ArrayA[0][2]=x+100;' and 'ArrayA[0][3]=x+200;' shoudn't be valid as they exceed the bounds of ArrayA so I would expect a run-time error to be generated when I tried to access (and of course GCC to inform me before that).

    Could someone help me on that please?

    Thanks in advance.

  2. #2
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    There is not really any such thing as a (generic, automatic, built-in) run-time error in C, because it is a 100% compiled language. There is no interpreter or virtual machine to generate such a thing. Of course, you can code fatal errors in yourself.

    There is the possibility of the OS killing the process while running, eg, if it tries to access memory it doesn't have, you get a segmentation fault. Going out of bounds on an array does not guarantee that, however, because the "out of bounds" may still be within the program's own memory. This is actually worse, because it means you may have overwritten some of your own data, but there is no way to detect that and the consequences may be very strange.

    Which is why it is very important in C to keep track of what you are doing and not go out of bounds.

    WRT to compile time, the C standard does not require the compiler to keep track of your allocations (only very simple violations could be caught then anyway) -- that's your job. There are some memory profiling tools around that can detect some out of bounds errors, and you may find an IDE or code validator that will also find some hard-coded violations. However, most probably happen at runtime due to faulty logic, so unless you are running the process inside a debugger or something, again, it's on its own. Short story: the only thing you can rely on in this regard is careful programming.
    Last edited by MK27; 01-16-2012 at 08:35 AM.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  3. #3
    Registered User
    Join Date
    Dec 2011
    Posts
    795
    Strangely, GDB catches the error during run-time, only if the variable is local. Any idea why it treats globals and locals differently?

  4. #4
    Registered User ledow's Avatar
    Join Date
    Dec 2011
    Posts
    435
    Relying on GDB to catch your out-of-bound errors is not an effective way to go about things. If you need to make sure you don't access out of bounds, you need to code the test for yourself on every access (by having a wrapper function when you want to access an element of the array, etc.) - that's what C doesn't do for you and why it's faster than other languages (all those other languages DO check every access for correct array indices, even if you don't see it, hence why they are slower than C for tasks like this). C is the Ferrari-without-seatbelts: Faster than your other car but a lot more dangerous if you don't use it properly.

    GDB may or may not catch the error, as you've noticed, and that depends on how it compiles (the compiler is free to throw away all sorts of junk if it likes), what options you have turned on, where you're looking and where the compiler decided to store variables. You can look into the ASM if you're really interested in why it missed being a global but most probably you just don't have relevant options turned on.

    C is NOT a safe language - it always relies on you being safe and taking precautions where necessary. You will *not* get compiler warnings about this. The syntax of the source is PERFECTLY valid (and that's all the compiler cares about), it just happens to access out of bounds when actually executed (and without executing the program and trying EVERY SINGLE CODEPATH in an automated fashion, there's no way for a language to detect such instances just from a compile - it's related to the Halting problem). The statement given may or may not execute correctly depending on things like the resolution of memory allocations (i.e. does malloc / the stack allocator always give you a 1k block no matter what you ask for below that size, thus even writing out of bounds actually writes in "writable" memory and thus no error?), whether DEP etc. are available on the system and turned on, and so on. Basically, C writes to the block because you told it to and only the OS / processor can say "Oi, you can't do that!" and when they do, C can't do anything to deal with it but terminate the program. In other languages, they would check the bounds every time you read from / write to the array and throw exceptions, etc. at great computational expense.

    If you're expecting GCC to hold your hand on this, you're mistaken. Yes, in other languages you'd get errors but NOT here. C is *designed* to have enough access to the computer that you can shoot yourself in the foot quite easily while it plays dumb. It's not C's job to guard against things like this or even look for them. That's your job and the OS's job. Be thankful that GCC warns about many things that it has no obligation to do so. This is a case where it doesn't warn because the syntax of the source is entirely valid - there are cases where it falsely warns too.

    - Compiler warnings are like "Bridge Out Ahead" warnings. DON'T just ignore them.
    - A compiler error is something SO stupid that the compiler genuinely can't carry on with its job. A compiler warning is the compiler saying "Well, that's bloody stupid but if you WANT to ignore me..." and carrying on.
    - The best debugging tool in the world is a bunch of printf()'s for everything important around the bits you think might be wrong.

  5. #5
    Registered User
    Join Date
    Sep 2008
    Location
    Toronto, Canada
    Posts
    1,834
    In your case of an array of 10 rows and 2 columns, accessing beyond the 2nd column in the first row means that you'll simply access the next row's data. The array is stored contiguously in memory - so even if there were some additional bounds checking done for you, the fact that you're still within your own array of 20 values ensures you're pretty safe. You aren't yet accessing beyond that array.

    I think compilers could generate appropriate errors for your example especially since the indexes are constants and there is no need to check "runtime" variable usage. However, the C spec may say that an array such as yours is simply generating address offsets by multiplying row * 2 (number of columns), and there may in fact not be a problem on a per-row basis. I'm saying that wrap-around is perhaps a desirable feature in some circumstances.

  6. #6
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Quote Originally Posted by limp View Post
    Hi all,

    When I accidentaly tried to reference outside the bounds of an array in C, I surprisingly discovered that not only the compiler (GCC) didn't generate an error, but the reference indeed seemed valid as I got the assigned value with printf.
    Congratulations... you've just realized that you are working with a language that has *exactly zero* runtime error checking.

    It is incumbent upon you to write code that doesn't do stuff like that.

    Lesson #1 in C programming ... "Compiles" does not mean "Works".

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Having trouble with the bounds of an array.
    By inversedarkfox in forum C++ Programming
    Replies: 0
    Last Post: 10-07-2011, 02:01 PM
  2. Array bounds checking
    By rohan_ak1 in forum C Programming
    Replies: 2
    Last Post: 08-26-2008, 10:16 PM
  3. Symbol Referencing Error
    By Delpheno in forum C++ Programming
    Replies: 3
    Last Post: 01-31-2008, 09:03 PM
  4. Array bounds overflow
    By athos in forum C++ Programming
    Replies: 3
    Last Post: 08-10-2004, 12:05 PM