[systemd-devel] [PATCH 4/4] coredump: collect all /proc data useful for bug reporting

Jakub Filak jfilak at redhat.com
Mon Nov 24 02:01:43 PST 2014


On Fri, 2014-11-21 at 21:14 +0100, Lennart Poettering wrote:
> On Wed, 19.11.14 11:01, Jakub Filak (jfilak at redhat.com) wrote:
> 
> > +/* Joins /proc/[pid]/fd/ and /proc/[pid]/fdinfo/ into the following lines:
> > + *
> > + * 0:/dev/pts/23
> > + * pos:    0
> > + * flags:  0100002
> > + * 1:/dev/pts/23
> > + * pos:    0
> > + * flags:  0100002
> > + * 2:/dev/pts/23
> 
> Hmm, I'd prefer a format here that is more easily reversible. For
> example, adding an extra newline between the fdinfo items would be a
> good start.
> 

I took this format from ABRT. I will add the extra blank line.

> > + *
> > + */
> > +static int compose_open_fds(pid_t pid, char **open_fds) {
> > +        const char *fd_name = NULL, *fdinfo_name = NULL;
> 
> const? why?

Not sure, typo? Lack of caffeine?

> 
> > +        char *outcome = NULL;
> > +        size_t len = 0, allocated = 0;
> > +        char line[LINE_MAX];
> > +        unsigned fd = 0;
> > +        int r = 0;
> > +
> > +        assert(pid >= 0);
> > +
> > +        fd_name = alloca(strlen("/proc//fd/") + DECIMAL_STR_MAX(pid_t) + DECIMAL_STR_MAX(unsigned) + 1);
>                                                                                             ^^^
>                                                                                             unsigned? an fd is an int!  

Thanks, I overlooked it.

> > +        fdinfo_name = alloca(strlen("/proc//fdinfo/") + DECIMAL_STR_MAX(pid_t) + DECIMAL_STR_MAX(unsigned) + 1);
> 
> same here.
> 
> The sizes you allocate here are fixed. I'd really prefer if you'd
> allocate these as normal arrays instead of alloca(). alloca() is a
> useful tool, but we should use it only when normal arrays aren't good
> denough, but not otherwise.
> 
> Also note that alloca() cannot be mixed with function calls in the
> same line. strlen() is a function call (though one that today's gcc
> actually is smart enough to optimize away at compile time if you
> invoke it on a literal string). 
> 
> Hence, please use this instead:
> 
> char fd_name[sizeof("/proc/")-1 + DECIMAL_STR_MAX(pid_t) + sizeof("/fd/")-1 + DECIMAL_STR_MAX(int) + 1];


OK, I thought systemd prefers alloca(). I was inspired by
procfs_file_alloca().

> > +
> > +        while (fd <= 99999) {
> 
> Oh no, this is not OK!
> 
> We shouldn't iterate though all thinkable fds, that's bad code. Please
> iterate through /proc/$PID/fd/ and just operate on fds that are
> actually there.
> 

OK.
Just a note, it iterates until it finds the first non-existing fd.

> > +                _cleanup_free_ char *name = NULL;
> > +                _cleanup_fclose_ FILE *fdinfo = NULL;
> > +
> > +                sprintf((char *)fd_name, "/proc/"PID_FMT"/fd/%u", pid, fd);
> 
> Hmm, first you declare the string as "const", then you cast this away?
> This is usually a good indication that something is really wrong...

Very bad! I hate code where people cast from const to non-const. What I
was thinking about while writing this patch?

> 
> > +                r = readlink_malloc(fd_name, &name);
> > +                if (r < 0) {
> > +                        if (r == -ENOENT) {
> > +                            *open_fds = outcome;
> > +                            r = 0;
> > +                        }
> > +                        else
> > +                            free(outcome);
> > +
> > +                        break;
> > +                }
> > +
> > +                if (!GREEDY_REALLOC(outcome, allocated, len + strlen(name) + DECIMAL_STR_MAX(unsigned) + 3))
> > +                        return -ENOMEM;
> > +
> > +                len += sprintf(outcome + len, "%u:%s\n", fd, name);
> > +                ++fd;
> > +
> > +                sprintf((char *)fdinfo_name, "/proc/"PID_FMT"/fdinfo/%u", pid, fd);
> > +                fdinfo = fopen(fdinfo_name, "r");
> > +                if (fdinfo == NULL)
> > +                        continue;
> > +
> > +                while(fgets(line, sizeof(line), fdinfo) != NULL) {
> > +                        if (!GREEDY_REALLOC(outcome, allocated, len + strlen(line) + 2))
> > +                                return -ENOMEM;
> > +
> > +                        len += sprintf(outcome + len, "%s", line);
> > +                        if (strchr(line, '\n') == NULL) {
> > +                                outcome[len++] = '\n';
> > +                                outcome[len] = '\0';
> > +                        }
> 
> > +                }
> 
> I think using libc's open_memstream() and then simply writing to it
> would be a *ton* prettier than this.
> 

Fabulous! I think so too. I wasn't allowed to use such a construction in
other projects.



Jakub




More information about the systemd-devel mailing list