From 16bea7fd0faa75e51e95d9f7aafa6d411019025d Mon Sep 17 00:00:00 2001 From: "Reece H. Dunn" Date: Sat, 19 Aug 2017 11:44:13 +0100 Subject: [PATCH] Don't crash in LoadVoice if langopts is NULL. --- src/libespeak-ng/voices.c | 112 +++++++++++++++++++++++--------------- tests/api.c | 37 +++++++++++++ 2 files changed, 104 insertions(+), 45 deletions(-) diff --git a/src/libespeak-ng/voices.c b/src/libespeak-ng/voices.c index 6a9d68b2..47a15209 100644 --- a/src/libespeak-ng/voices.c +++ b/src/libespeak-ng/voices.c @@ -705,47 +705,57 @@ voice_t *LoadVoice(const char *vname, int control) break; case V_INTONATION: // intonation sscanf(p, "%d %d", &option_tone_flags, &option_tone2); - if ((option_tone_flags & 0xff) != 0) - langopts->intonation_group = option_tone_flags & 0xff; + if ((option_tone_flags & 0xff) != 0) { + if (langopts) + langopts->intonation_group = option_tone_flags & 0xff; + else + fprintf(stderr, "Cannot set intonation: language not set, or is invalid.\n"); + } break; case V_TUNES: n = sscanf(p, "%s %s %s %s %s %s", names[0], names[1], names[2], names[3], names[4], names[5]); - langopts->intonation_group = 0; - for (ix = 0; ix < n; ix++) { - if (strcmp(names[ix], "NULL") == 0) - continue; + if (langopts) { + langopts->intonation_group = 0; + for (ix = 0; ix < n; ix++) { + if (strcmp(names[ix], "NULL") == 0) + continue; - if ((value = LookupTune(names[ix])) < 0) - fprintf(stderr, "Unknown tune '%s'\n", names[ix]); - else - langopts->tunes[ix] = value; - } + if ((value = LookupTune(names[ix])) < 0) + fprintf(stderr, "Unknown tune '%s'\n", names[ix]); + else + langopts->tunes[ix] = value; + } + } else + fprintf(stderr, "Cannot set tunes: language not set, or is invalid.\n"); break; case V_DICTRULES: // conditional dictionary rules and list entries case V_NUMBERS: case V_STRESSOPT: - // expect a list of numbers - while (*p != 0) { - while (isspace(*p)) p++; - if ((n = atoi(p)) > 0) { - p++; - if (n < 32) { - if (key == V_DICTRULES) - conditional_rules |= (1 << n); - else if (key == V_NUMBERS) - langopts->numbers |= (1 << n); - else if (key == V_STRESSOPT) - langopts->stress_flags |= (1 << n); - } else { - if ((key == V_NUMBERS) && (n < 64)) - langopts->numbers2 |= (1 << (n-32)); - else - fprintf(stderr, "Bad option number %d\n", n); + if (langopts) { + // expect a list of numbers + while (*p != 0) { + while (isspace(*p)) p++; + if ((n = atoi(p)) > 0) { + p++; + if (n < 32) { + if (key == V_DICTRULES) + conditional_rules |= (1 << n); + else if (key == V_NUMBERS) + langopts->numbers |= (1 << n); + else if (key == V_STRESSOPT) + langopts->stress_flags |= (1 << n); + } else { + if ((key == V_NUMBERS) && (n < 64)) + langopts->numbers2 |= (1 << (n-32)); + else + fprintf(stderr, "Bad option number %d\n", n); + } } + while (isalnum(*p)) p++; } - while (isalnum(*p)) p++; - } - ProcessLanguageOptions(langopts); + ProcessLanguageOptions(langopts); + } else + fprintf(stderr, "Cannot set stressopt: language not set, or is invalid.\n"); break; case V_REPLACE: if (phonemes_set == 0) { @@ -756,22 +766,31 @@ voice_t *LoadVoice(const char *vname, int control) PhonemeReplacement(p); break; case V_WORDGAP: // words - sscanf(p, "%d %d", &langopts->word_gap, &langopts->vowel_pause); + if (langopts) + sscanf(p, "%d %d", &langopts->word_gap, &langopts->vowel_pause); + else + fprintf(stderr, "Cannot set wordgap: language not set, or is invalid.\n"); break; case V_STRESSRULE: - sscanf(p, "%d %d %d %d", &langopts->stress_rule, - &langopts->stress_flags, - &langopts->unstressed_wd1, - &langopts->unstressed_wd2); + if (langopts) + sscanf(p, "%d %d %d %d", &langopts->stress_rule, + &langopts->stress_flags, + &langopts->unstressed_wd1, + &langopts->unstressed_wd2); + else + fprintf(stderr, "Cannot set stressrule: language not set, or is invalid.\n"); break; case V_OPTION: - value2 = 0; - if (((sscanf(p, "%s %d %d", option_name, &value, &value2) >= 2) && ((ix = LookupMnem(options_tab, option_name)) >= 0)) || - ((sscanf(p, "%d %d %d", &ix, &value, &value2) >= 2) && (ix < N_LOPTS))) { - langopts->param[ix] = value; - langopts->param2[ix] = value2; + if (langopts) { + value2 = 0; + if (((sscanf(p, "%s %d %d", option_name, &value, &value2) >= 2) && ((ix = LookupMnem(options_tab, option_name)) >= 0)) || + ((sscanf(p, "%d %d %d", &ix, &value, &value2) >= 2) && (ix < N_LOPTS))) { + langopts->param[ix] = value; + langopts->param2[ix] = value2; + } else + fprintf(stderr, "Bad voice option: %s %s\n", buf, p); } else - fprintf(stderr, "Bad voice option: %s %s\n", buf, p); + fprintf(stderr, "Cannot set option: language not set, or is invalid.\n"); break; case V_ECHO: // echo. suggest: 135mS 11% @@ -852,9 +871,12 @@ voice_t *LoadVoice(const char *vname, int control) case V_STATUS: break; default: - if ((key & 0xff00) == 0x100) - sscanf(p, "%d", &langopts->param[key &0xff]); - else + if ((key & 0xff00) == 0x100) { + if (langopts) + sscanf(p, "%d", &langopts->param[key &0xff]); + else + fprintf(stderr, "Cannot set voice attribute: language not set, or is invalid.\n"); + } else fprintf(stderr, "Bad voice attribute: %s\n", buf); break; } diff --git a/tests/api.c b/tests/api.c index bc57f8a1..e474a039 100644 --- a/tests/api.c +++ b/tests/api.c @@ -275,6 +275,42 @@ test_espeak_set_voice_by_name_invalid_voice() assert(p_decoder == NULL); } +void +test_espeak_set_voice_by_name_language_variant_intonation_parameter() +{ + printf("testing espeak_SetVoiceByName(\"!v/Annie\") (language variant; intonation)\n"); + + assert(event_list == NULL); + assert(translator == NULL); + assert(p_decoder == NULL); + + assert(espeak_Initialize(AUDIO_OUTPUT_RETRIEVAL, 0, NULL, 0) == 22050); + assert(event_list != NULL); + assert(translator == NULL); + assert(p_decoder == NULL); + + assert(espeak_SetVoiceByName("!v/Annie") == EE_OK); + assert(translator != NULL); + assert(strcmp(translator->dictionary_name, "en") == 0); + assert(p_decoder == NULL); + + const char *test = "One two three."; + assert(espeak_Synth(test, strlen(test)+1, 0, POS_CHARACTER, 0, espeakCHARS_AUTO, NULL, NULL) == EE_OK); + assert(translator != NULL); + assert(strcmp(translator->dictionary_name, "en") == 0); + assert(p_decoder != NULL); + + assert(espeak_Synchronize() == EE_OK); + assert(translator != NULL); + assert(strcmp(translator->dictionary_name, "en") == 0); + assert(p_decoder != NULL); + + assert(espeak_Terminate() == EE_OK); + assert(event_list == NULL); + assert(translator == NULL); + assert(p_decoder == NULL); +} + // endregion // region espeak_SetVoiceByProperties @@ -457,6 +493,7 @@ main(int argc, char **argv) test_espeak_set_voice_by_name_blank_voice(); test_espeak_set_voice_by_name_valid_voice(); test_espeak_set_voice_by_name_invalid_voice(); + test_espeak_set_voice_by_name_language_variant_intonation_parameter(); test_espeak_set_voice_by_properties_empty(); test_espeak_set_voice_by_properties_blank_language();