Skip to content

Commit

Permalink
Kill bogus TYPE_BLOB marker type
Browse files Browse the repository at this point in the history
Since commit 32b9c61 "Preserve datatype markers when emitting dts
format", we no longer try to guess the value type. Instead, we reuse
the type of the datatype markers when they are present, if the type
is either TYPE_UINT* or TYPE_STRING.

This causes 'dtc -I fs' to crash:

Starting program: /root/dtc -q -f -O dts -I fs /proc/device-tree
/dts-v1/;

/ {

Program received signal SIGSEGV, Segmentation fault.
__strlen_power8 () at ../sysdeps/powerpc/powerpc64/power8/strlen.S:47
47              ld      r12,0(r4)     /* Load doubleword from memory.  */
(gdb) bt
#0  __strlen_power8 () at ../sysdeps/powerpc/powerpc64/power8/strlen.S:47
#1  0x00007ffff7de3d10 in __GI__IO_fputs (str=<optimized out>,
    fp=<optimized out>) at iofputs.c:33
#2  0x000000001000c7a0 in write_propval (prop=0x100525e0,
    f=0x7ffff7f718a0 <_IO_2_1_stdout_>) at treesource.c:245

The offending line is:

                fprintf(f, "%s", delim_start[emit_type]);

where emit_type is TYPE_BLOB and:

static const char *delim_start[] = {
        [TYPE_UINT8] = "[",
        [TYPE_UINT16] = "/bits/ 16 <",
        [TYPE_UINT32] = "<",
        [TYPE_UINT64] = "/bits/ 64 <",
        [TYPE_STRING] = "",
};

/* Data blobs */
enum markertype {
        TYPE_NONE,
        REF_PHANDLE,
        REF_PATH,
        LABEL,
        TYPE_UINT8,
        TYPE_UINT16,
        TYPE_UINT32,
        TYPE_UINT64,
        TYPE_BLOB,
        TYPE_STRING,
};

Because TYPE_BLOB < TYPE_STRING and delim_start[] is a static array,
delim_start[emit_type] is 0x0. The glibc usually prints out "(null)"
when one passes 0x0 to %s, but it seems to call fputs() internally if
the format is exactly "%s", hence the crash.

TYPE_BLOB basically means the data comes from a file and we don't know
its type. We don't care for the former, and the latter is TYPE_NONE.

So let's drop TYPE_BLOB completely and use TYPE_NONE instead when reading
the file. Then, try to guess the data type at emission time, like the
code already does for refs and labels.

Instead of adding yet another check for TYPE_NONE, an helper is introduced
to check if the data marker has type information, ie, >= TYPE_UINT8.

Fixes: 32b9c61
Suggested-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Greg Kurz <groug@kaod.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
  • Loading branch information
gkurz authored and dgibson committed Aug 31, 2018
1 parent ac68ff9 commit 9619c86
Show file tree
Hide file tree
Showing 3 changed files with 8 additions and 4 deletions.
2 changes: 1 addition & 1 deletion data.c
Expand Up @@ -95,7 +95,7 @@ struct data data_copy_file(FILE *f, size_t maxlen)
{
struct data d = empty_data;

d = data_add_marker(d, TYPE_BLOB, NULL);
d = data_add_marker(d, TYPE_NONE, NULL);
while (!feof(f) && (d.len < maxlen)) {
size_t chunksize, ret;

Expand Down
1 change: 0 additions & 1 deletion dtc.h
Expand Up @@ -82,7 +82,6 @@ enum markertype {
TYPE_UINT16,
TYPE_UINT32,
TYPE_UINT64,
TYPE_BLOB,
TYPE_STRING,
};
extern const char *markername(enum markertype markertype);
Expand Down
9 changes: 7 additions & 2 deletions treesource.c
Expand Up @@ -133,9 +133,14 @@ static void write_propval_int(FILE *f, const char *p, size_t len, size_t width)
}
}

static bool has_data_type_information(struct marker *m)
{
return m->type >= TYPE_UINT8;
}

static struct marker *next_type_marker(struct marker *m)
{
while (m && (m->type == LABEL || m->type == REF_PHANDLE || m->type == REF_PATH))
while (m && !has_data_type_information(m))
m = m->next;
return m;
}
Expand Down Expand Up @@ -225,7 +230,7 @@ static void write_propval(FILE *f, struct property *prop)
size_t chunk_len;
const char *p = &prop->val.val[m->offset];

if (m->type < TYPE_UINT8)
if (!has_data_type_information(m))
continue;

chunk_len = type_marker_length(m);
Expand Down

0 comments on commit 9619c86

Please sign in to comment.