libdvbv5: don't use realloc() inside pat.c
authorMauro Carvalho Chehab <m.chehab@samsung.com>
Thu, 28 Nov 2013 11:34:15 +0000 (09:34 -0200)
committerMauro Carvalho Chehab <m.chehab@samsung.com>
Thu, 28 Nov 2013 11:41:34 +0000 (09:41 -0200)
The usage of realloc() inside pat is wrong, as the newly reallocated
data could have a different address, and this is not returned back
to dvb-scan's dvb_read_section_with_id().

While we could do some other tricks to pass the new pointer back,
the entire logic is really not good. Also, the PAT handler uses a
different model than the other tables.

So, change it to use a linked list for the programs. This can, however,
break the API for other applications using it.

Fortunately, the dvb_pat_program_foreach() macro abstracts this
API difference, so, the breakage will not actually happen, if the
other apps use this macro (with is the case of tvdaemon).

Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
lib/include/descriptors/pat.h
lib/libdvbv5/descriptors.c
lib/libdvbv5/descriptors/nit.c
lib/libdvbv5/descriptors/pat.c
lib/libdvbv5/dvb-scan.c

index 419e342..edb58c5 100644 (file)
@@ -39,17 +39,17 @@ struct dvb_table_pat_program {
                        uint8_t  reserved:3;
                } __attribute__((packed));
        };
+       struct dvb_table_pat_program *next;
 } __attribute__((packed));
 
 struct dvb_table_pat {
        struct dvb_table_header header;
        uint16_t programs;
-       struct dvb_table_pat_program program[];
+       struct dvb_table_pat_program *program;
 } __attribute__((packed));
 
-#define dvb_pat_program_foreach(_program, _pat) \
-       struct dvb_table_pat_program *_program; \
-       for (int _i = 0; _i < _pat->programs && (_program = _pat->program + _i); _i++) \
+#define dvb_pat_program_foreach(_pgm, _pat) \
+       for (struct dvb_table_pat_program *_pgm = _pat->program; _pgm; _pgm = _pgm->next) \
 
 struct dvb_v5_fe_parms;
 
