9

Consider this program:

int w(int x, int y){
    if(x != y) {
        w(x, y);
    }else return x+y;
}

Call it this way:

w(0, 5);

For distinct values (like above), it generates an infinite recursion. The problem is, once the program started this way, the specific process turns into a D mode (waiting for an internal I/O, therefore untouchable).

top see untitled1

Take a normal loop

while(1){
    if(0 != 5){
        //foo
    }else{
        //bar
    }
}

Generates R state mode - perfectly capable of getting SIGKILL.

enter image description here

Although normal loops beat recursions performance-wise; the system should still be capable of killing the process.

Why is this happening? And how to prevent it remotely?

The code will be compiled an executed by a program that returns its output to the webclient via sockets. So there is no control over what the user attempts to compile.

Edit:

Ubiquitous process of compiling and running the code:

$ g++ main.cpp -o m
$ ./m

Edit2:

$ g++ --version
g++ (GCC) 4.9.2 20150204 (prerelease)
Copyright (C) 2014 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ df --print-type
Filesystem     Type     1K-blocks      Used Available Use% Mounted on
/dev/sda2      ext4     957174124 168965980 739563400  19% /
dev            devtmpfs   4087124         0   4087124   0% /dev
run            tmpfs      4089872       528   4089344   1% /run
tmpfs          tmpfs      4089872        76   4089796   1% /dev/shm
tmpfs          tmpfs      4089872         0   4089872   0% /sys/fs/cgroup
tmpfs          tmpfs      4089872      1052   4088820   1% /tmp
tmpfs          tmpfs       817976        12    817964   1% /run/user/1000

The tests were done on Arch Linux x64 (with latest gcc).

Edit3:

The same problem occurs even after reinstalling the OS. The image has been used on another pc as well, where this problem does not occur.

Gabe
  • 961
  • 1
  • 10
  • 23
  • 3
    Did you leave out some details on how you're building this? When I run your program, I just get a segfault ... how are you compiling your code to either force it to try to do tail recursion or otherwise avoid just getting a stack overflow error? – Foon Feb 26 '15 at 13:24
  • g++ and directly running it or through an IDE (usually wraps up g++) still phenomenon happens – Gabe Feb 26 '15 at 13:26
  • Weird... just for grins, what g++ are you using? Using g++ 4.8.2 (RHEL -16) on CentOS 7.0 for when I run your sample program (that segfaults for me which makes sense) using int main(int argc, char *argv[]) { w(0,5);} – Foon Feb 26 '15 at 13:29
  • I´m running Ununtu 14.04 and I get `Semgentation fault` error when try to run such function. – Raydel Miranda Feb 26 '15 at 13:29
  • One last other random thought... I can remember getting extremely upset that SGI (and Linux) both do weird things over NFS. In a probably horribly inaccurate summary, various read operations assume that read will not take a long time and so they ignore signals, which is problematic for NFS. Are you using any exotic file systems? – Foon Feb 26 '15 at 13:32
  • @Foon No, check edit – Gabe Feb 26 '15 at 13:38
  • I'm using gcc 4.8.1 and the code compiles, but program crashes when I run it. – Arun A S Feb 26 '15 at 13:42

2 Answers2

1

I'm not sure to have undertood:

Launch your command in this way:

./m & echo $! > mpid

So to kill process:

kill $(cat mpid)
Luca Davanzo
  • 21,000
  • 15
  • 120
  • 146
  • Stagnates in T (trace mode) after exposing pid, killable with -9 but program does not truly execute (take a trivial hello world) – Gabe Feb 26 '15 at 13:49
1

I will start with a cite from this answer(zerodeux): Linux Process States.

... The D state (TASK_UNINTERRUPTIBLE) is a special sleep mode which is only triggered in a kernel space code path, when that code path can't be interrupted (because it would be to complex to program), most of the time in the hope that it would block very shortly. I believe that most "D states" are actually invisible, they are very short lived and can't be observed by sampling tools such as 'top'.

So, it's possible the kernel set the D state for a process that it's calling some function (at the exact moment the function it's being called and nothing else) becouse that involve memory work, call stack modifications, and other complex things.

Your code left almost no time between w(x, y) calls so it's possible that is causing you to see the continuous D state.

I could not reproduce your code's behaviour, but I have an experiment in mind, set a time sleep (about a second is enough) before call w(x, y), and see what happends.

On the other hand, I think the program is actualy being executed, in fact in your code you're passing x and y as values so, in every call copies will be made and that will comsume memory(the call stack also consumes memory). You can then (another experiment) check for the memory consumption, if the program is not being executed, the memory consumtpion stay the same in time.

Community
  • 1
  • 1
Raydel Miranda
  • 13,825
  • 3
  • 38
  • 60
  • Yes! Adding sleep(1) before the next call, gets the task in S mode, which is perfectly killable. However, this is not suitable for the real-world use (and breaking any conventional runtime rules: in the context given I do not have control over the code that gets into the "compilation program" ; editing it programatically isn't a viable option either) – Gabe Feb 26 '15 at 14:06
  • @Gabe Of course not. That's only for demostrate the problem. (Which seems I have nailed it ;D), If you Don't have control over the code, could you write you own version of the function? Lets say with a loop. On the other hand, it is very rare(I'm being generous here) a real-word-working function that don't performs a little more work before call itself again. – Raydel Miranda Feb 26 '15 at 14:25
  • The behaviour of the program is still abnormal, it should be automatically aborted by the system. Prioritization and abortion are low level procedures that should not imply modification of the code. Tests on other distros and versions have proved that. The S state is relatively expected - same thing would happen in a non recursive style as well. – Gabe Feb 26 '15 at 14:35
  • Again, that has to do with how the kernel (which is not the same for all distributions) handles this. For instance, in ubuntu 14.04, recently installed, I get segmentation fault, a completely diferent behaviour. – Raydel Miranda Feb 26 '15 at 14:39