Skip to content

[IR] Avoid UB in SymbolTableListTraits #139096

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 30, 2025
Merged

Conversation

dtcxzyw
Copy link
Member

@dtcxzyw dtcxzyw commented May 8, 2025

This patch fixes the "dereferencing null" UB. Unfortunately, C++ doesn't provide an inverse operation for p->*pmf.
See also #130952.

Copy link

github-actions bot commented May 11, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

@dtcxzyw dtcxzyw requested review from nikic and efriedma-quic May 29, 2025 11:14
@dtcxzyw dtcxzyw marked this pull request as ready for review May 29, 2025 11:14
@llvmbot
Copy link
Member

llvmbot commented May 29, 2025

@llvm/pr-subscribers-llvm-ir

Author: Yingwei Zheng (dtcxzyw)

Changes

This patch fixes the "dereferencing null" UB. Unfortunately, C++ doesn't provide an inverse operation for p->*pmf.
See also #130952.


Full diff: https://github.com/llvm/llvm-project/pull/139096.diff

4 Files Affected:

  • (modified) llvm/include/llvm/IR/BasicBlock.h (+4)
  • (modified) llvm/include/llvm/IR/Function.h (+4)
  • (modified) llvm/include/llvm/IR/Module.h (+12)
  • (modified) llvm/include/llvm/IR/SymbolTableListTraits.h (+2-4)
diff --git a/llvm/include/llvm/IR/BasicBlock.h b/llvm/include/llvm/IR/BasicBlock.h
index 9ee0bacb5c258..10617db09fde6 100644
--- a/llvm/include/llvm/IR/BasicBlock.h
+++ b/llvm/include/llvm/IR/BasicBlock.h
@@ -546,6 +546,10 @@ class BasicBlock final : public Value, // Basic blocks are data objects also
     return &BasicBlock::InstList;
   }
 
+  static size_t getSublistOffset(Instruction *) {
+    return offsetof(BasicBlock, InstList);
+  }
+
   /// Dedicated function for splicing debug-info: when we have an empty
   /// splice (i.e. zero instructions), the caller may still intend any
   /// debug-info in between the two "positions" to be spliced.
diff --git a/llvm/include/llvm/IR/Function.h b/llvm/include/llvm/IR/Function.h
index 6d4a53da7ff22..63100568d07e4 100644
--- a/llvm/include/llvm/IR/Function.h
+++ b/llvm/include/llvm/IR/Function.h
@@ -811,6 +811,10 @@ class LLVM_ABI Function : public GlobalObject, public ilist_node<Function> {
     return &Function::BasicBlocks;
   }
 
+  static size_t getSublistOffset(BasicBlock *) {
+    return offsetof(Function, BasicBlocks);
+  }
+
 public:
   const BasicBlock       &getEntryBlock() const   { return front(); }
         BasicBlock       &getEntryBlock()         { return front(); }
