0

First an abstraction of my program:

int main ()
{
    My_Struct1 ms1; // sizeof (My_Struct1) is 88712 B  -- L1
    My_Struct2 ms2; // sizeof (My_Struct2) is 13208 B  -- L2

    // 1. Invoke parser to fill in the two struct instances.  -- L3

    printf ("%ul, %ul\n", &ms1, &ms2) // -- **L3b** doesn't produce seg. fault.

    my_fun (&ms1, &ms2); //  -- L4, does produce seg. fault.

    return 0;
}

If I run my program using makefile, then a segmentation fault occurs at L4 (always).

If I execute my program directly from shell (./executable), then the segmentation does occur sometimes but not always.

The error is: Segmentation fault: Cannot access memory at address at L4 for &ms1 and &ms2 both. The type and location of the error is what was pointed out by gdb.

My guess is that the error is because of the size of the structures. Please explain in detail what is going.

The error behivour is same even after reducing the size of My_Struct1 to 8112 B and My_Struct2 to 1208 B.

I am working on:

  • Ubuntu 14.04
  • Intel® Core™ i5-4200M CPU @ 2.50GHz × 4
  • 3.8 GiB memory
  • gcc - 4.8.4
Kulwant Singh
  • 121
  • 2
  • 12
  • 2
    "even after reducing the size of My_Struct1 to 8112 B". Do you mean "KB"? 8112KB is about 8MB, which is a common value for the stack size limit in Linux. So unless you have increased the stack size limit, that will likely overflow the stack. – kaylum Mar 18 '16 at 04:36
  • Your guess is a reasonable one, but without seeing the definition of `My_Struct1`, `My_Struct2`, and `my_fun` (in particular, what locals it declares; if it's a stack size issue, those may play a role), we couldn't say for sure. – Ray Mar 18 '16 at 04:51
  • 1
    Hold on while I get my crystal ball – M.M Mar 18 '16 at 07:42
  • It is 8112 B only, not KB as it is the value returned by the `sizeof ()` . `My_Struct1` is a struct containing an array (of #defined size) of basic blocks and `My_Struct2` is a Symbol Table. They are probably too big to post in a question, I will if you still suggest. But **the major point** is that the statement _L3b_ (newly added) **doesn't produce a segmentation fault** but statement _L4_ does; as pointed out by **gdb**. – Kulwant Singh Mar 18 '16 at 07:49
  • 1
    You should probably create a minimal, complete, verifiable example (http://stackoverflow.com/help/mcve). We can't see the definition of your structs or what `my_fun` is. A minor point is that you should not pass pointers to `printf` if the formatting is `%ul` (`printf` will expect `unsigned long`s and nothing else). For printing pointers you should use `%p` instead. – skyking Mar 18 '16 at 08:08

1 Answers1

5

First, compile with all warnings & debug info. Probably with CFLAGS= -g -Wall -Wextra in your Makefile. Perhaps you might sometimes add some sanitize instrumentation options such as -fsanitize=address or -fsanitize=undefined (then it could be worthwhile to upgrade your GCC compiler to GCC 5 in march 2016).You might also want -Wstack-usage=1000 warning & -fstack-usage developer option.

Be very afraid of undefined behavior.

Then, enable core(5) dumps. Probably some ulimit -c 100000 (or whatever number is realistic) in your ~/.bashrc then start a new terminal; check with cat /proc/self/limits (a Linux specific command, related to proc(5)) that the limits are well set. See setrlimit(2).

Run your faulty test, e.g. with make test. You'll get a core dump. Check with ls -l core and file core.

At last, do a post mortem debugging session. If your binary is someprog, run gdb someprog core. Probably the first gdb command you'll type would be bt

Indeed, you are probably wrong in declaring quite large struct as local variables in main. The rule of thumb is to restrict your call frame to a few kilobytes at most (hence, never have a local variable of more than a kilobyte in the call stack). So I would recommend putting your large struct in the heap (so use malloc and free appropriately, read about C dynamic memory allocation). But a typical call stack on Linux can grow to several megabytes.

Also, run your program with valgrind

BTW, the correct format for (void*) pointers in %p so your added printf should be

printf("ms1@%p, ms2@%p\n", (void*)&ms1, (void*)&ms2);
Community
  • 1
  • 1
Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547