diff --git a/Changes b/Changes index 315b9d191..0bc065689 100644 --- a/Changes +++ b/Changes @@ -28,6 +28,7 @@ Verilator 4.203 devel * Fix initialization of assoc in assoc array (#2914). [myftptoyman] * Fix make support for gmake 3.x (#2920) (#2921). [Philipp Wagner] * Fix VPI memory access for packed arrays (#2922). [Todd Strader] +* Fix MCD close also closing stdout (#2931). [Alexander Grobman] * Fix split procedures to better respect --output-split-cfuncs (#2942). [Geza Lore] * Fix to emit 'else if' without nesting (#2944). [Geza Lore] * Fix part select issues in LATCH warning (#2948) (#2938). [Julien Margetts] diff --git a/include/verilated_imp.h b/include/verilated_imp.h index 584213b38..b4d13e0e0 100644 --- a/include/verilated_imp.h +++ b/include/verilated_imp.h @@ -333,17 +333,20 @@ public: // But only for verilated*.cpp } void fdClose(IData fdi) VL_MT_SAFE_EXCLUDES(m_fdMutex) { const VerilatedLockGuard lock(m_fdMutex); - if ((fdi & (1 << 31)) != 0) { + if (VL_BITISSET_I(fdi, 31)) { // Non-MCD case IData idx = VL_MASK_I(31) & fdi; if (VL_UNLIKELY(idx >= m_fdps.size())) return; + if (VL_UNLIKELY(idx <= 2)) return; // stdout/stdin/stderr if (VL_UNLIKELY(!m_fdps[idx])) return; // Already free std::fclose(m_fdps[idx]); m_fdps[idx] = (FILE*)0; m_fdFree.push_back(idx); } else { // MCD case - for (int i = 0; (fdi != 0) && (i < 31); i++, fdi >>= 1) { + // Starts at 1 to skip stdout + fdi >>= 1; + for (int i = 1; (fdi != 0) && (i < 31); i++, fdi >>= 1) { if (fdi & VL_MASK_I(1)) { std::fclose(m_fdps[i]); m_fdps[i] = nullptr; @@ -375,7 +378,9 @@ private: } } else { // MCD Case - for (size_t i = 0; (fdi != 0) && (i < fp.capacity()); ++i, fdi >>= 1) { + if (fdi & 1) fp.push_back(stdout); + fdi >>= 1; + for (size_t i = 1; (fdi != 0) && (i < fp.capacity()); ++i, fdi >>= 1) { if (fdi & VL_MASK_I(1)) fp.push_back(m_fdps[i]); } } diff --git a/test_regress/t/t_sys_file_basic_mcd.out b/test_regress/t/t_sys_file_basic_mcd.out index bac06f7e9..636fdaca3 100644 --- a/test_regress/t/t_sys_file_basic_mcd.out +++ b/test_regress/t/t_sys_file_basic_mcd.out @@ -1,2 +1,3 @@ Sean Connery was the best Bond. +To file and to stdout *-* All Finished *-* diff --git a/test_regress/t/t_sys_file_basic_mcd.pl b/test_regress/t/t_sys_file_basic_mcd.pl index 106810fa0..e77ffbc08 100755 --- a/test_regress/t/t_sys_file_basic_mcd.pl +++ b/test_regress/t/t_sys_file_basic_mcd.pl @@ -24,6 +24,8 @@ files_identical("$Self->{obj_dir}/t_sys_file_basic_mcd_test2_1.dat", "$Self->{t_dir}/t_sys_file_basic_mcd_test2_1.dat"); files_identical("$Self->{obj_dir}/t_sys_file_basic_mcd_test2_2.dat", "$Self->{t_dir}/t_sys_file_basic_mcd_test2_2.dat"); +files_identical("$Self->{obj_dir}/t_sys_file_basic_mcd_test5.dat", + "$Self->{t_dir}/t_sys_file_basic_mcd_test5.dat"); ok(1); 1; diff --git a/test_regress/t/t_sys_file_basic_mcd.v b/test_regress/t/t_sys_file_basic_mcd.v index 16742829a..54d0aba21 100644 --- a/test_regress/t/t_sys_file_basic_mcd.v +++ b/test_regress/t/t_sys_file_basic_mcd.v @@ -30,7 +30,7 @@ module t; if (fd_fail != 0) fail("Able to allocate MCD descriptor when fully utilized."); // Return descriptor back to pool - fd_close = fd[0]; + fd_close = fd[0]; $fclose(fd_close); // Re-attempt MCD allocation; should pass at this point. fd_success = $fopen($sformatf("%s/yet_another_file.dat", `STR(`TEST_OBJ_DIR))); @@ -76,12 +76,21 @@ module t; int fd; // Wide filename fd = $fopen({`STR(`TEST_OBJ_DIR), - "some_very_large_filename_that_no_one_would_ever_use_", + "/some_very_large_filename_that_no_one_would_ever_use_", "except_to_purposefully_break_my_beautiful_code.dat"}); if (fd == 0) fail("Long filename could not be opened."); $fclose(fd); end endtask + task automatic test5; begin + int fd_all; + fd_all = $fopen({`STR(`TEST_OBJ_DIR), "/t_sys_file_basic_mcd_test5.dat"}); + if (fd_all == 0) fail("could not be opened."); + fd_all |= 1; + $fdisplay(fd_all, "To file and to stdout"); + $fclose(fd_all); + end endtask + initial begin // Test1: Validate file descriptor region. @@ -96,6 +105,9 @@ module t; // Test4: Validate filename lengths test4; + // Test5: OR with stdout + test5; + $write("*-* All Finished *-*\n"); $finish(0); // Test arguments to finish diff --git a/test_regress/t/t_sys_file_basic_mcd_test5.dat b/test_regress/t/t_sys_file_basic_mcd_test5.dat new file mode 100644 index 000000000..a623ecae3 --- /dev/null +++ b/test_regress/t/t_sys_file_basic_mcd_test5.dat @@ -0,0 +1 @@ +To file and to stdout