diff --git a/llvm/include/llvm/IR/Module.h b/llvm/include/llvm/IR/Module.h
index 53d1005333ee1..298ccab3bfae1 100644
--- a/llvm/include/llvm/IR/Module.h
+++ b/llvm/include/llvm/IR/Module.h
@@ -609,6 +609,9 @@ class LLVM_ABI Module {
   static GlobalListType Module::*getSublistAccess(GlobalVariable*) {
     return &Module::GlobalList;
   }
+  static size_t getSublistOffset(GlobalVariable *) {
+    return offsetof(Module, GlobalList);
+  }
   friend class llvm::SymbolTableListTraits<llvm::GlobalVariable>;
 
 public:
@@ -619,6 +622,9 @@ class LLVM_ABI Module {
   static FunctionListType Module::*getSublistAccess(Function*) {
     return &Module::FunctionList;
   }
+  static size_t getSublistOffset(Function *) {
+    return offsetof(Module, FunctionList);
+  }
 
   /// Detach \p Alias from the list but don't delete it.
   void removeAlias(GlobalAlias *Alias) { AliasList.remove(Alias); }
@@ -658,6 +664,9 @@ class LLVM_ABI Module {
   static AliasListType Module::*getSublistAccess(GlobalAlias*) {
     return &Module::AliasList;
   }
+  static size_t getSublistOffset(GlobalAlias *) {
+    return offsetof(Module, AliasList);
+  }
   friend class llvm::SymbolTableListTraits<llvm::GlobalAlias>;
 
   /// Get the Module's list of ifuncs (constant).
@@ -668,6 +677,9 @@ class LLVM_ABI Module {
   static IFuncListType Module::*getSublistAccess(GlobalIFunc*) {
     return &Module::IFuncList;
   }
+  static size_t getSublistOffset(GlobalIFunc *) {
+    return offsetof(Module, IFuncList);
+  }
   friend class llvm::SymbolTableListTraits<llvm::GlobalIFunc>;
 
   /// Get the Module's list of named metadata (constant).
diff --git a/llvm/include/llvm/IR/SymbolTableListTraits.h b/llvm/include/llvm/IR/SymbolTableListTraits.h
index fcf6f0fb15280..456833fff62ce 100644
--- a/llvm/include/llvm/IR/SymbolTableListTraits.h
+++ b/llvm/include/llvm/IR/SymbolTableListTraits.h
@@ -77,10 +77,8 @@ class SymbolTableListTraits : public ilist_alloc_traits<ValueSubClass> {
   /// getListOwner - Return the object that owns this list.  If this is a list
   /// of instructions, it returns the BasicBlock that owns them.
   ItemParentClass *getListOwner() {
-    size_t Offset = reinterpret_cast<size_t>(
-        &((ItemParentClass *)nullptr->*ItemParentClass::getSublistAccess(
-                                           static_cast<ValueSubClass *>(
-                                               nullptr))));
+    size_t Offset = ItemParentClass::getSublistOffset(
+        static_cast<ValueSubClass *>(nullptr));
     ListTy *Anchor = static_cast<ListTy *>(this);
     return reinterpret_cast<ItemParentClass*>(reinterpret_cast<char*>(Anchor)-
                                               Offset);

Copy link
Collaborator

@efriedma-quic efriedma-quic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

static_cast<ValueSubClass *>(
nullptr))));
size_t Offset = ItemParentClass::getSublistOffset(
static_cast<ValueSubClass *>(nullptr));
ListTy *Anchor = static_cast<ListTy *>(this);
return reinterpret_cast<ItemParentClass*>(reinterpret_cast<char*>(Anchor)-
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure C++ semantics actually allow this arithmetic, strictly speaking; you might need to go though uintptr_t. But I don't want to try to address that in this patch.

@dtcxzyw dtcxzyw merged commit 1e81e80 into llvm:main May 30, 2025
14 checks passed
@dtcxzyw dtcxzyw deleted the perf/safe_container_of branch May 30, 2025 06:11
@Michael137
Copy link
Member

FYI, getting a bunch of these warnings when building LLVM:

/Users/jonas/Git/llvm-worktrees/llvm-project/llvm/include/llvm/IR/Module.h:667:12: warning: offset of on non-standard-layout type 'Module' [-Winvalid-offsetof]
  667 |     return offsetof(Module, AliasList);
      |            ^                ~~~~~~~~~
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/17/include/__stddef_offsetof.h:16:24: note: expanded from macro 'offsetof'
   16 | #define offsetof(t, d) __builtin_offsetof(t, d)
      |                        ^                     ~
In file included from /Users/jonas/Git/llvm-worktrees/llvm-project/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp:13:
In file included from /Users/jonas/Git/llvm-worktrees/llvm-project/clang/lib/CodeGen/CodeGenFunction.h:19:
In file included from /Users/jonas/Git/llvm-worktrees/llvm-project/clang/lib/CodeGen/CodeGenModule.h:18:
In file included from /Users/jonas/Git/llvm-worktrees/llvm-project/clang/lib/CodeGen/CodeGenTypes.h:20:
/Users/jonas/Git/llvm-worktrees/llvm-project/llvm/include/llvm/IR/Module.h:680:12: warning: offset of on non-standard-layout type 'Module' [-Winvalid-offsetof]
  680 |     return offsetof(Module, IFuncList);
      |            ^                ~~~~~~~~~
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/17/include/__stddef_offsetof.h:16:24: note: expanded from macro 'offsetof'
   16 | #define offsetof(t, d) __builtin_offsetof(t, d)
      |                        ^                     ~
6 warnings generated.
[1724/2358] Building CXX object lib/Target/AA...VMAArch64Utils.dir/AArch64SMEAttributes.cpp.o
In file included from /Users/jonas/Git/llvm-worktrees/llvm-project/llvm/lib/Target/AArch64/Utils/AArch64SMEAttributes.cpp:9:
In file included from /Users/jonas/Git/llvm-worktrees/llvm-project/llvm/lib/Target/AArch64/Utils/AArch64SMEAttributes.h:12:
In file included from /Users/jonas/Git/llvm-worktrees/llvm-project/llvm/include/llvm/IR/Function.h:27:
/Users/jonas/Git/llvm-worktrees/llvm-project/llvm/include/llvm/IR/BasicBlock.h:550:12: warning: offset of on non-standard-layout type 'BasicBlock' [-Winvalid-offsetof]
  550 |     return offsetof(BasicBlock, InstList);
      |            ^                    ~~~~~~~~
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/17/include/__stddef_offsetof.h:16:24: note: expanded from macro 'offsetof'
   16 | #define offsetof(t, d) __builtin_offsetof(t, d)
      |                        ^                     ~
In file included from /Users/jonas/Git/llvm-worktrees/llvm-project/llvm/lib/Target/AArch64/Utils/AArch64SMEAttributes.cpp:9:
In file included from /Users/jonas/Git/llvm-worktrees/llvm-project/llvm/lib/Target/AArch64/Utils/AArch64SMEAttributes.h:12:
/Users/jonas/Git/llvm-worktrees/llvm-project/llvm/include/llvm/IR/Function.h:815:12: warning: offset of on non-standard-layout type 'Function' [-Winvalid-offsetof]
  815 |     return offsetof(Function, BasicBlocks);
      |            ^                  ~~~~~~~~~~~
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/17/include/__stddef_offsetof.h:16:24: note: expanded from macro 'offsetof'
   16 | #define offsetof(t, d) __builtin_offsetof(t, d)

@hahnjo
Copy link
Member

hahnjo commented May 30, 2025

Clang builds are heavily warning about this change:

llvm/include/llvm/IR/Module.h:667:12: warning: offset of on non-standard-layout type 'Module' [-Winvalid-offsetof]
  667 |     return offsetof(Module, AliasList);
      |            ^                ~~~~~~~~~

https://en.cppreference.com/w/cpp/types/offsetof.html says

If type is not a standard-layout type use of the offsetof macro is conditionally-supported.

@dtcxzyw
Copy link
Member Author

dtcxzyw commented May 30, 2025

Clang builds are heavily warning about this change:

llvm/include/llvm/IR/Module.h:667:12: warning: offset of on non-standard-layout type 'Module' [-Winvalid-offsetof]
  667 |     return offsetof(Module, AliasList);
      |            ^                ~~~~~~~~~

https://en.cppreference.com/w/cpp/types/offsetof.html says

If type is not a standard-layout type use of the offsetof macro is conditionally-supported.

I noticed this issue when drafting this patch. But we don't have a better solution :(

@hahnjo
Copy link
Member

hahnjo commented May 30, 2025

Ok, but spamming compilation warnings for almost every TU isn't a solution either. If it's not easy to fix, I would propose to revert both PRs for the time being.

dtcxzyw added a commit that referenced this pull request May 30, 2025
dtcxzyw added a commit that referenced this pull request May 30, 2025
Reverts #139096 due to invalid uses of `offsetof` on
non-standard-layout types.
@kazutakahirata
Copy link
Contributor

@dtcxzyw I am no expert in what you are trying to do here, but I wonder if disabling specific warnings with #pragma clang diagnostic push/ignored/pop is worth considering.

llvm-sync bot pushed a commit to arm/arm-toolchain that referenced this pull request May 30, 2025
Reverts llvm/llvm-project#139096 due to invalid uses of `offsetof` on
non-standard-layout types.
@llvm-ci
Copy link
Collaborator

llvm-ci commented May 30, 2025

LLVM Buildbot has detected a new failure on builder ppc64le-flang-rhel-clang running on ppc64le-flang-rhel-test while building llvm at step 5 "build-unified-tree".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/157/builds/29466

Here is the relevant piece of the build log for the reference
Step 5 (build-unified-tree) failure: build (failure)
...
67.978 [339/289/6214] Linking CXX executable bin/clang-scan-deps
67.993 [339/288/6215] Linking CXX executable bin/clang-diff
68.029 [339/287/6216] Linking CXX executable bin/clang-refactor
68.033 [339/286/6217] Linking CXX executable bin/clang-extdef-mapping
68.074 [339/285/6218] Linking CXX shared module lib/CheckerOptionHandlingAnalyzerPlugin.so
68.108 [339/284/6219] Linking CXX shared module lib/CheckerDependencyHandlingAnalyzerPlugin.so
68.192 [339/283/6220] Linking CXX shared module lib/SampleAnalyzerPlugin.so
68.265 [339/282/6221] Linking CXX shared library lib/libclang.so.21.0.0git
68.272 [338/282/6222] Creating library symlink lib/libclang.so.21.0git lib/libclang.so
68.369 [337/282/6223] Building CXX object tools/flang/lib/Optimizer/CodeGen/CMakeFiles/FIRCodeGen.dir/TargetRewrite.cpp.o
FAILED: tools/flang/lib/Optimizer/CodeGen/CMakeFiles/FIRCodeGen.dir/TargetRewrite.cpp.o 
ccache /home/buildbots/llvm-external-buildbots/clang.19.1.7/bin/clang++ -DFLANG_INCLUDE_TESTS=1 -DGTEST_HAS_RTTI=0 -D_DEBUG -D_GLIBCXX_ASSERTIONS -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -I/home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/build/tools/flang/lib/Optimizer/CodeGen -I/home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/llvm-project/flang/lib/Optimizer/CodeGen -I/home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/llvm-project/flang/include -I/home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/build/tools/flang/include -I/home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/build/include -I/home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/llvm-project/llvm/include -isystem /home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/llvm-project/flang/../mlir/include -isystem /home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/build/tools/mlir/include -isystem /home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/build/tools/clang/include -isystem /home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/llvm-project/llvm/../clang/include -fPIC -fno-semantic-interposition -fvisibility-inlines-hidden -Werror=date-time -Werror=unguarded-availability-new -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -pedantic -Wno-long-long -Wc++98-compat-extra-semi -Wimplicit-fallthrough -Wcovered-switch-default -Wno-noexcept-type -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -Wsuggest-override -Wstring-conversion -Wmisleading-indentation -Wctad-maybe-unsupported -fdiagnostics-color -ffunction-sections -fdata-sections -Werror -Wno-deprecated-copy -Wno-string-conversion -Wno-ctad-maybe-unsupported -Wno-unused-command-line-argument -Wstring-conversion           -Wcovered-switch-default -Wno-nested-anon-types -Xclang -fno-pch-timestamp -O3 -DNDEBUG -std=c++17  -fno-exceptions -funwind-tables -fno-rtti -UNDEBUG -MD -MT tools/flang/lib/Optimizer/CodeGen/CMakeFiles/FIRCodeGen.dir/TargetRewrite.cpp.o -MF tools/flang/lib/Optimizer/CodeGen/CMakeFiles/FIRCodeGen.dir/TargetRewrite.cpp.o.d -o tools/flang/lib/Optimizer/CodeGen/CMakeFiles/FIRCodeGen.dir/TargetRewrite.cpp.o -c /home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/llvm-project/flang/lib/Optimizer/CodeGen/TargetRewrite.cpp
In file included from /home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/llvm-project/flang/lib/Optimizer/CodeGen/TargetRewrite.cpp:17:
In file included from /home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/llvm-project/flang/include/flang/Optimizer/CodeGen/CodeGen.h:15:
In file included from /home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/llvm-project/llvm/include/llvm/IR/Module.h:25:
In file included from /home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/llvm-project/llvm/include/llvm/IR/Function.h:27:
/home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/llvm-project/llvm/include/llvm/IR/BasicBlock.h:550:12: error: offset of on non-standard-layout type 'BasicBlock' [-Werror,-Winvalid-offsetof]
  550 |     return offsetof(BasicBlock, InstList);
      |            ^                    ~~~~~~~~
/home/buildbots/llvm-external-buildbots/clang.19.1.7/lib/clang/19/include/__stddef_offsetof.h:16:24: note: expanded from macro 'offsetof'
   16 | #define offsetof(t, d) __builtin_offsetof(t, d)
      |                        ^                     ~
In file included from /home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/llvm-project/flang/lib/Optimizer/CodeGen/TargetRewrite.cpp:17:
In file included from /home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/llvm-project/flang/include/flang/Optimizer/CodeGen/CodeGen.h:15:
In file included from /home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/llvm-project/llvm/include/llvm/IR/Module.h:25:
/home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/llvm-project/llvm/include/llvm/IR/Function.h:815:12: error: offset of on non-standard-layout type 'Function' [-Werror,-Winvalid-offsetof]
  815 |     return offsetof(Function, BasicBlocks);
      |            ^                  ~~~~~~~~~~~
/home/buildbots/llvm-external-buildbots/clang.19.1.7/lib/clang/19/include/__stddef_offsetof.h:16:24: note: expanded from macro 'offsetof'
   16 | #define offsetof(t, d) __builtin_offsetof(t, d)
      |                        ^                     ~
In file included from /home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/llvm-project/flang/lib/Optimizer/CodeGen/TargetRewrite.cpp:17:
In file included from /home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/llvm-project/flang/include/flang/Optimizer/CodeGen/CodeGen.h:15:
/home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/llvm-project/llvm/include/llvm/IR/Module.h:612:12: error: offset of on non-standard-layout type 'Module' [-Werror,-Winvalid-offsetof]
  612 |     return offsetof(Module, GlobalList);
      |            ^                ~~~~~~~~~~
/home/buildbots/llvm-external-buildbots/clang.19.1.7/lib/clang/19/include/__stddef_offsetof.h:16:24: note: expanded from macro 'offsetof'
   16 | #define offsetof(t, d) __builtin_offsetof(t, d)
      |                        ^                     ~
In file included from /home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/llvm-project/flang/lib/Optimizer/CodeGen/TargetRewrite.cpp:17:
In file included from /home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/llvm-project/flang/include/flang/Optimizer/CodeGen/CodeGen.h:15:
/home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/llvm-project/llvm/include/llvm/IR/Module.h:625:12: error: offset of on non-standard-layout type 'Module' [-Werror,-Winvalid-offsetof]
  625 |     return offsetof(Module, FunctionList);
      |            ^                ~~~~~~~~~~~~
/home/buildbots/llvm-external-buildbots/clang.19.1.7/lib/clang/19/include/__stddef_offsetof.h:16:24: note: expanded from macro 'offsetof'
   16 | #define offsetof(t, d) __builtin_offsetof(t, d)
      |                        ^                     ~
In file included from /home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/llvm-project/flang/lib/Optimizer/CodeGen/TargetRewrite.cpp:17:
In file included from /home/buildbots/llvm-external-buildbots/workers/ppc64le-flang-rhel-test/ppc64le-flang-rhel-clang-build/llvm-project/flang/include/flang/Optimizer/CodeGen/CodeGen.h:15:

sivan-shani pushed a commit to sivan-shani/llvm-project that referenced this pull request Jun 3, 2025
This patch fixes the "dereferencing null" UB. Unfortunately, C++ doesn't
provide an inverse operation for `p->*pmf`.
See also llvm#130952.
sivan-shani pushed a commit to sivan-shani/llvm-project that referenced this pull request Jun 3, 2025
Reverts llvm#139096 due to invalid uses of `offsetof` on
non-standard-layout types.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants