Skip to content

Commit 9fff2f1

Browse files
Mizuchifacebook-github-bot
authored andcommitted
Fix infinite loop when there is circular typedef
Summary: Otherwise thrift compiler will never finish running since functions like `get_true_type()` takes literally forever to return. Reviewed By: createdbysk Differential Revision: D67924820 fbshipit-source-id: c3aadb12cb2fbcd22a4ff61ea690073726c77653
1 parent a1378af commit 9fff2f1

File tree

3 files changed

+40
-1
lines changed

3 files changed

+40
-1
lines changed

third-party/thrift/src/thrift/compiler/sema/sema.cc

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -610,7 +610,33 @@ bool sema::resolve_all_types(sema_context& diags, t_program_bundle& bundle) {
610610
assert(!td.resolve());
611611
success = false;
612612
}
613-
return success;
613+
return success && check_circular_typedef(diags, bundle);
614+
}
615+
616+
bool sema::check_circular_typedef(
617+
sema_context& diags, t_program_bundle& bundle) {
618+
std::unordered_set<const t_type*> checked;
619+
for (auto& td : bundle.root_program()->scope()->placeholder_typedefs()) {
620+
if (checked.count(td.get_type())) {
621+
continue;
622+
}
623+
std::unordered_set<const t_type*> visited;
624+
std::vector<const t_type*> chain;
625+
if (nullptr != t_typedef::find_type_if(td.get_type(), [&](const t_type* t) {
626+
// Find the first typedef which insertion failed
627+
checked.insert(t);
628+
chain.push_back(t);
629+
return visited.insert(t).second == false;
630+
})) {
631+
std::string msg;
632+
for (const auto& i : chain) {
633+
msg += i->name() + (&i != &chain.back() ? " --> " : "");
634+
}
635+
diags.error(td, "Circular typedef: {}", msg);
636+
return false;
637+
}
638+
}
639+
return true;
614640
}
615641

616642
sema::result sema::run(sema_context& ctx, t_program_bundle& bundle) {

third-party/thrift/src/thrift/compiler/sema/sema.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@ struct sema {
3232
// successful and reporting any errors via diags.
3333
bool resolve_all_types(sema_context& diags, t_program_bundle& bundle);
3434

35+
// Check whether we have circular typedef, returning true if successful and
36+
// reporting any errors via diags. Example of circular typedef:
37+
// typedef Foo Bar
38+
// typedef Bar Foo
39+
bool check_circular_typedef(sema_context& diags, t_program_bundle& bundle);
40+
3541
public:
3642
explicit sema(bool use_legacy_type_ref_resolution)
3743
: use_legacy_type_ref_resolution_(use_legacy_type_ref_resolution) {}

third-party/thrift/src/thrift/compiler/test/compiler_test.cc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2350,3 +2350,10 @@ TEST(CompilerTest, not_bundled_annotation) {
23502350
{},
23512351
options);
23522352
}
2353+
2354+
TEST(CompilerTest, circular_typedef) {
2355+
check_compile(R"(
2356+
typedef Foo Bar # expected-error: Circular typedef: Foo --> Bar --> Foo
2357+
typedef Bar Foo
2358+
)");
2359+
}

0 commit comments

Comments
 (0)