Subject: | invalid cmdline field returned under Linux when command lines are 20, 40, ... character long |
Date: | Thu, 12 Nov 2009 14:24:05 +0100 |
To: | bug-Proc-ProcessTable [...] rt.cpan.org |
From: | Christian BOITEL <christian.boitel [...] gmail.com> |
On one terminal, run a program that: prints its pid, defines its command
line as a string of length being a modulo of 20 and waits a bit so you have
time to run second program
=> Example: perl -e 'print "mypid=$$\n"; while (<>) { chomp(); $0 = $_; }'
While the first program is working, do the following:
1/ display cmndline value of the test program using cat
/proc/<mypid>/cmndline
=> this is to confirm it shows up with no garbagge at the end
2/ use a sample perl program using Proc::ProcessTable to display processes
pid and cmndline attributes and grep the output to locate process created on
first terminal
=>
perl -e 'use Proc::ProcessTable; $t = new Proc::ProcessTable; foreach $p
(@{$t->table}) {print "pid=".$p->{"pid"}.",cmdline=".$p->{"cmndline"}."\n";
}' | fgrep <mypid>
=> you should see additional characters at the end
Example:
Show quoted text
root> perl -e 'print "mypid=$$\n"; while (<>) { chomp(); $0 = $_; }'
mypid=2110
01234567890123456789
root.hpbl20050> {print "pid=".$p->{"pid"}.",cmdline=".$p->{"cmndline"}."\n";
}' | fgrep pid=2110 <
pid=2110,cmdline=012345678901234567892110 28928 34820 211
(/proc)
root.hpbl20050> cat /proc/2110/cmdline
01234567890123456789
Pb has been located in read_file function within os/Linux.c
=> bug therefore applies to all /proc/xxx/yyy files being read if it is a
multiple of 20 in size
=> bug is just after the for loop that reads the file content into the
obstack:
from my understanding, it is useless to test after if len
of data being read is a multiple of 20
the for loop will be executed at least once more than
needed for loop exits if result is 0 (when eof is reached)
(result must be 0 to exit) and therefore obstack is always 20 characters
more long than needed
--- Linux.c 2009-11-12 14:13:07.000000000 +0100
+++ Linux.c.original 2008-09-08 17:10:41.000000000 +0200
@@ -235,22 +235,26 @@
for (*len = 0; result; *len += result) {
obstack_blank(mem_pool, 20);
start = obstack_base(mem_pool) + *len;
if ((result = read(fd, start, 20)) == -1) {
obstack_free(mem_pool, obstack_finish(mem_pool));
return NULL;
}
}
- start = obstack_base(mem_pool) + *len;
- *start = '\0';
+ /* null terminate */
+ if (*len % 20) {
+ start = obstack_base(mem_pool) + *len;
+ *start = '\0';
+ } else
+ obstack_1grow(mem_pool, '\0');
/* finalize our text buffer */
text = obstack_finish(mem_pool);
/* not bothering checking return value, because it's possible that the
* process went away */
close(fd);
return text;
}