Skip to content

[clang][ASTImporter] fix assert fail due to offset overflow #79084

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

Closed
wants to merge 1 commit into from

Conversation

jcsxky
Copy link
Contributor

@jcsxky jcsxky commented Jan 23, 2024

This patch tries to fix assert failed due to offset overflow in SourceManager. UIntTy in SourceLocation is unsigned int and has 2G limit(highest bit represent whether it is macro). When importing a huge file or importing to many files, NextLocalOffset in SourceManager will overflow and createFileID returns a invalid FileID. This will lead to assert failed and crash.

@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Jan 23, 2024
@jcsxky
Copy link
Contributor Author

jcsxky commented Jan 23, 2024

We encounter this problem in OpenBCM. But, it's not convenient and proper to create such a huge file to test.

@llvmbot
Copy link
Member

llvmbot commented Jan 23, 2024

@llvm/pr-subscribers-clang

Author: Qizhi Hu (jcsxky)

Changes

This patch tries to fix assert failed due to offset overflow in SourceManager. UIntTy in SourceLocation is unsigned int and has 2G limit(low bit represent whether it is macro). When importing a huge file or importing to many files, NextLocalOffset in SourceManager will overflow and createFileID returns a invalid FileID. This will lead to assert failed and crash.


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

1 Files Affected:

  • (modified) clang/lib/AST/ASTImporter.cpp (+15-1)
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index 12734d62ed9fb76..ae9c9e8d04fc98a 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -9837,6 +9837,13 @@ Expected<SourceRange> ASTImporter::Import(SourceRange FromRange) {
   return SourceRange(ToBegin, ToEnd);
 }
 
+static bool isBufferSizeOverflow(SourceManager &SM, size_t BufferSize) {
+  unsigned Offset = SM.getNextLocalOffset();
+  unsigned FullSize = Offset + BufferSize + 1;
+  SourceLocation L = SourceLocation().getFromRawEncoding(FullSize);
+  return !L.isFileID() || !(FullSize > Offset && SM.isLoadedSourceLocation(L));
+}
+
 Expected<FileID> ASTImporter::Import(FileID FromID, bool IsBuiltin) {
   llvm::DenseMap<FileID, FileID>::iterator Pos = ImportedFileIDs.find(FromID);
   if (Pos != ImportedFileIDs.end())
@@ -9896,9 +9903,13 @@ Expected<FileID> ASTImporter::Import(FileID FromID, bool IsBuiltin) {
         // FIXME: The filename may be a virtual name that does probably not
         // point to a valid file and we get no Entry here. In this case try with
         // the memory buffer below.
-        if (Entry)
+        if (Entry) {
+          if (isBufferSizeOverflow(ToSM, Entry->getSize()))
+            return llvm::make_error<ASTImportError>(
+                ASTImportError::UnsupportedConstruct);
           ToID = ToSM.createFileID(*Entry, ToIncludeLocOrFakeLoc,
                                    FromSLoc.getFile().getFileCharacteristic());
+        }
       }
     }
 
@@ -9913,6 +9924,9 @@ Expected<FileID> ASTImporter::Import(FileID FromID, bool IsBuiltin) {
       std::unique_ptr<llvm::MemoryBuffer> ToBuf =
           llvm::MemoryBuffer::getMemBufferCopy(FromBuf->getBuffer(),
                                                FromBuf->getBufferIdentifier());
+      if (isBufferSizeOverflow(ToSM, ToBuf->getBufferSize()))
+        return llvm::make_error<ASTImportError>(
+            ASTImportError::UnsupportedConstruct);
       ToID = ToSM.createFileID(std::move(ToBuf),
                                FromSLoc.getFile().getFileCharacteristic());
     }

@jcsxky jcsxky requested a review from balazske January 23, 2024 02:23
@jcsxky jcsxky marked this pull request as draft January 23, 2024 03:03
@jcsxky jcsxky marked this pull request as ready for review January 23, 2024 03:04
@jcsxky jcsxky force-pushed the fix_import_crash_of_loc_overflow branch from 251b4b4 to 0b127ff Compare January 23, 2024 04:08
if (Entry) {
if (isBufferSizeOverflow(ToSM, Entry->getSize()))
return llvm::make_error<ASTImportError>(
ASTImportError::UnsupportedConstruct);
Copy link
Collaborator

Choose a reason for hiding this comment

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

It is better to use Unknown as error kind here (it is used already in this function), or add a new type of error to ASTImportError::ErrorKind.

Copy link
Member

Choose a reason for hiding this comment

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

ASTImportError::Unknown would crash CTU module too, ASTImportError::UnsupportedConstruct might be deliberately chosen so the analysis could continue in this case.

Copy link
Collaborator

Choose a reason for hiding this comment

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

This error is clearly not an unsupported AST construct. For this case a new error type should be added like ASTImportError::SourceLocationOverflow or ResourceOverflow. Code in CrossTranslationUnitContext::importDefinitionImpl should be updated to count this new error.
Alternatively the llvm_unreachable from UnknownError can be removed. But UnknownError should be used if something happens that is not supposed to happen, even if now it is used like "other error".

Copy link
Member

Choose a reason for hiding this comment

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

This error is clearly not an unsupported AST construct. For this case a new error type should be added like ASTImportError::SourceLocationOverflow or ResourceOverflow

Agreed

@@ -9896,9 +9903,13 @@ Expected<FileID> ASTImporter::Import(FileID FromID, bool IsBuiltin) {
// FIXME: The filename may be a virtual name that does probably not
// point to a valid file and we get no Entry here. In this case try with
// the memory buffer below.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Did you check that these FIXME's have no connection to the problem?

Copy link
Member

Choose a reason for hiding this comment

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

Invalid file could exist in real case (causes no Entry) while SourceLocation overflow is normally caused by cumulative effect of multiple (large enough) files imported so I think these two are not connected.

Copy link
Member

Choose a reason for hiding this comment

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

Is there a way to reproduce this? By creating some very large dummy files? Just to confirm what the crash is exactly (since I don't see an attached stacktrace)

@balazske balazske requested a review from Michael137 February 12, 2024 14:33
@jcsxky jcsxky closed this Aug 3, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants