Segmentation fault: Stack allocation in a C program in Ubuntu when bufffer>4M


Question: 

Here's a small program to a college's task:

#include <unistd.h>

#ifndef BUFFERSIZE
#define BUFFERSIZE 1
#endif

main()
{
    char buffer[BUFFERSIZE];
    int i;
    int j = BUFFERSIZE;

    i = read(0, buffer, BUFFERSIZE);

    while (i>0)
    {
        write(1, buffer, i);
        i = read(0, buffer, BUFFERSIZE);
    }

    return 0;
}

There is a alternative using the stdio.h fread and fwrite functions instead.

Well. I compiled this both versions of program with 25 different values of Buffer Size: 1, 2, 4, ..., 2^i with i=0..30

This is a example of how I compile it: gcc -DBUFFERSIZE=8388608 prog_sys.c -o bin/psys.8M

The question: In my machine (Ubuntu Precise 64, more details in the end) all versions of the program works fine: ./psys.1M < data

(data is a small file with 3 line ascii text.)

The problem is: When the buffer size is 8MB or greater. Both versions (using system call or clib functions) crashes with these buffer sizes (Segmentation Fault).

I tested many things. The first version of the code was like this: (...) main() { char buffer[BUFFERSIZE]; int i;

    i = read(0, buffer, BUFFERSIZE);
(...)

This crashs when I call the read function. But with these versions:

main()
{
    char buffer[BUFFERSIZE]; // SEGMENTATION FAULT HERE
    int i;
    int j = BUFFERSIZE;

    i = read(0, buffer, BUFFERSIZE);


main()
{
    int j = BUFFERSIZE; // SEGMENTATION FAULT HERE
    char buffer[BUFFERSIZE];
    int i;

    i = read(0, buffer, BUFFERSIZE);

Both them crashs (SEGFAULT) in the first line of main. However, if I move the buffer out of main to the global scope (thus, allocation in the heap instead the stack), this works fine:

char buffer[BUFFERSIZE]; //NOW GLOBAL AND WORKING FINE
main()
{
    int j = BUFFERSIZE;
    int i;

    i = read(0, buffer, BUFFERSIZE);

I use a Ubuntu Precise 12.04 64bits and Intel i5 M 480 1st generation.

#uname -a
Linux hostname 3.2.0-34-generic #53-Ubuntu SMP Thu Nov 15 10:48:16 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux

I don't know the OS limitations about the stack. Is there some way to allocate big data in stack, even if this is not a good pratice?




2 Answers: 

The stack size is quite often limited in Linux. The command ulimit -s will give the current value, in Kbytes. You can change the default in (usually) the file /etc/security/limits.conf. You can also, depending on privileges, change it on a per-process basis via the code:

#include <sys/resource.h>
// ...
struct rlimit x;
if (getrlimit(RLIMIT_STACK, &x) < 0)
    perror("getrlimit");
x.rlim_cur = RLIM_INFINITY;
if (setrlimit(RLIMIT_STACK, &x) < 0)
    perror("setrlimit");
 

I think it is pretty simple: if you try to make the buffer too big, it overflows the stack.

If you use malloc() to allocate the buffer, I bet you will have no problem.

Note that there is a function called alloca() that explicitly allocates stack storage. Using alloca() is pretty much the same thing as declaring a stack variable, except that it happens while your program is running. Reading the man page for alloca() or discussions of it may help you to understand what is going wrong with your program. Here's a good discussion:

Why is the use of alloca() not considered good practice?

EDIT: In a comment, @jim mcnamara told us about ulimit, a command-line tool that can check on user limits. On this computer (running Linux Mint 14, so it should be the same limits as Ubuntu 12.10) the ulimit -s command shows a stack size limit of: 8192 K-bytes, which tracks nicely with the problem as you describe it.

EDIT: In case it wasn't completely clear, I recommend that you solve the problem by calling malloc(). Another acceptable solution would be to statically allocate the memory, which will work fine as long as your code is single-threaded.

You should only use stack allocation for small buffers, precisely because you don't want to blow up your stack. If your buffers are big, or your code will recursively call a function many times such that the little buffers will be allocated many many times, you will clobber your stack and your code will crash. The worst part is that you won't get any warning: it will either be fine, or your program already crashed.

The only disadvantage of malloc() is that it is relatively slow, so you don't want to call malloc() inside time-critical code. But it's fine for initial setup; once the malloc is done, the address of your allocated buffer is just an address in memory like any other memory address within your program's address space.

I specifically recommend against editing the system defaults to make the stack size bigger, because that makes your program much less portable. If you call standard C library functions like malloc() you could port your code to Windows, Mac, Android, etc. with little trouble; if you start calling system functions to change the default stack size, you would have much more problems porting. (And you may have no plans to port this now, but plans change!)

 

More Articles


c - Whats the difference between the two command lines? (SegFault)

I have written a code that maps to a shared memory location,so that the first program opens a shared memory block and stores some data in it.And the second program reads the shared data.Whats the difference between the two command lines:1. if(argc<2) { printf("USAGE:%s text-to-share\n",argv[0

shell - monitor for file then copy to another directory

I'm relatively new to unix scripting, so apologies for the newbie question.I need to create a script which will permanently run in the background, and monitor for a file to arrive in an FTP landing directory, then copy it to a different directory, and lastly remove the file from the original directo

Why does the following code raise a SegFault. c(Linux)

This a code that would reverse the data of a document and save it in the same document itself.However I am getting a Segmentation Fault.Please Help,I don't know why it gives a SegFault.#include <stdio.h>#include <stdlib.h>#include <termios.h>#include <fcntl.h>#include <str


mysql - Apache2 / phpmyadmin - PHP isn't working

I was working on a project of mine . then i had to restart the computer.Once I did suddenly PHP stopped working on Apache. then i starting looking into the configuration files and error logs and fixed a spelling error in the config file, but STILL the problem persisted, then i decided to re-install

Shell script - convert Excel (xlsx) to CSV - remove blank space / tab space

I receive excel file (xslx) with multiple sheets for my project. The number of records on these sheets ranges from 15k to 70k per sheet. I need to perform following tasks on this data and then convert it to CSV. Or covert to CSV and then process the data either way its fine.Input Example:call_no un

php - Having trouble with Ubuntu LAMP stack

I have installed Ubuntu 16.04 LTS, Apache2, Mysql 14, Php7. I have installed Drupal with a few difficulties. Specifically, I had to install php extensions and tweak the configs to enable those extensions, and finally the installation was successful. However, whenever I try to click on any link, the


Segmentation Fault Core dump with C on ubuntu

I have a problem with some line of codes I've written in plain C.It worked fine on windows, but on ubuntu there's an error saying "Segmentation Fault (core dumped)". I've searched for answers but there's too many problem that can caused that error.char line[80];char sett[50][80];int index=0;static c

linux - Docker run command error

I have just installed docker and pulled their official ubuntu image following their documentation installation tutorial.However, when I get to the point of executing a command in a specific container, I end up with the following error:Error: Cannot start container f6e1084236794548bbd5cd059f46f916367

c - Encountering segment fault when printing out directories in Ubuntu

I've been working on this code for a while and I can not figure out the problem. The idea is to print out all directories and sub directories from the given directory (hard coded for testing purposes). However, I keep getting a segmentation fault.#include <stdio.h>#include <dirent.h>#in

bash - attempting to recreate supervisor tutorial in docker, running into error (permissioning?)

I'm attempting to recreate the steps in this tutorial in a docker context, ubuntu image installed under coreos running in virtualbox on OS X.I've set up a Dockerfile that has the following steps:# Install docker basicsRUN echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/ap