From: Nick Alcock Date: Tue, 17 Sep 2019 05:57:00 +0000 (+0100) Subject: libctf: make ctf_dump not crash on OOM X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=9323dd869dfe481d46512c7f9b1a30d0b7d2d7c4;p=binutils-gdb.git libctf: make ctf_dump not crash on OOM ctf_dump calls ctf_str_append extensively but never checks to see if it returns NULL (on OOM). If it ever does, we truncate the string we are appending to and leak it! Instead, create a variant of ctf_str_append that returns the *original string* on OOM, and use it in ctf-dump. It is far better to omit a tiny piece of a dump on OOM than to omit a bigger piece, and it is also better to do this in what is after all purely debugging code than it is to uglify ctf-dump.c with huge numbers of checks for the out-of-memory case. Slightly truncated debugging output is better than no debugging output at all and an out-of-memory message. New in v4. libctf/ * ctf-impl.h (ctf_str_append_noerr): Declare. * ctf-util.c (ctf_str_append_noerr): Define in terms of ctf_str_append. * ctf-dump.c (str_append): New, call it. (ctf_dump_format_type): Use str_append, not ctf_str_append. (ctf_dump_label): Likewise. (ctf_dump_objts): Likewise. (ctf_dump_funcs): Likewise. (ctf_dump_var): Likewise. (ctf_dump_member): Likewise. (ctf_dump_type): Likewise. (ctf_dump): Likewise. --- diff --git a/libctf/ChangeLog b/libctf/ChangeLog index 85cd785de94..b7f12d8e092 100644 --- a/libctf/ChangeLog +++ b/libctf/ChangeLog @@ -1,3 +1,18 @@ +2019-09-23 Nick Alcock + + * ctf-impl.h (ctf_str_append_noerr): Declare. + * ctf-util.c (ctf_str_append_noerr): Define in terms of + ctf_str_append. + * ctf-dump.c (str_append): New, call it. + (ctf_dump_format_type): Use str_append, not ctf_str_append. + (ctf_dump_label): Likewise. + (ctf_dump_objts): Likewise. + (ctf_dump_funcs): Likewise. + (ctf_dump_var): Likewise. + (ctf_dump_member): Likewise. + (ctf_dump_type): Likewise. + (ctf_dump): Likewise. + 2019-09-23 Nick Alcock * ctf-impl.h (ctf_alloc): Remove. diff --git a/libctf/ctf-dump.c b/libctf/ctf-dump.c index c2d331be23f..88e81a574f4 100644 --- a/libctf/ctf-dump.c +++ b/libctf/ctf-dump.c @@ -20,6 +20,8 @@ #include #include +#define str_append(s, a) ctf_str_append_noerr (s, a) + /* One item to be dumped, in string form. */ typedef struct ctf_dump_item @@ -119,7 +121,7 @@ ctf_dump_format_type (ctf_file_t *fp, ctf_id_t id, int flag) { if (id == 0 || ctf_errno (fp) == ECTF_NONREPRESENTABLE) { - str = ctf_str_append (str, " (type not represented in CTF)"); + str = str_append (str, " (type not represented in CTF)"); ctf_set_errno (fp, ECTF_NOTREF); break; } @@ -147,13 +149,13 @@ ctf_dump_format_type (ctf_file_t *fp, ctf_id_t id, int flag) } free (buf); buf = NULL; - str = ctf_str_append (str, bit); + str = str_append (str, bit); free (bit); bit = NULL; new_id = ctf_type_reference (fp, id); if (new_id != CTF_ERR) - str = ctf_str_append (str, " ->"); + str = str_append (str, " ->"); } while (new_id != CTF_ERR); if (ctf_errno (fp) != ECTF_NOTREF) @@ -319,7 +321,7 @@ ctf_dump_label (const char *name, const ctf_lblinfo_t *info, return -1; /* errno is set for us. */ } - str = ctf_str_append (str, typestr); + str = str_append (str, typestr); free (typestr); ctf_dump_append (state, str); @@ -376,7 +378,7 @@ ctf_dump_objts (ctf_file_t *fp, ctf_dump_state_t *state) return -1; /* errno is set for us. */ } - str = ctf_str_append (str, typestr); + str = str_append (str, typestr); free (typestr); ctf_dump_append (state, str); @@ -426,7 +428,7 @@ ctf_dump_funcs (ctf_file_t *fp, ctf_dump_state_t *state) goto err; } - str = ctf_str_append (str, " "); + str = str_append (str, " "); /* Function name. */ @@ -441,8 +443,8 @@ ctf_dump_funcs (ctf_file_t *fp, ctf_dump_state_t *state) if (asprintf (&bit, "%s (0x%lx) ", sym_name, (unsigned long) i) < 0) goto oom; } - str = ctf_str_append (str, bit); - str = ctf_str_append (str, " ("); + str = str_append (str, bit); + str = str_append (str, " ("); free (bit); /* Function arguments. */ @@ -460,15 +462,15 @@ ctf_dump_funcs (ctf_file_t *fp, ctf_dump_state_t *state) err = "look up argument type name"; goto err; } - str = ctf_str_append (str, bit); + str = str_append (str, bit); if ((j < fi.ctc_argc - 1) || (fi.ctc_flags & CTF_FUNC_VARARG)) - str = ctf_str_append (str, ", "); + str = str_append (str, ", "); free (bit); } if (fi.ctc_flags & CTF_FUNC_VARARG) - str = ctf_str_append (str, "..."); - str = ctf_str_append (str, ")"); + str = str_append (str, "..."); + str = str_append (str, ")"); free (args); ctf_dump_append (state, str); @@ -507,7 +509,7 @@ ctf_dump_var (const char *name, ctf_id_t type, void *arg) return -1; /* errno is set for us. */ } - str = ctf_str_append (str, typestr); + str = str_append (str, typestr); free (typestr); ctf_dump_append (state, str); @@ -526,7 +528,7 @@ ctf_dump_member (const char *name, ctf_id_t id, unsigned long offset, ssize_t i; for (i = 0; i < depth; i++) - *state->cdm_str = ctf_str_append (*state->cdm_str, " "); + *state->cdm_str = str_append (*state->cdm_str, " "); if ((typestr = ctf_type_aname (state->cdm_fp, id)) == NULL) { @@ -536,7 +538,7 @@ ctf_dump_member (const char *name, ctf_id_t id, unsigned long offset, offset) < 0) goto oom; - *state->cdm_str = ctf_str_append (*state->cdm_str, bit); + *state->cdm_str = str_append (*state->cdm_str, bit); free (typestr); free (bit); return 0; @@ -549,7 +551,7 @@ ctf_dump_member (const char *name, ctf_id_t id, unsigned long offset, offset, id, ctf_type_kind (state->cdm_fp, id), typestr, name, (unsigned long) ctf_type_align (state->cdm_fp, id)) < 0) goto oom; - *state->cdm_str = ctf_str_append (*state->cdm_str, bit); + *state->cdm_str = str_append (*state->cdm_str, bit); free (typestr); free (bit); typestr = NULL; @@ -563,12 +565,12 @@ ctf_dump_member (const char *name, ctf_id_t id, unsigned long offset, if (asprintf (&bit, ", format 0x%x, offset:bits 0x%x:0x%x", ep.cte_format, ep.cte_offset, ep.cte_bits) < 0) goto oom; - *state->cdm_str = ctf_str_append (*state->cdm_str, bit); + *state->cdm_str = str_append (*state->cdm_str, bit); free (bit); bit = NULL; } - *state->cdm_str = ctf_str_append (*state->cdm_str, ")\n"); + *state->cdm_str = str_append (*state->cdm_str, ")\n"); return 0; oom: @@ -593,7 +595,7 @@ ctf_dump_type (ctf_id_t id, int flag, void *arg) goto err; } - str = ctf_str_append (str, "\n"); + str = str_append (str, "\n"); if ((ctf_type_visit (state->cds_fp, id, ctf_dump_member, &membstate)) < 0) { if (id == 0 || ctf_errno (state->cds_fp) == ECTF_NONREPRESENTABLE) @@ -752,8 +754,8 @@ ctf_dump (ctf_file_t *fp, ctf_dump_state_t **statep, ctf_sect_names_t sect, nline[0] = '\0'; ret = func (sect, line, arg); - str = ctf_str_append (str, ret); - str = ctf_str_append (str, "\n"); + str = str_append (str, ret); + str = str_append (str, "\n"); if (ret != line) free (ret); @@ -772,7 +774,14 @@ ctf_dump (ctf_file_t *fp, ctf_dump_state_t **statep, ctf_sect_names_t sect, str[len-1] = '\0'; } else - str = strdup (state->cds_current->cdi_item); + { + str = strdup (state->cds_current->cdi_item); + if (!str) + { + ctf_set_errno (fp, ENOMEM); + return str; + } + } ctf_set_errno (fp, 0); return str; diff --git a/libctf/ctf-impl.h b/libctf/ctf-impl.h index bed3487608f..6040457e36e 100644 --- a/libctf/ctf-impl.h +++ b/libctf/ctf-impl.h @@ -457,6 +457,7 @@ extern ssize_t ctf_pread (int fd, void *buf, ssize_t count, off_t offset); extern void *ctf_realloc (ctf_file_t *, void *, size_t); extern char *ctf_str_append (char *, const char *); +extern char *ctf_str_append_noerr (char *, const char *); extern const char *ctf_strerror (int); extern ctf_id_t ctf_type_resolve_unsliced (ctf_file_t *, ctf_id_t); diff --git a/libctf/ctf-util.c b/libctf/ctf-util.c index d10b2b53a9c..d4a1c5aaeac 100644 --- a/libctf/ctf-util.c +++ b/libctf/ctf-util.c @@ -103,7 +103,7 @@ ctf_sym_to_elf64 (const Elf32_Sym *src, Elf64_Sym *dst) return dst; } -/* A string appender working on dynamic strings. */ +/* A string appender working on dynamic strings. Returns NULL on OOM. */ char * ctf_str_append (char *s, const char *append) @@ -127,6 +127,19 @@ ctf_str_append (char *s, const char *append) return s; } +/* A version of ctf_str_append that returns the old string on OOM. */ + +char * +ctf_str_append_noerr (char *s, const char *append) +{ + char *new_s; + + new_s = ctf_str_append (s, append); + if (!new_s) + return s; + return new_s; +} + /* A realloc() that fails noisily if called with any ctf_str_num_users. */ void * ctf_realloc (ctf_file_t *fp, void *ptr, size_t size)