From 5101b9fcba8f892a45bb5371e6f25f4d2ae9a46d Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Wed, 16 Apr 2025 18:52:49 +0200 Subject: [PATCH 1/4] liberty: Fix handling of non-ascii characters Use an `unsigned char` buffer to ensure characters cast to an `int` are in the range 0 <= c <= 255. --- passes/techmap/libparse.cc | 2 +- passes/techmap/libparse.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/passes/techmap/libparse.cc b/passes/techmap/libparse.cc index bc7758cbd..97a94ece0 100644 --- a/passes/techmap/libparse.cc +++ b/passes/techmap/libparse.cc @@ -75,7 +75,7 @@ bool LibertyInputStream::extend_buffer_once() buffer.resize(buf_end + chunk_size); } - size_t read_size = f.rdbuf()->sgetn(buffer.data() + buf_end, chunk_size); + size_t read_size = f.rdbuf()->sgetn((char *)buffer.data() + buf_end, chunk_size); buf_end += read_size; if (read_size < chunk_size) eof = true; diff --git a/passes/techmap/libparse.h b/passes/techmap/libparse.h index 3ba381fdf..f834044ae 100644 --- a/passes/techmap/libparse.h +++ b/passes/techmap/libparse.h @@ -92,7 +92,7 @@ namespace Yosys class LibertyInputStream { std::istream &f; - std::vector buffer; + std::vector buffer; size_t buf_pos = 0; size_t buf_end = 0; bool eof = false; @@ -107,7 +107,7 @@ namespace Yosys LibertyInputStream(std::istream &f) : f(f) {} size_t buffered_size() { return buf_end - buf_pos; } - const char *buffered_data() { return buffer.data() + buf_pos; } + const unsigned char *buffered_data() { return buffer.data() + buf_pos; } int get() { if (buf_pos == buf_end) From 418e795235a0b2b8ebd5a39d8b0fa32c8707f0e7 Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Wed, 16 Apr 2025 19:03:05 +0200 Subject: [PATCH 2/4] liberty: Error when a read liberty file has no nodes --- passes/techmap/libparse.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/passes/techmap/libparse.h b/passes/techmap/libparse.h index f834044ae..e52f91e77 100644 --- a/passes/techmap/libparse.h +++ b/passes/techmap/libparse.h @@ -176,6 +176,14 @@ namespace Yosys LibertyParser(std::istream &f) : f(f), line(1) { shared_ast.reset(parse()); ast = shared_ast.get(); + if (!ast) { +#ifdef FILTERLIB + fprintf(stderr, "No entries found in liberty file.\n"); + exit(1); +#else + log_error("No entries found in liberty file.\n"); +#endif + } } #ifndef FILTERLIB @@ -186,6 +194,9 @@ namespace Yosys LibertyAstCache::instance.parsed_ast(fname, shared_ast); } ast = shared_ast.get(); + if (!ast) { + log_error("No entries found in liberty file `%s'.\n", fname.c_str()); + } } #endif }; From ce74404890242d8a45bccb6ee2fefd302316efcf Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Wed, 16 Apr 2025 19:12:01 +0200 Subject: [PATCH 3/4] liberty: Error on unclosed curly braces This is an indication that the liberty file was truncated, which shouldn't be silently ignored. --- passes/techmap/libparse.cc | 23 +++++++++++++++++++---- passes/techmap/libparse.h | 6 +++--- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/passes/techmap/libparse.cc b/passes/techmap/libparse.cc index 97a94ece0..5594d5443 100644 --- a/passes/techmap/libparse.cc +++ b/passes/techmap/libparse.cc @@ -436,6 +436,9 @@ void LibertyParser::report_unexpected_token(int tok) eReport += "'."; error(eReport); break; + case EOF: + error("Unexpected end of file"); + break; default: eReport = "Unexpected token: "; eReport += static_cast(tok); @@ -484,7 +487,7 @@ void LibertyParser::parse_vector_range(int tok) } } -LibertyAst *LibertyParser::parse() +LibertyAst *LibertyParser::parse(bool top_level) { std::string str; @@ -498,7 +501,13 @@ LibertyAst *LibertyParser::parse() while ((tok == 'n') || (tok == ';')) tok = lexer(str); - if (tok == '}' || tok < 0) + if (tok == EOF) { + if (top_level) + return NULL; + report_unexpected_token(tok); + } + + if (tok == '}') return NULL; if (tok != 'v') { @@ -571,12 +580,18 @@ LibertyAst *LibertyParser::parse() } if (tok == '{') { + bool terminated = false; while (1) { - LibertyAst *child = parse(); - if (child == NULL) + LibertyAst *child = parse(false); + if (child == NULL) { + terminated = true; break; + } ast->children.push_back(child); } + if (!terminated) { + report_unexpected_token(EOF); + } break; } diff --git a/passes/techmap/libparse.h b/passes/techmap/libparse.h index e52f91e77..61dc83867 100644 --- a/passes/techmap/libparse.h +++ b/passes/techmap/libparse.h @@ -165,7 +165,7 @@ namespace Yosys void report_unexpected_token(int tok); void parse_vector_range(int tok); - LibertyAst *parse(); + LibertyAst *parse(bool top_level); void error() const; void error(const std::string &str) const; @@ -174,7 +174,7 @@ namespace Yosys const LibertyAst *ast = nullptr; LibertyParser(std::istream &f) : f(f), line(1) { - shared_ast.reset(parse()); + shared_ast.reset(parse(true)); ast = shared_ast.get(); if (!ast) { #ifdef FILTERLIB @@ -190,7 +190,7 @@ namespace Yosys LibertyParser(std::istream &f, const std::string &fname) : f(f), line(1) { shared_ast = LibertyAstCache::instance.cached_ast(fname); if (!shared_ast) { - shared_ast.reset(parse()); + shared_ast.reset(parse(true)); LibertyAstCache::instance.parsed_ast(fname, shared_ast); } ast = shared_ast.get(); From c555add2310db3556db09a2e1e15864917a93fc3 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Thu, 17 Apr 2025 00:17:06 +0200 Subject: [PATCH 4/4] liberty: Test non-ascii characters --- tests/liberty/non-ascii.lib | 14 ++++++++++++++ tests/liberty/non-ascii.lib.filtered.ok | 12 ++++++++++++ tests/liberty/non-ascii.lib.verilogsim.ok | 5 +++++ 3 files changed, 31 insertions(+) create mode 100644 tests/liberty/non-ascii.lib create mode 100644 tests/liberty/non-ascii.lib.filtered.ok create mode 100644 tests/liberty/non-ascii.lib.verilogsim.ok diff --git a/tests/liberty/non-ascii.lib b/tests/liberty/non-ascii.lib new file mode 100644 index 000000000..1ac636e34 --- /dev/null +++ b/tests/liberty/non-ascii.lib @@ -0,0 +1,14 @@ +// The parser used to choke on the copyright symbol even in comments +// © ® ø Φ +library(dummy) { + cell(buffer) { + area : 1 ; + pin(A) { + direction : input ; + } + pin(Y) { + direction : output ; + function : "A" ; + } + } +} \ No newline at end of file diff --git a/tests/liberty/non-ascii.lib.filtered.ok b/tests/liberty/non-ascii.lib.filtered.ok new file mode 100644 index 000000000..f03f725f7 --- /dev/null +++ b/tests/liberty/non-ascii.lib.filtered.ok @@ -0,0 +1,12 @@ +library(dummy) { + cell(buffer) { + area : 1 ; + pin(A) { + direction : input ; + } + pin(Y) { + direction : output ; + function : "A" ; + } + } +} diff --git a/tests/liberty/non-ascii.lib.verilogsim.ok b/tests/liberty/non-ascii.lib.verilogsim.ok new file mode 100644 index 000000000..de5e2e5f3 --- /dev/null +++ b/tests/liberty/non-ascii.lib.verilogsim.ok @@ -0,0 +1,5 @@ +module buffer (A, Y); + input A; + output Y; + assign Y = A; // "A" +endmodule