index d12119f..7d44653 100644 (file)
@@ -74,7 +74,7 @@ void dvb_desc_default_print(struct dvb_v5_fe_parms *parms, const struct dvb_desc
 }
 
 const struct dvb_table_init dvb_table_initializers[] = {
-       [DVB_TABLE_PAT] = { dvb_table_pat_init, 0 /* Size here is variable */ },
+       [DVB_TABLE_PAT] = { dvb_table_pat_init, sizeof(struct dvb_table_pat) },
        [DVB_TABLE_PMT] = { dvb_table_pmt_init, sizeof(struct dvb_table_pmt) },
        [DVB_TABLE_NIT] = { dvb_table_nit_init, sizeof(struct dvb_table_nit) },
        [DVB_TABLE_SDT] = { dvb_table_sdt_init, sizeof(struct dvb_table_sdt) },
index 3cb4dbe..97865d2 100644 (file)
@@ -90,7 +90,9 @@ void dvb_table_nit_init(struct dvb_v5_fe_parms *parms, const uint8_t *buf, ssize
 
        size = offsetof(struct dvb_table_nit_transport, descriptor);
        while (p + size <= endbuf) {
-               struct dvb_table_nit_transport *transport = malloc(sizeof(struct dvb_table_nit_transport));
+               struct dvb_table_nit_transport *transport;
+
+               transport = malloc(sizeof(struct dvb_table_nit_transport));
                if (!transport)
                        dvb_perror("Out of memory");
                memcpy(transport, p, size);
index af68b38..2b6fd7f 100644 (file)
 void dvb_table_pat_init(struct dvb_v5_fe_parms *parms, const uint8_t *buf, ssize_t buflen, uint8_t *table, ssize_t *table_length)
 {
        struct dvb_table_pat *pat = (struct dvb_table_pat *) table;
+       struct dvb_table_pat_program **head, *last = NULL;
+
        const uint8_t *p = buf, *endbuf = buf + buflen - 4;
        size_t size;
 
        if (*table_length > 0) {
-               p += offsetof(struct dvb_table_pat, programs);
-
-               size = sizeof(struct dvb_table_pat_program) * pat->programs;
-               size += buflen;
-
-               pat = realloc(pat, size);
+               /* find end of current list */
+               head = &pat->program;
+               while (*head != NULL)
+                       head = &(*head)->next;
        } else {
                size = offsetof(struct dvb_table_pat, programs);
                if (p + size > endbuf) {
@@ -46,16 +46,33 @@ void dvb_table_pat_init(struct dvb_v5_fe_parms *parms, const uint8_t *buf, ssize
                memcpy(table, buf, size);
                p += size;
                pat->programs = 0;
+               pat->program = NULL;
+               head = &pat->program;
        }
-       *table_length = buflen + sizeof(uint16_t);
+       *table_length = sizeof(struct dvb_table_pat_program);
 
-       size = sizeof(struct dvb_table_pat_program);
+       size = offsetof(struct dvb_table_pat_program, next);
        while (p + size <= endbuf) {
-               memcpy(pat->program + pat->programs, p, size);
-               bswap16(pat->program[pat->programs].service_id);
-               bswap16(pat->program[pat->programs].bitfield);
+               struct dvb_table_pat_program *pgm;
+
+               pgm = malloc(sizeof(struct dvb_table_pat_program));
+               if (!pgm)
+                       dvb_perror("Out of memory");
+
+               memcpy(pgm, p, size);
                p += size;
+
+               bswap16(pgm->service_id);
+               bswap16(pgm->bitfield);
                pat->programs++;
+
+               pgm->next = NULL;
+
+               if (!*head)
+                       *head = pgm;
+               if (last)
+                       last->next = pgm;
+               last = pgm;
        }
        if (endbuf - p)
                dvb_logerr("PAT table has %zu spurious bytes at the end.",
@@ -64,17 +81,27 @@ void dvb_table_pat_init(struct dvb_v5_fe_parms *parms, const uint8_t *buf, ssize
 
 void dvb_table_pat_free(struct dvb_table_pat *pat)
 {
+       struct dvb_table_pat_program *pgm = pat->program;
+
+       while (pgm) {
+               struct dvb_table_pat_program *tmp = pgm;
+               pgm = pgm->next;
+               free(tmp);
+       }
        free(pat);
 }
 
 void dvb_table_pat_print(struct dvb_v5_fe_parms *parms, struct dvb_table_pat *pat)
 {
+       struct dvb_table_pat_program *pgm = pat->program;
+
        dvb_log("PAT");
        dvb_table_header_print(parms, &pat->header);
        dvb_log("|\\  program  service (%d programs)", pat->programs);
-       int i;
-       for (i = 0; i < pat->programs; i++) {
-               dvb_log("|- %7d %7d", pat->program[i].pid, pat->program[i].service_id);
+
+       while (pgm) {
+               dvb_log("|- %7d %7d", pgm->pid, pgm->service_id);
+               pgm = pgm->next;
        }
 }
 
index c5eb68f..978975e 100644 (file)
@@ -215,18 +215,9 @@ int dvb_read_section_with_id(struct dvb_v5_fe_parms *parms, int dmx_fd,
                        }
                }
 
-               if (dvb_table_initializers[tid].init) {
+               if (dvb_table_initializers[tid].init)
                        dvb_table_initializers[tid].init(parms, buf, buf_length, tbl, &table_length);
-                       if (!dvb_table_initializers[tid].size) {
-                               tbl = realloc(tbl, table_length);
-                               if (!tbl) {
-                                       dvb_perror("Out of memory");
-                                       free(buf);
-                                       dvb_dmx_stop(dmx_fd);
-                                       return -4;
-                               }
-                       }
-               } else
+               else
                        dvb_logerr("dvb_read_section: no initializer for table %d", tid);
 
                if (++sections == last_section + 1)