Runaway program

Questions about applications and software
Forum rules
Before you post please read how to get help
User avatar
cpergiel
Level 2
Level 2
Posts: 86
Joined: Mon Feb 16, 2015 9:03 pm
Location: Silicon Forest
Contact:

Runaway program

Postby cpergiel » Sun Nov 19, 2017 1:44 pm

I am playing with a program to see how much memory I can access. The program is written in C, I compile it and run it in a Terminal window. It allocates the biggest chunk of memory that it can, which is something like 10GB, and then proceeds to fill that memory with integers. It runs fine for a few seconds, posting intermittent results to the screen, and then it goes off in the weeds. The disk is getting hammered and the screen is locked up. Control-C has no effect. Pressing and holding the power button to turn it off is the only way to stop it.

I am thinking there must be some kind of OS call I can make so that the program will get notified if Control-C is pressed.

My computer has about 4GB of RAM, so I imagine that most of the 10GB is virtual, which kind of explains why the disk is getting hammered, but not really, since I am simply writing the index into each location.

rene
Level 6
Level 6
Posts: 1366
Joined: Sun Mar 27, 2016 6:58 pm

Re: Runaway program

Postby rene » Sun Nov 19, 2017 3:46 pm

cpergiel wrote:I am thinking there must be some kind of OS call I can make so that the program will get notified if Control-C is pressed.

That already happens by default; specifically, Ctrl-C sends a SIGINT signal to the current foreground process, which if not explicitly handled terminates it. It's just that Linux is notoriously lousy at actually getting signals delivered to processes during I/O storms, such as when swapping. SIGSTOP (Ctrl-Z) followed by a kill %1 usually works slightly better. Yes, certainly the hammering is your swap space being put to use; note that swap granularity is 4K on x86 (a page); that is, not sure what you mean by "the index", but even a single byte written causes an entire 4096-byte page to be dirtied...

The below example explicitly handles SIGINT so as to show what's happening. I am usually able to get the Ctrl-C delivered, i.e. the program to exit gracefully, before the OOM-killer steps in to shoot the thing (which is what happened if you see "Killed" instead of the program's own message) but not always; certainly it always takes a huge amount of time for the SIGINT to register once the machine starts swapping even though it is near-immediate if you hit Ctrl-C before it does. Mileage will vary according to amount of configured swap and it being on HDD or SSD. There's also some interplay with configurable settings such as /proc/sys/vm/overcommit_memory here but assuming you haven't done strange things it should never be necessary to hard-reset the machine: the program will be killed eventually, and the machine will recover, the latter fastest by doing a sudo swapoff -a, sudo swapon -a cycle.

But take care to not have anything essential and unsaved open when you run this regardless...

Code: Select all

#include <stdlib.h>
#include <stdio.h>
#include <signal.h>

volatile int interrupted;

void sigint(int signum __attribute__((unused)))
{
    interrupted = 1;
}

int main(void)
{
    unsigned char *p;

    if (signal(SIGINT, sigint) == SIG_ERR) {
        perror("signal");
        return EXIT_FAILURE;
    }

    while ((p = malloc(4096)) && !interrupted)
       *p = 0;

    if (interrupted)
        printf("Got SIGINT; exiting gracefully.");

    return EXIT_SUCCESS;
}

User avatar
cpergiel
Level 2
Level 2
Posts: 86
Joined: Mon Feb 16, 2015 9:03 pm
Location: Silicon Forest
Contact:

Re: Runaway program

Postby cpergiel » Sun Nov 19, 2017 5:57 pm

Who hoo! An answer! It will probably take me a couple of days to digest. Thank you.

rene
Level 6
Level 6
Posts: 1366
Joined: Sun Mar 27, 2016 6:58 pm

Re: Runaway program

Postby rene » Sun Nov 19, 2017 6:17 pm

Then allow me to add that "some interplay" is a bit understated. Enabling memory overcommit (the default) means that basically the while loop never ends without the program being interrupted by a signal (manually as in this case, or through any unhandled signal the default action of which is to terminate the process such as unhandled SIGINT) or by the system terminating the program as a memory hog ("the OOM-killer stepping in"); that malloc() will "never" fail. As implicitly the program assumes but it would've been a better example if it have had

Code: Select all

else
    printf("Allocation failure; exiting gracefully.");

after the if branch, even if then only in the sense of showing that unless you disable overcommit, you never see the else branch execute. Sort of besides the point (of showing Linux signal delivery to be tardy) but, anyways, still better.

Also, that signal() is a basically obsolete interface; use sigaction() for serious code.


Return to “Software & Applications”