Activity log for bug #1779583

Date Who What changed Old value New value Message
2018-07-01 22:03:23 Alexis Wilke bug added bug
2018-07-01 22:03:23 Alexis Wilke attachment added Fix to second fork() in child_process() https://bugs.launchpad.net/bugs/1779583/+attachment/5158449/+files/do_command.patch
2018-07-01 23:03:47 Alexis Wilke description The do_command.c file calls fork() twice. For the first for(), the possibility for an error is checked properly and an error emitted (see https://bugs.launchpad.net/ubuntu/+source/cron/+bug/1702785 for an example when that happens: message is "can't fork".) This first fork() makes use of a switch() statement as expected. The second fork(), however, is used inside an if() statement like this: if (*input_data && fork() == 0) { ... } Here we can see a couple of problems. After the if block, we have this statement: children++; which means that we will have to wait on TWO children. However, (1) the *input_data could return false and thus the second child may not be created at all. (2) the fork() could return -1 meaning that no other child is created. I suppose that the child_process() probably always or nearly always has some input_data. Otherwise it would block waiting for a child that was never started. And of course, it is relatively rare that fork() fails, unless you are running our of RAM (heap or stack can't be allocated) or process space (too many processes running concurrently.) I have a proposed patch to fix the problem. It uses a switch() which emits an error in case the fork() fails, but let the program go on as before (instead of an immediate exit as in the first fork()). The children variable gets incremented only when the fork() happens and succeeds (default: block in the new switch().) The do_command.c file did not change between 16.04 (trusty) and 18.04 (bionic beaver), so the patch will work for either version. The do_command.c file calls fork() twice. For the first fork(), the possibility for an error is checked properly and an error emitted (see https://bugs.launchpad.net/ubuntu/+source/cron/+bug/1702785 for an example when that happens: message is "can't fork".) This first fork() makes use of a switch() statement as expected. The second fork(), however, is used inside an if() statement like this: if (*input_data && fork() == 0) { ... } Here we can see a couple of problems. After the if block, we have this statement: children++; which means that we will have to wait on TWO children. However, (1) the *input_data could return false and thus the second child may not be created at all. (2) the fork() could return -1 meaning that no other child is created. I suppose that the child_process() probably always or nearly always has some input_data. Otherwise it would block waiting for a child that was never started. And of course, it is relatively rare that fork() fails, unless you are running our of RAM (heap or stack can't be allocated) or process space (too many processes running concurrently.) I have a proposed patch to fix the problem. It uses a switch() which emits an error in case the fork() fails, but let the program go on as before (instead of an immediate exit as in the first fork()). The children variable gets incremented only when the fork() happens and succeeds (default: block in the new switch().) The do_command.c file did not change between 16.04 (trusty) and 18.04 (bionic beaver), so the patch will work for either version.
2018-07-01 23:23:01 Alexis Wilke attachment added Compiling fix to second fork() in child_process() https://bugs.launchpad.net/ubuntu/+source/cron/+bug/1779583/+attachment/5158458/+files/do_command-2.patch
2018-07-02 00:21:12 Ubuntu Foundations Team Bug Bot bug added subscriber Ubuntu Review Team
2018-07-02 16:21:50 Brian Murray tags bionic patch trusty bionic cosmic patch trusty
2018-07-02 21:52:58 Alexis Wilke tags bionic cosmic patch trusty bionic cosmic patch xenial
2018-07-02 21:53:22 Alexis Wilke description The do_command.c file calls fork() twice. For the first fork(), the possibility for an error is checked properly and an error emitted (see https://bugs.launchpad.net/ubuntu/+source/cron/+bug/1702785 for an example when that happens: message is "can't fork".) This first fork() makes use of a switch() statement as expected. The second fork(), however, is used inside an if() statement like this: if (*input_data && fork() == 0) { ... } Here we can see a couple of problems. After the if block, we have this statement: children++; which means that we will have to wait on TWO children. However, (1) the *input_data could return false and thus the second child may not be created at all. (2) the fork() could return -1 meaning that no other child is created. I suppose that the child_process() probably always or nearly always has some input_data. Otherwise it would block waiting for a child that was never started. And of course, it is relatively rare that fork() fails, unless you are running our of RAM (heap or stack can't be allocated) or process space (too many processes running concurrently.) I have a proposed patch to fix the problem. It uses a switch() which emits an error in case the fork() fails, but let the program go on as before (instead of an immediate exit as in the first fork()). The children variable gets incremented only when the fork() happens and succeeds (default: block in the new switch().) The do_command.c file did not change between 16.04 (trusty) and 18.04 (bionic beaver), so the patch will work for either version. The do_command.c file calls fork() twice. For the first fork(), the possibility for an error is checked properly and an error emitted (see https://bugs.launchpad.net/ubuntu/+source/cron/+bug/1702785 for an example when that happens: message is "can't fork".) This first fork() makes use of a switch() statement as expected. The second fork(), however, is used inside an if() statement like this: if (*input_data && fork() == 0) { ... } Here we can see a couple of problems. After the if block, we have this statement: children++; which means that we will have to wait on TWO children. However, (1) the *input_data could return false and thus the second child may not be created at all. (2) the fork() could return -1 meaning that no other child is created. I suppose that the child_process() probably always or nearly always has some input_data. Otherwise it would block waiting for a child that was never started. And of course, it is relatively rare that fork() fails, unless you are running our of RAM (heap or stack can't be allocated) or process space (too many processes running concurrently.) I have a proposed patch to fix the problem. It uses a switch() which emits an error in case the fork() fails, but let the program go on as before (instead of an immediate exit as in the first fork()). The children variable gets incremented only when the fork() happens and succeeds (default: block in the new switch().) The do_command.c file did not change between 16.04 (xenial) and 18.04 (bionic beaver), so the patch will work for either version.
2018-08-29 02:09:44 Launchpad Janitor cron (Ubuntu): status New Confirmed