Browse Source

Fix storing the line length in the hash chain.

The length is stored as the first byte in the output from
compile_line. As the data pointer is char, if char is signed then
length could be negative resulting in undefined behaviour. This
commit fixes the issue by reading and writing that byte as a
uint8_t.

This bug was caused by 2a00ca79f6.
Previously, the entries could only be a maximum of 128 bytes, and
would not be negative on platforms with signed chars. That
commit was made to support long emoji entries, especially for
non-Latin languages where the utf-8 representations could be
longer than 128 bytes.

This change also adds some documentation to make it clearer what
is going on. NOTE: The code should really be using actual struct
objects instead of writing to opaque char buffers.

Reported by Reef Turner <[email protected]>
master
Reece H. Dunn 8 years ago
parent
commit
ebfa320956
1 changed files with 12 additions and 3 deletions
  1. 12
    3
      src/libespeak-ng/compiledict.c

+ 12
- 3
src/libespeak-ng/compiledict.c View File

@@ -52,7 +52,15 @@ static int text_mode = 0;
static int debug_flag = 0;
static int error_need_dictionary = 0;

// A hash chain is a linked-list of hash chain entry objects:
// struct hash_chain_entry {
// hash_chain_entry *next_entry;
// // dict_line output from compile_line:
// uint8_t length;
// char contents[length];
// };
static char *hash_chains[N_HASH_DICT];

static char letterGroupsDefined[N_LETTER_GROUPS];

MNEM_TAB mnem_rules[] = {
@@ -648,7 +656,7 @@ static int compile_line(char *linebuf, char *dict_line, int n_dict_line, int *ha
length += ix;
}
}
dict_line[0] = length;
*((uint8_t *)dict_line) = (uint8_t)length;

return length;
}
@@ -682,7 +690,7 @@ static void compile_dictlist_end(FILE *f_out)
p = hash_chains[hash];

while (p != NULL) {
length = *(p+sizeof(char *));
length = *(uint8_t *)(p+sizeof(char *));
fwrite(p+sizeof(char *), length, 1, f_out);
memcpy(&p, p, sizeof(char *));
}
@@ -699,7 +707,7 @@ static int compile_dictlist_file(const char *path, const char *filename)
FILE *f_in;
char buf[200];
char fname[sizeof(path_home)+45];
char dict_line[200];
char dict_line[256]; // length is uint8_t, so an entry can't take up more than 256 bytes

text_mode = 0;

@@ -733,6 +741,7 @@ static int compile_dictlist_file(const char *path, const char *filename)

memcpy(p, &hash_chains[hash], sizeof(char *));
hash_chains[hash] = p;
// NOTE: dict_line[0] is the entry length (0-255)
memcpy(p+sizeof(char *), dict_line, length);
count++;
}

Loading…
Cancel
Save