Undefined behaviour relating to placement new in odb
Describe the bug
This line in odb: https://github.com/The-OpenROAD-Project/OpenROAD/blob/6231dc8c45d6eee2b5dd64aa32279820a26ab0e6/src/odb/src/db/dbTable.hpp#L252
assumes that a placement new keeps uninitialised fields, like _oid, intact. But this isn't the case, and indeed with a new compiler (G++ 14.1.1), _oid gets set to zero by the placement new, which totally breaks the internal odb structures, and the ability to find a page from an object, causing a crash as soon as you do something like loading a LEF that's creating db objects.
A provisional fix is:
diff --git a/src/odb/src/db/dbArrayTable.hpp b/src/odb/src/db/dbArrayTable.hpp
index d1a048b91..990fcbe9e 100644
--- a/src/odb/src/db/dbArrayTable.hpp
+++ b/src/odb/src/db/dbArrayTable.hpp
@@ -248,8 +248,9 @@ T* dbArrayTable<T>::create()
}
_dbFreeObject* o = popQ(_free_list);
- o->_oid |= DB_ALLOC_BIT;
+ uint oid = o->_oid;
new (o) T(_db);
+ o->_oid = oid | DB_ALLOC_BIT;
T* t = (T*) o;
dbArrayTablePage* page = (dbArrayTablePage*) t->getObjectPage();
@@ -395,8 +396,8 @@ void dbArrayTable<T>::copy_page(uint page_id, dbArrayTablePage* page)
for (; t < e; t++, o++) {
if (t->_oid & DB_ALLOC_BIT) {
- o->_oid = t->_oid;
new (o) T(_db, *t);
+ o->_oid = t->_oid;
} else {
*((_dbFreeObject*) o) = *((_dbFreeObject*) t);
}
diff --git a/src/odb/src/db/dbTable.hpp b/src/odb/src/db/dbTable.hpp
index a9073a041..04a01f31c 100644
--- a/src/odb/src/db/dbTable.hpp
+++ b/src/odb/src/db/dbTable.hpp
@@ -249,8 +249,10 @@ T* dbTable<T>::create()
}
_dbFreeObject* o = popQ(_free_list);
+ uint oid = o->_oid;
new (o) T(_db);
- o->_oid |= DB_ALLOC_BIT;
+ // placement new isn't guaranteed to leave an uninitialised field (like _oid) alone
+ o->_oid = oid | DB_ALLOC_BIT;
T* t = (T*) o;
dbTablePage* page = (dbTablePage*) t->getObjectPage();
@@ -279,8 +281,9 @@ T* dbTable<T>::duplicate(T* c)
}
_dbFreeObject* o = popQ(_free_list);
- o->_oid |= DB_ALLOC_BIT;
+ uint oid = o->_oid;
new (o) T(_db, *c);
+ o->_oid = oid | DB_ALLOC_BIT;
T* t = (T*) o;
dbTablePage* page = (dbTablePage*) t->getObjectPage();
@@ -613,8 +616,8 @@ void dbTable<T>::copy_page(uint page_id, dbTablePage* page)
for (; t < e; t++, o++) {
if (t->_oid & DB_ALLOC_BIT) {
- o->_oid = t->_oid;
new (o) T(_db, *t);
+ o->_oid = t->_oid;
} else {
*((_dbFreeObject*) o) = *((_dbFreeObject*) t);
}
But I'm not 100% sure if this catches all the cases and is fully correct, I notice the compiler produces a similar uninitialised warning around destructor calls in this file (e.g. this line), which might also have the same problem but I haven't investigated or tested yet.
Expected Behavior
OpenDB works on modern compilers
Environment
Git commit: 6231dc8c45d6eee2b5dd64aa32279820a26ab0e6
kernel: Linux 6.8.9-arch1-2
os: Arch Linux
cmake version 3.29.3
CMake Warning at CMakeLists.txt:98 (message):
OpenROAD git describe failed, using sha1 instead
-- The CXX compiler identification is GNU 14.1.1
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- OpenROAD version: HEAD-HASH-NOTFOUND
-- System name: Linux
-- Compiler: GNU 14.1.1
-- Build type: RELEASE
-- Install prefix: /usr/local
-- C++ Standard: 17
-- C++ Standard Required: ON
-- C++ Extensions: OFF
-- The C compiler identification is GNU 14.1.1
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Found Python: /usr/bin/python3.12 (found version "3.12.3") found components: Interpreter
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD - Success
-- Found Threads: TRUE
-- Performing Test C_COMPILER_SUPPORTS__-Wall
-- Performing Test C_COMPILER_SUPPORTS__-Wall - Success
-- Performing Test CXX_COMPILER_SUPPORTS__-Wall
-- Performing Test CXX_COMPILER_SUPPORTS__-Wall - Success
-- Performing Test C_COMPILER_SUPPORTS__-Wno-array-bounds
-- Performing Test C_COMPILER_SUPPORTS__-Wno-array-bounds - Success
-- Performing Test CXX_COMPILER_SUPPORTS__-Wno-array-bounds
-- Performing Test CXX_COMPILER_SUPPORTS__-Wno-array-bounds - Success
-- Performing Test C_COMPILER_SUPPORTS__-Wno-nonnull
-- Performing Test C_COMPILER_SUPPORTS__-Wno-nonnull - Success
-- Performing Test CXX_COMPILER_SUPPORTS__-Wno-nonnull
-- Performing Test CXX_COMPILER_SUPPORTS__-Wno-nonnull - Success
-- Performing Test C_COMPILER_SUPPORTS__-Wno-maybe-uninitialized
-- Performing Test C_COMPILER_SUPPORTS__-Wno-maybe-uninitialized - Success
-- Performing Test CXX_COMPILER_SUPPORTS__-Wno-maybe-uninitialized
-- Performing Test CXX_COMPILER_SUPPORTS__-Wno-maybe-uninitialized - Success
-- Performing Test C_COMPILER_SUPPORTS__-Wno-format-overflow
-- Performing Test C_COMPILER_SUPPORTS__-Wno-format-overflow - Success
-- Performing Test CXX_COMPILER_SUPPORTS__-Wno-format-overflow
-- Performing Test CXX_COMPILER_SUPPORTS__-Wno-format-overflow - Success
-- Performing Test C_COMPILER_SUPPORTS__-Wno-unused-variable
-- Performing Test C_COMPILER_SUPPORTS__-Wno-unused-variable - Success
-- Performing Test CXX_COMPILER_SUPPORTS__-Wno-unused-variable
-- Performing Test CXX_COMPILER_SUPPORTS__-Wno-unused-variable - Success
-- Performing Test C_COMPILER_SUPPORTS__-Wno-unused-function
-- Performing Test C_COMPILER_SUPPORTS__-Wno-unused-function - Success
-- Performing Test CXX_COMPILER_SUPPORTS__-Wno-unused-function
-- Performing Test CXX_COMPILER_SUPPORTS__-Wno-unused-function - Success
-- Performing Test C_COMPILER_SUPPORTS__-Wno-write-strings
-- Performing Test C_COMPILER_SUPPORTS__-Wno-write-strings - Success
-- Performing Test CXX_COMPILER_SUPPORTS__-Wno-write-strings
-- Performing Test CXX_COMPILER_SUPPORTS__-Wno-write-strings - Success
-- Performing Test C_COMPILER_SUPPORTS__-Wno-sign-compare
-- Performing Test C_COMPILER_SUPPORTS__-Wno-sign-compare - Success
-- Performing Test CXX_COMPILER_SUPPORTS__-Wno-sign-compare
-- Performing Test CXX_COMPILER_SUPPORTS__-Wno-sign-compare - Success
-- Performing Test C_COMPILER_SUPPORTS__-Wno-deprecated
-- Performing Test C_COMPILER_SUPPORTS__-Wno-deprecated - Success
-- Performing Test CXX_COMPILER_SUPPORTS__-Wno-deprecated
-- Performing Test CXX_COMPILER_SUPPORTS__-Wno-deprecated - Success
-- Performing Test C_COMPILER_SUPPORTS__-Wno-c++11-narrowing
-- Performing Test C_COMPILER_SUPPORTS__-Wno-c++11-narrowing - Failed
-- Performing Test CXX_COMPILER_SUPPORTS__-Wno-c++11-narrowing
-- Performing Test CXX_COMPILER_SUPPORTS__-Wno-c++11-narrowing - Failed
-- Performing Test C_COMPILER_SUPPORTS__-Wno-register
-- Performing Test C_COMPILER_SUPPORTS__-Wno-register - Failed
-- Performing Test CXX_COMPILER_SUPPORTS__-Wno-register
-- Performing Test CXX_COMPILER_SUPPORTS__-Wno-register - Success
-- Performing Test C_COMPILER_SUPPORTS__-Wno-format
-- Performing Test C_COMPILER_SUPPORTS__-Wno-format - SuccesCMake Warning at src/CMakeLists.txt:245 (message):
spdlog: SPDLOG_FMT_EXTERNAL=ON
s
-- Performing Test CXX_COMPILER_SUPPORTS__-Wno-format
-- Performing Test CXX_COMPILER_SUPPORTS__-Wno-format - Success
-- Performing Test C_COMPILER_SUPPORTS__-Wno-reserved-user-defined-literal
-- Performing Test C_COMPILER_SUPPORTS__-Wno-reserved-user-defined-literal - Failed
-- Performing Test CXX_COMPILER_SUPPORTS__-Wno-reserved-user-defined-literal
-- Performing Test CXX_COMPILER_SUPPORTS__-Wno-reserved-user-defined-literal - Failed
-- Performing Test C_COMPILER_SUPPORTS__-fpermissive
-- Performing Test C_COMPILER_SUPPORTS__-fpermissive - Success
-- Performing Test CXX_COMPILER_SUPPORTS__-fpermissive
-- Performing Test CXX_COMPILER_SUPPORTS__-fpermissive - Success
-- Performing Test C_COMPILER_SUPPORTS__-x
-- Performing Test C_COMPILER_SUPPORTS__-x - Failed
-- Performing Test CXX_COMPILER_SUPPORTS__-x
-- Performing Test CXX_COMPILER_SUPPORTS__-x - Failed
-- Performing Test C_COMPILER_SUPPORTS__c++
-- Performing Test C_COMPILER_SUPPORTS__c++ - Failed
-- Performing Test CXX_COMPILER_SUPPORTS__c++
-- Performing Test CXX_COMPILER_SUPPORTS__c++ - Failed
-- Performing Test C_COMPILER_SUPPORTS__-std=c++17
-- Performing Test C_COMPILER_SUPPORTS__-std=c++17 - Failed
-- Performing Test CXX_COMPILER_SUPPORTS__-std=c++17
-- Performing Test CXX_COMPILER_SUPPORTS__-std=c++17 - Success
-- Performing Test C_COMPILER_SUPPORTS__-Wno-unused-but-set-variable
-- Performing Test C_COMPILER_SUPPORTS__-Wno-unused-but-set-variable - Success
-- Performing Test CXX_COMPILER_SUPPORTS__-Wno-unused-but-set-variable
-- Performing Test CXX_COMPILER_SUPPORTS__-Wno-unused-but-set-variable - Success
-- TCL library: /usr/lib/libtcl.so
-- TCL header: /usr/include/tcl.h
-- Found SWIG: /usr/bin/swig (found suitable version "4.2.1", minimum required is "4.0")
-- Using SWIG >= 4.2.1 -flatstaticmethod flag for python
-- Found Boost: /usr/lib/cmake/Boost-1.83.0/BoostConfig.cmake (found version "1.83.0")
-- boost: 1.83.0
-- Found Python3: /usr/include/python3.12 (found version "3.12.3") found components: Development Development.Module Development.Embed
-- Found ZLIB: /usr/lib/libz.so (found version "1.3.1")
-- spdlog: 1.13.0
-- Found BISON: /usr/bin/bison (found version "3.8.2")
-- Found Doxygen: /usr/bin/doxygen (found version "1.10.0") found components: doxygen dot
-- STA version: 2.5.0
-- STA git sha: b71b48ad16590ea7fa144790a2f7ab2ab3d24640
-- System name: Linux
-- Compiler: GNU 14.1.1
-- Build type: RELEASE
-- Build CXX_FLAGS: -O3 -DNDEBUG
-- Install prefix: /usr/local
-- Found FLEX: /usr/bin/flex (found version "2.6.4")
-- TCL library: /usr/lib/libtcl.so
-- TCL header: /usr/include/tcl.h
-- SSTA: 0
-- Found SWIG: /usr/bin/swig (found suitable version "4.2.1", minimum required is "3.0")
-- STA executable: /home/gatecat/OpenROAD-upstream/src/sta/app/sta
-- Found Protobuf: /usr/lib/libprotobuf.so (found version "4.25.3")
-- Found OpenMP_CXX: -fopenmp (found version "4.5")
-- Found OpenMP: TRUE (found version "4.5")
-- GPU is not enabled
-- TCL library: /usr/lib/libtcl.so
-- TCL header: /usr/include/tcl.h
-- GUI is enabled
-- Charts widget is not enabled
-- Found Boost: /usr/lib/cmake/Boost-1.83.0/BoostConfig.cmake (found version "1.83.0") found components: serialization
-- Could NOT find VTune (missing: VTune_LIBRARIES VTune_INCLUDE_DIRS)
-- Found Boost: /usr/lib/cmake/Boost-1.83.0/BoostConfig.cmake (found suitable version "1.83.0", minimum required is "1.78")
-- TCL library: /usr/lib/libtcl.so
-- TCL header: /usr/include/tcl.h
-- Found Boost: /usr/lib/cmake/Boost-1.83.0/BoostConfig.cmake (found version "1.83.0") found components: serialization system thread
-- Found Boost: /usr/lib/cmake/Boost-1.83.0/BoostConfig.cmake (found version "1.83.0")
-- Found PkgConfig: /usr/bin/pkg-config (found version "2.1.1")
-- Checking for modules 're2;IMPORTED'
-- Package 'IMPORTED', required by 'virtual:world', not found
-- Checking for modules 'Cbc;IMPORTED'
-- Package 'Cbc', required by 'virtual:world', not found
-- Package 'IMPORTED', required by 'virtual:world', not found
-- Checking for modules 'Cbc;IMPORTED'
-- Package 'Cbc', required by 'virtual:world', noNumber of processor cores: 16
t found
-- Package 'IMPORTED', required by 'virtual:world', not found
-- Checking for modules 'Cbc;IMPORTED'
-- Package 'Cbc', required by 'virtual:world', not found
-- Package 'IMPORTED', required by 'virtual:world', not found
-- Found Eigen3: /usr/share/eigen3/cmake/Eigen3Config.cmake (found version "3.4.0")
-- Checking for modules 're2;IMPORTED'
-- Package 'IMPORTED', required by 'virtual:world', not found
-- TCL readline disabled
-- Tcl Extended disabled
-- Python3 enabled
-- Configuring done (5.9s)
-- Generating done (0.4s)
-- Build files have been written to: /tmp/tmp.d2PdItTTO0
To Reproduce
Open a LEF file in OpenROAD built by G++ 14.1.1
Relevant log output
No response
Screenshots
No response
Additional Context
No response