Skip to content

Commit c55e33f

Browse files
fix: harden runtime FST and JNI handling
1 parent 6bc6946 commit c55e33f

3 files changed

Lines changed: 86 additions & 9 deletions

File tree

runtime/bindings/android/wetextprocessing.cc

Lines changed: 69 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
// limitations under the License.
1414
#include <jni.h>
1515

16+
#include <exception>
17+
#include <string>
18+
1619
#include "processor/wetext_processor.h"
1720
#include "utils/wetext_flags.h"
1821
#include "utils/wetext_string.h"
@@ -22,28 +25,85 @@ namespace wetextprocessing {
2225
std::shared_ptr<wetext::Processor> processorTN;
2326
std::shared_ptr<wetext::Processor> processorITN;
2427

28+
namespace {
29+
class UtfStringChars {
30+
public:
31+
UtfStringChars(JNIEnv* env, jstring string)
32+
: env_(env),
33+
string_(string),
34+
chars_(env->GetStringUTFChars(string, nullptr)) {}
35+
36+
UtfStringChars(const UtfStringChars&) = delete;
37+
UtfStringChars& operator=(const UtfStringChars&) = delete;
38+
39+
~UtfStringChars() {
40+
if (chars_ != nullptr) {
41+
env_->ReleaseStringUTFChars(string_, chars_);
42+
}
43+
}
44+
45+
const char* get() const { return chars_; }
46+
47+
private:
48+
JNIEnv* env_;
49+
jstring string_;
50+
const char* chars_;
51+
};
52+
53+
bool CopyJString(JNIEnv* env, jstring string, std::string* output) {
54+
UtfStringChars chars(env, string);
55+
if (chars.get() == nullptr) {
56+
return false;
57+
}
58+
*output = chars.get();
59+
return true;
60+
}
61+
62+
void ThrowIllegalState(JNIEnv* env, const char* message) {
63+
jclass exception_class = env->FindClass("java/lang/IllegalStateException");
64+
if (exception_class != nullptr) {
65+
env->ThrowNew(exception_class, message);
66+
}
67+
}
68+
}
69+
2570
void init(JNIEnv* env, jobject, jstring jModelDir) {
26-
const char* pModelDir = env->GetStringUTFChars(jModelDir, nullptr);
71+
std::string model_dir;
72+
if (!CopyJString(env, jModelDir, &model_dir)) {
73+
return;
74+
}
2775

28-
std::string tnTagger = std::string(pModelDir) + "/zh_tn_tagger.fst";
29-
std::string tnVerbalizer = std::string(pModelDir) + "/zh_tn_verbalizer.fst";
30-
processorTN = std::make_shared<wetext::Processor>(tnTagger, tnVerbalizer);
76+
try {
77+
std::string tnTagger = model_dir + "/zh_tn_tagger.fst";
78+
std::string tnVerbalizer = model_dir + "/zh_tn_verbalizer.fst";
79+
processorTN = std::make_shared<wetext::Processor>(tnTagger, tnVerbalizer);
3180

32-
std::string itnTagger = std::string(pModelDir) + "/zh_itn_tagger.fst";
33-
std::string itnVerbalizer = std::string(pModelDir) + "/zh_itn_verbalizer.fst";
34-
processorITN = std::make_shared<wetext::Processor>(itnTagger, itnVerbalizer);
81+
std::string itnTagger = model_dir + "/zh_itn_tagger.fst";
82+
std::string itnVerbalizer = model_dir + "/zh_itn_verbalizer.fst";
83+
processorITN = std::make_shared<wetext::Processor>(itnTagger, itnVerbalizer);
84+
} catch (const std::exception& error) {
85+
processorTN.reset();
86+
processorITN.reset();
87+
ThrowIllegalState(env, error.what());
88+
}
3589
}
3690

3791
jstring normalize(JNIEnv* env, jobject, jstring input) {
38-
std::string input_text = std::string(env->GetStringUTFChars(input, nullptr));
92+
std::string input_text;
93+
if (!CopyJString(env, input, &input_text)) {
94+
return nullptr;
95+
}
3996
std::string tagged_text = processorTN->Tag(input_text);
4097
std::string normalized_text = processorTN->Verbalize(tagged_text);
4198

4299
return env->NewStringUTF(normalized_text.c_str());
43100
}
44101

45102
jstring inverse_normalize(JNIEnv* env, jobject, jstring input) {
46-
std::string input_text = std::string(env->GetStringUTFChars(input, nullptr));
103+
std::string input_text;
104+
if (!CopyJString(env, input, &input_text)) {
105+
return nullptr;
106+
}
47107
std::string tagged_text = processorITN->Tag(input_text);
48108
std::string normalized_text = processorITN->Verbalize(tagged_text);
49109

runtime/processor/wetext_processor.cc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,22 @@
1414

1515
#include "processor/wetext_processor.h"
1616

17+
#include <stdexcept>
18+
1719
#include "utils/wetext_log.h"
1820

1921
namespace wetext {
2022
Processor::Processor(const std::string& tagger_path,
2123
const std::string& verbalizer_path) {
2224
tagger_.reset(StdVectorFst::Read(tagger_path));
25+
if (tagger_ == nullptr) {
26+
throw std::runtime_error("Failed to load tagger FST: " + tagger_path);
27+
}
2328
verbalizer_.reset(StdVectorFst::Read(verbalizer_path));
29+
if (verbalizer_ == nullptr) {
30+
throw std::runtime_error("Failed to load verbalizer FST: " +
31+
verbalizer_path);
32+
}
2433
compiler_ = std::make_shared<StringCompiler<StdArc>>();
2534
printer_ = std::make_shared<StringPrinter<StdArc>>();
2635

runtime/test/processor_test.cc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15+
#include <stdexcept>
1516
#include <string>
1617
#include <vector>
1718

@@ -72,6 +73,13 @@ TEST_P(ProcessorTest, NormalizeTest) {
7273
EXPECT_EQ(processor->Normalize(written), spoken);
7374
}
7475

76+
TEST(ProcessorLoadTest, ThrowsWhenFstFilesCannotBeLoaded) {
77+
EXPECT_THROW(
78+
wetext::Processor("/tmp/zh_tn_missing_tagger.fst",
79+
"/tmp/zh_tn_missing_verbalizer.fst"),
80+
std::runtime_error);
81+
}
82+
7583
std::vector<std::pair<std::string, std::string>> test_cases =
7684
ParseTestCase(WETEXT_TN_DIR "/chinese/test/data/normalizer.txt");
7785
INSTANTIATE_TEST_SUITE_P(NormalizeTest, ProcessorTest,

0 commit comments

Comments
 (0)