-
Notifications
You must be signed in to change notification settings - Fork 379
Fix SLANG_ENABLE_ASAN CMake option
#8980
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
Changes from all commits
8922141
4dae658
7e8a478
53b5d33
ffd7a0e
9fe3e02
506d457
817f6db
0a30070
3d46bc2
d688ef3
bc306b7
6261017
fa1982c
39971df
b4a3193
5464944
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -159,11 +159,28 @@ function(set_default_compile_options target) | |
| add_supported_cxx_linker_flags( | ||
| ${target} | ||
| PRIVATE | ||
| # Don't assume that symbols will be resolved at runtime | ||
| "-Wl,--no-undefined" | ||
| # No reason not to do this? Useful when using split debug info | ||
| "-Wl,--build-id" | ||
| ) | ||
| # Workaround for slang-llvm's own classes needing RTTI for UBSan's type checks but LLVM not | ||
| # supporting RTTI, meaning slang-llvm built with RTTI will fail to link due to undefined | ||
| # LLVM typeinfo symbols | ||
| if(${target} STREQUAL slang-llvm) | ||
| if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") | ||
| add_supported_cxx_linker_flags( | ||
| ${target} | ||
| PRIVATE | ||
| "-Wl,-undefined,suppress" | ||
| ) | ||
| endif() | ||
| else() | ||
|
Comment on lines
+168
to
+176
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am not sure where the WAR is supposed to be applied to. Shouldn't the logic more be like, |
||
| add_supported_cxx_linker_flags( | ||
| ${target} | ||
| PRIVATE | ||
| # Don't assume that symbols will be resolved at runtime | ||
| "-Wl,--no-undefined" | ||
| ) | ||
| endif() | ||
| endif() | ||
|
|
||
| set_target_properties( | ||
|
|
@@ -214,19 +231,30 @@ function(set_default_compile_options target) | |
| ) | ||
|
|
||
| if(SLANG_ENABLE_ASAN) | ||
| add_supported_cxx_flags( | ||
| ${target} | ||
| PRIVATE | ||
| /fsanitize=address | ||
| -fsanitize=address | ||
| ) | ||
| add_supported_cxx_linker_flags( | ||
| ${target} | ||
| BEFORE | ||
| PUBLIC | ||
| /INCREMENTAL:NO | ||
| -fsanitize=address | ||
| ) | ||
| if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") | ||
| # Clang defaults to statically linking the sanitizer runtime (except on macOS/Darwin), | ||
| # which is not compatible with -Wl,--no-undefined, so we need to use dynamic linking | ||
| # instead (-shared-libsan). | ||
| target_compile_options( | ||
| ${target} | ||
| PRIVATE -fsanitize=address,undefined -shared-libsan | ||
| ) | ||
| target_link_options( | ||
| ${target} | ||
| PUBLIC -fsanitize=address,undefined -shared-libsan | ||
| ) | ||
|
Comment on lines
+234
to
+245
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I forgot to mention, the downside of |
||
| elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") | ||
| target_compile_options( | ||
| ${target} | ||
| PRIVATE -fsanitize=address,undefined | ||
| ) | ||
| target_link_options(${target} PUBLIC -fsanitize=address,undefined) | ||
| elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") | ||
| target_compile_options(${target} PRIVATE /fsanitize=address) | ||
| target_link_options(${target} PRIVATE /INCREMENTAL:NO) | ||
| else() | ||
| message(WARNING "Not enabling sanitizers: unsupported C++ compiler") | ||
| endif() | ||
| endif() | ||
|
|
||
| if(SLANG_ENABLE_COVERAGE) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -69,16 +69,30 @@ SlangResult CommandLineDownstreamCompiler::compile( | |
| if (!isVersionCompatible(inOptions)) | ||
| { | ||
| // Not possible to compile with this version of the interface. | ||
| // TODO: Fix other `IDownstreamCompiler::compile` implementations not always writing to | ||
| // `outArtifact` when returning early. | ||
| const auto targetDesc = ArtifactDescUtil::makeDescForCompileTarget(SLANG_TARGET_UNKNOWN); | ||
| auto artifact = ArtifactUtil::createArtifact(targetDesc); | ||
| *outArtifact = artifact.detach(); | ||
| return SLANG_E_NOT_IMPLEMENTED; | ||
| } | ||
|
|
||
| CompileOptions options = getCompatibleVersion(&inOptions); | ||
| const auto targetDesc = ArtifactDescUtil::makeDescForCompileTarget(options.targetType); | ||
|
|
||
| // Copy the command line options | ||
| CommandLine cmdLine(m_cmdLine); | ||
| // Create the result artifact | ||
| auto resultArtifact = ArtifactUtil::createArtifact(targetDesc); | ||
|
|
||
| // Work out the ArtifactDesc | ||
| const auto targetDesc = ArtifactDescUtil::makeDescForCompileTarget(options.targetType); | ||
| // Create the diagnostics | ||
| auto diagnostics = ArtifactDiagnostics::create(); | ||
| ArtifactUtil::addAssociated(resultArtifact, diagnostics); | ||
|
|
||
| // If Slang was built with Clang or GCC and sanitizers were enabled, the same `-fsanitize=...` | ||
| // flag must be passed when linking an executable or shared library with a Slang library, or | ||
| // linking will fail. We can't instrument C++ generated from Slang code with sanitizers as they | ||
| // might report errors that we can't fix, so we separate compilation and linking into two | ||
| // commands to enable sanitizers only during linking. | ||
| bool shouldSeparateCompileAndLink = options.targetType != SLANG_OBJECT_CODE; | ||
|
|
||
| auto helper = DefaultArtifactHelper::getSingleton(); | ||
|
|
||
|
|
@@ -95,8 +109,13 @@ SlangResult CommandLineDownstreamCompiler::compile( | |
| { | ||
| // We could use the path to the source, or use the source name/paths as defined on the | ||
| // artifact For now we just go with a lock file based on "slang-generated". | ||
| SLANG_RETURN_ON_FAIL( | ||
| helper->createLockFile(asCharSlice(toSlice("slang-generated")), lockFile.writeRef())); | ||
| if (SLANG_FAILED(helper->createLockFile( | ||
| asCharSlice(toSlice("slang-generated")), | ||
| lockFile.writeRef()))) | ||
| { | ||
| *outArtifact = resultArtifact.detach(); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't know this part of slangc very well (yet), but I'd just like to double-check that this is intentional. Usually, a failure should rollback whatever changes was done by the function. In this case, it feels a bit odd that we're returning a failure but still also returning the artifact. See also https://en.wikipedia.org/wiki/Exception_safety Addendum. I see from above that apparently this is the intention. But I do wonder if the call site shouldn't try to use the artifact in case this function failed, unless it's for some sort of diagnostics (= error output). I this case, I would appreciate a code comment. |
||
| return SLANG_FAIL; | ||
| } | ||
|
|
||
| auto lockArtifact = Artifact::create( | ||
| ArtifactDesc::make(ArtifactKind::Base, ArtifactPayload::Lock, ArtifactStyle::None)); | ||
|
|
@@ -110,17 +129,81 @@ SlangResult CommandLineDownstreamCompiler::compile( | |
| options.modulePath = SliceUtil::asTerminatedCharSlice(modulePath); | ||
| } | ||
|
|
||
| // Compile stage: compile source to object code | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do we need this newly added code just as an ASAN fix? (I presume we do. The PR description would be the place to explain why. Not at all obvious.) |
||
| ComPtr<IArtifact> objectArtifact; | ||
|
|
||
| if (shouldSeparateCompileAndLink) | ||
| { | ||
| CompileOptions compileOptions = options; | ||
| compileOptions.targetType = SLANG_OBJECT_CODE; | ||
|
|
||
| CommandLine compileCmdLine(m_cmdLine); | ||
| if (SLANG_FAILED(calcArgs(compileOptions, compileCmdLine))) | ||
| { | ||
| *outArtifact = resultArtifact.detach(); | ||
| return SLANG_FAIL; | ||
| } | ||
|
|
||
| List<ComPtr<IArtifact>> compileArtifacts; | ||
| if (SLANG_FAILED(calcCompileProducts( | ||
| compileOptions, | ||
| DownstreamProductFlag::All, | ||
| lockFile, | ||
| compileArtifacts))) | ||
| { | ||
| *outArtifact = resultArtifact.detach(); | ||
| return SLANG_FAIL; | ||
| } | ||
|
|
||
| // There should only be one object file (.o/.obj) as artifact | ||
| SLANG_ASSERT(compileArtifacts.getCount() == 1); | ||
| SLANG_ASSERT(compileArtifacts[0]->getDesc().kind == ArtifactKind::ObjectCode); | ||
| objectArtifact = compileArtifacts[0]; | ||
|
|
||
| ExecuteResult compileResult; | ||
| if (SLANG_FAILED(ProcessUtil::execute(compileCmdLine, compileResult)) || | ||
| SLANG_FAILED(parseOutput(compileResult, diagnostics))) | ||
| { | ||
| *outArtifact = resultArtifact.detach(); | ||
| return SLANG_FAIL; | ||
| } | ||
|
|
||
| // If compilation failed, return the diagnostics | ||
| if (compileResult.resultCode != 0 || !objectArtifact->exists()) | ||
| { | ||
| *outArtifact = resultArtifact.detach(); | ||
| return SLANG_FAIL; | ||
| } | ||
| } | ||
|
|
||
| // Link stage (or single-stage compile for object code targets) | ||
| CommandLine cmdLine(m_cmdLine); | ||
|
|
||
| if (shouldSeparateCompileAndLink) | ||
| { | ||
| // Pass compiled object to linker | ||
| options.sourceArtifacts = makeSlice(objectArtifact.readRef(), 1); | ||
| } | ||
|
|
||
| // Append command line args to the end of cmdLine using the target specific function for the | ||
| // specified options | ||
| SLANG_RETURN_ON_FAIL(calcArgs(options, cmdLine)); | ||
| if (SLANG_FAILED(calcArgs(options, cmdLine))) | ||
| { | ||
| *outArtifact = resultArtifact.detach(); | ||
| return SLANG_FAIL; | ||
| } | ||
|
|
||
| // The 'productArtifact' is the main product produced from the compilation - the | ||
| // executable/sharedlibrary/object etc | ||
| ComPtr<IArtifact> productArtifact; | ||
| { | ||
| List<ComPtr<IArtifact>> artifacts; | ||
| SLANG_RETURN_ON_FAIL( | ||
| calcCompileProducts(options, DownstreamProductFlag::All, lockFile, artifacts)); | ||
| if (SLANG_FAILED( | ||
| calcCompileProducts(options, DownstreamProductFlag::All, lockFile, artifacts))) | ||
| { | ||
| *outArtifact = resultArtifact.detach(); | ||
| return SLANG_FAIL; | ||
| } | ||
|
|
||
| for (IArtifact* artifact : artifacts) | ||
| { | ||
|
|
@@ -139,6 +222,7 @@ SlangResult CommandLineDownstreamCompiler::compile( | |
| // Somethings gone wrong if we don't find the main artifact | ||
| if (!productArtifact) | ||
| { | ||
| *outArtifact = resultArtifact.detach(); | ||
| return SLANG_FAIL; | ||
| } | ||
|
|
||
|
|
@@ -152,7 +236,13 @@ SlangResult CommandLineDownstreamCompiler::compile( | |
| } | ||
| #endif | ||
|
|
||
| SLANG_RETURN_ON_FAIL(ProcessUtil::execute(cmdLine, exeRes)); | ||
| if (SLANG_FAILED(ProcessUtil::execute(cmdLine, exeRes)) || | ||
| SLANG_FAILED(parseOutput(exeRes, diagnostics))) | ||
| { | ||
| // If the process failed or the output parsing failed, return the diagnostics | ||
| *outArtifact = resultArtifact.detach(); | ||
| return SLANG_FAIL; | ||
| } | ||
|
|
||
| #if 0 | ||
| { | ||
|
|
@@ -209,23 +299,13 @@ SlangResult CommandLineDownstreamCompiler::compile( | |
| } | ||
| } | ||
|
|
||
| // Create the result artifact | ||
| auto artifact = ArtifactUtil::createArtifact(targetDesc); | ||
|
|
||
| // Createa the diagnostics | ||
| auto diagnostics = ArtifactDiagnostics::create(); | ||
|
|
||
| SLANG_RETURN_ON_FAIL(parseOutput(exeRes, diagnostics)); | ||
|
|
||
| ArtifactUtil::addAssociated(artifact, diagnostics); | ||
|
|
||
| // Find the rep from the 'main' artifact, we'll just use the same representation on the output | ||
| // artifact. Sharing is desirable, because the rep owns the file. | ||
| if (auto fileRep = productArtifact | ||
| ? findRepresentation<IOSFileArtifactRepresentation>(productArtifact) | ||
| : nullptr) | ||
| { | ||
| artifact->addRepresentation(fileRep); | ||
| resultArtifact->addRepresentation(fileRep); | ||
| } | ||
|
|
||
| // Add the artifact list if there is anything in it | ||
|
|
@@ -242,10 +322,10 @@ SlangResult CommandLineDownstreamCompiler::compile( | |
|
|
||
| artifactContainer->setChildren(slice.data, slice.count); | ||
|
|
||
| artifact->addAssociated(artifactContainer); | ||
| resultArtifact->addAssociated(artifactContainer); | ||
| } | ||
|
|
||
| *outArtifact = artifact.detach(); | ||
| *outArtifact = resultArtifact.detach(); | ||
| return SLANG_OK; | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -375,8 +375,7 @@ static SlangResult _parseGCCFamilyLine( | |
|
|
||
| SliceAllocator allocator; | ||
|
|
||
| diagnostics->reset(); | ||
| diagnostics->setRaw(SliceUtil::asCharSlice(exeRes.standardError)); | ||
| diagnostics->appendRaw(SliceUtil::asCharSlice(exeRes.standardError)); | ||
|
|
||
| // We hold in workDiagnostics so as it is more convenient to append to the last with a | ||
| // continuation also means we don't hold the allocations of building up continuations, just the | ||
|
|
@@ -620,12 +619,34 @@ static SlangResult _parseGCCFamilyLine( | |
| { | ||
| // Don't link, just produce object file | ||
| cmdLine.addArg("-c"); | ||
|
|
||
| if (PlatformUtil::isFamily(PlatformFamily::Unix, platformKind)) | ||
| { | ||
| // Position independent | ||
| cmdLine.addArg("-fPIC"); | ||
| } | ||
|
Comment on lines
+623
to
+627
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am not sure why this is needed.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's needed to fix this kind of link error: Objects linked into shared libraries must be compiled with Note that with this change, position-independent code will be enabled for all objects (there's no way to tell just from
Right. |
||
| break; | ||
| } | ||
| default: | ||
| break; | ||
| } | ||
|
|
||
| #if defined(__has_feature) | ||
| #if __has_feature(address_sanitizer) | ||
| if (options.targetType != SLANG_OBJECT_CODE) | ||
| { | ||
| #if SLANG_CLANG || SLANG_GCC | ||
| // Assume ASan was enabled through the SLANG_ENABLE_ASAN CMake option, meaning UBSan was | ||
| // enabled as well. | ||
| cmdLine.addArg("-fsanitize=address,undefined"); | ||
| #endif | ||
|
Comment on lines
+634
to
+642
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure if we should really assume that ASan being enabled + the compiler being either Clang or GCC means that UBSan is also enabled. |
||
| #if SLANG_CLANG | ||
| cmdLine.addArg("-shared-libsan"); | ||
| #endif | ||
| } | ||
| #endif | ||
| #endif | ||
|
|
||
| // Add defines | ||
| for (const auto& define : options.defines) | ||
| { | ||
|
|
@@ -678,14 +699,18 @@ static SlangResult _parseGCCFamilyLine( | |
| cmdLine.addArg(fileRep->getPath()); | ||
| } | ||
|
|
||
| // Add the library paths | ||
|
|
||
| if (options.libraryPaths.count && (options.targetType == SLANG_HOST_EXECUTABLE)) | ||
| // Add linker-specific options only when not compiling to object code | ||
| if (options.targetType != SLANG_OBJECT_CODE) | ||
| { | ||
| if (PlatformUtil::isFamily(PlatformFamily::Apple, platformKind)) | ||
| cmdLine.addArg("-Wl,-rpath,@loader_path,-rpath,@loader_path/../lib"); | ||
| else | ||
| cmdLine.addArg("-Wl,-rpath,$ORIGIN,-rpath,$ORIGIN/../lib"); | ||
| // Add the library paths | ||
|
|
||
| if (options.libraryPaths.count && (options.targetType == SLANG_HOST_EXECUTABLE)) | ||
| { | ||
| if (PlatformUtil::isFamily(PlatformFamily::Apple, platformKind)) | ||
| cmdLine.addArg("-Wl,-rpath,@loader_path,-rpath,@loader_path/../lib"); | ||
| else | ||
| cmdLine.addArg("-Wl,-rpath,$ORIGIN,-rpath,$ORIGIN/../lib"); | ||
| } | ||
| } | ||
|
|
||
| StringSlicePool libPathPool(StringSlicePool::Style::Default); | ||
|
|
@@ -711,13 +736,17 @@ static SlangResult _parseGCCFamilyLine( | |
| const UnownedStringSlice path(fileRep->getPath()); | ||
| libPathPool.add(Path::getParentDirectory(path)); | ||
|
|
||
| cmdLine.addPrefixPathArg( | ||
| "-l", | ||
| ArtifactDescUtil::getBaseNameFromPath(artifact->getDesc(), path)); | ||
| if (options.targetType != SLANG_OBJECT_CODE) | ||
| { | ||
| cmdLine.addPrefixPathArg( | ||
| "-l", | ||
| ArtifactDescUtil::getBaseNameFromPath(artifact->getDesc(), path)); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| if (options.sourceLanguage == SLANG_SOURCE_LANGUAGE_CPP && | ||
| options.targetType != SLANG_OBJECT_CODE && | ||
| !PlatformUtil::isFamily(PlatformFamily::Windows, platformKind)) | ||
| { | ||
| // Make STD libs available | ||
|
|
@@ -728,9 +757,12 @@ static SlangResult _parseGCCFamilyLine( | |
|
|
||
| for (const auto& libPath : libPathPool.getAdded()) | ||
| { | ||
| // Note that any escaping of the path is handled in the ProcessUtil:: | ||
| cmdLine.addArg("-L"); | ||
| cmdLine.addArg(libPath); | ||
| if (options.targetType != SLANG_OBJECT_CODE) | ||
| { | ||
| // Note that any escaping of the path is handled in the ProcessUtil:: | ||
| cmdLine.addArg("-L"); | ||
| cmdLine.addArg(libPath); | ||
| } | ||
| cmdLine.addArg("-F"); | ||
| cmdLine.addArg(libPath); | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changes such as this should be commented in the PR description. It is not obvious to the reviewer why you removed this flag. Presumably there was a good reason.