Skip to content

Avoid illegal function pointer operation for async funcs #35220

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

Conversation

kateinoigakukun
Copy link
Member

@kateinoigakukun kateinoigakukun commented Dec 24, 2020

When compiling Concurrency module targeting wasm32, it fails with Function addresses with offsets not supported.
It's a limitation of wasm32 for security reason. In wasm32, function and data address spaces are separated, so additive operation to function address as data pointer is invalid. Therefore if it's statically known to be an additive operation to function address, LLVM fails with the above error.

<unknown>:0: note: Function addresses with offsets not supported
Please submit a bug report (https://swift.org/contributing/#reporting-bugs) and include the project and the crash backtrace.
Stack dump:
0.      Program arguments: /Users/kateinoigakukun/projects/swiftwasm-source/host-build/Ninja-Release/swift-macosx-x86_64/bin/swift-frontend -frontend -c /Users/kateinoigakukun/projects/swiftwasm-source/swift/stdlib/public/Concurrency/Actor.swift /Users/kateinoigakukun/projects/swiftwasm-source/swift/stdlib/public/Concurrency/PartialAsyncTask.swift /Users/kateinoigakukun/projects/swiftwasm-source/swift/stdlib/public/Concurrency/Task.swift /Users/kateinoigakukun/projects/swiftwasm-source/swift/stdlib/public/Concurrency/TaskCancellation.swift /Users/kateinoigakukun/projects/swiftwasm-source/swift/stdlib/public/Concurrency/_TimeTypes.swift /Users/kateinoigakukun/projects/swiftwasm-source/swift/stdlib/public/Concurrency/TaskGroup.swift -supplementary-output-file-map /var/folders/br/7sr_p7cj7v549x_gtkb33df00000gp/T/supplementaryOutputs-aa56e1 -disable-objc-attr-requires-foundation-module -target wasm32-unknown-wasi -disable-objc-interop -sdk /Users/kateinoigakukun/projects/swiftwasm-source/wasi-sdk/share/wasi-sysroot -I /Users/kateinoigakukun/projects/swiftwasm-source/target-build/swift-stdlib-wasi-wasm32/./lib/swift/wasi -warn-implicit-overrides -enable-library-evolution -module-cache-path /Users/kateinoigakukun/projects/swiftwasm-source/target-build/swift-stdlib-wasi-wasm32/./module-cache -module-link-name swift_Concurrency -parse-stdlib -resource-dir /Users/kateinoigakukun/projects/swiftwasm-source/target-build/swift-stdlib-wasi-wasm32/./lib/swift -swift-version 5 -O -D SWIFT_RUNTIME_OS_VERSIONING -assume-single-threaded -enforce-exclusivity=unchecked -enable-experimental-concurrency -disable-implicit-concurrency-module-import -Xcc -D_WASI_EMULATED_MMAN -parse-as-library -module-name _Concurrency -o /Users/kateinoigakukun/projects/swiftwasm-source/target-build/swift-stdlib-wasi-wasm32/stdlib/public/Concurrency/WASI/wasm32/_Concurrency.o -runtime-compatibility-version none -use-static-resource-dir -disable-autolinking-runtime-compatibility-dynamic-replacements
1.      SwiftWasm Swift version 5.3-dev (LLVM d8483794c7cfb2f, Swift 8e50d4d7dbda580)
2.      Running pass 'Function Pass Manager' on module '/Users/kateinoigakukun/projects/swiftwasm-source/target-build/swift-stdlib-wasi-wasm32/stdlib/public/Concurrency/WASI/wasm32/_Concurrency.o'.
3.      Running pass 'WebAssembly Assembly Printer' on function '@"$s12_Concurrency16_runAsyncHandler9operationyyyYc_tF"'
define dso_local swiftcc void @"$s12_Concurrency16_runAsyncHandler9operationyyyYc_tF"(i8* %0, %swift.refcounted* %1) #3 {
entry:
  %2 = load i32, i32* getelementptr inbounds (%swift.async_func_pointer, %swift.async_func_pointer* @"$ss5Error_pIegHzo_ytsAA_pIegHrzo_TRTu", i32 0, i32 1), align 4
  %3 = tail call noalias %swift.refcounted* @swift_allocObject(%swift.type* getelementptr inbounds (%swift.full_boxmetadata, %swift.full_boxmetadata* @metadata, i32 0, i32 2), i32 20, i32 3) #5
  %4 = getelementptr inbounds %swift.refcounted, %swift.refcounted* %3, i32 1
  %5 = bitcast %swift.refcounted* %4 to i32*
  store i32 %2, i32* %5, align 4
  %6 = getelementptr inbounds %swift.refcounted, %swift.refcounted* %3, i32 1, i32 1
  %.fn = bitcast i32* %6 to i8**
  store i8* %0, i8** %.fn, align 4
  %.data = getelementptr inbounds i32, i32* %6, i32 1
  %7 = bitcast i32* %.data to %swift.refcounted**
  store %swift.refcounted* %1, %swift.refcounted** %7, align 4
  %.not = icmp eq %swift.refcounted* %3, null
  %8 = tail call %swift.refcounted* @swift_nonatomic_retain(%swift.refcounted* returned %1) #5
  %9 = tail call %swift.refcounted* @swift_nonatomic_retain(%swift.refcounted* returned %3) #5
  br i1 %.not, label %10, label %14

10:                                               ; preds = %entry
  %11 = load i32, i32* getelementptr inbounds (%swift.async_func_pointer, %swift.async_func_pointer* bitcast (void (%swift.task*, %swift.executor*, %swift.context*)* @"$ss5Error_pIegHzo_ytsAA_pIegHrzo_TRTA" to %swift.async_func_pointer*), i32 0, i32 0), align 4
  %12 = add i32 %11, ptrtoint (void (%swift.task*, %swift.executor*, %swift.context*)* @"$ss5Error_pIegHzo_ytsAA_pIegHrzo_TRTA" to i32)
  %13 = inttoptr i32 %12 to i8*
  ; !!Here is the additive operation!!
  %.pre = load i32, i32* getelementptr inbounds (%swift.async_func_pointer, %swift.async_func_pointer* bitcast (void (%swift.task*, %swift.executor*, %swift.context*)* @"$ss5Error_pIegHzo_ytsAA_pIegHrzo_TRTA" to %swift.async_func_pointer*), i32 0, i32 1), align 4
  br label %14

14:                                               ; preds = %entry, %10
  %15 = phi i32 [ %.pre, %10 ], [ %2, %entry ]
  %16 = phi i8* [ %13, %10 ], [ bitcast (void (%swift.task*, %swift.executor*, %swift.context*)* @"$ss5Error_pIegHzo_ytsAA_pIegHrzo_TRTA" to i8*), %entry ]

As far as I understand, if function pointer is a direct pointer to a function, it could not be an async function pointer. So this PR changes to emit undefs instead of offset operations.

I'm not familiar with this area, so I would appreciate it if you could tell me if I'm doing in wrong way.

CC: @nate-chandler

If function pointer is a direct pointer to a function,
it could not be an async function pointer. And additive
operation to function address is illegal on some archs
like wasm32, so emit undefs instead.
@MaxDesiatov
Copy link
Contributor

@swift-ci please smoke test

@MaxDesiatov
Copy link
Contributor

@swift-ci please test macOS platform

@swift-ci
Copy link
Contributor

swift-ci commented Jan 8, 2021

Build failed
Swift Test OS X Platform
Git Sha - 3a6e33f

@kateinoigakukun
Copy link
Member Author

@MaxDesiatov Could you re-trigger CI again?

@MaxDesiatov
Copy link
Contributor

@swift-ci please test

@swift-ci
Copy link
Contributor

swift-ci commented Feb 3, 2021

Build failed
Swift Test OS X Platform
Git Sha - 3a6e33f

@nate-chandler
Copy link
Contributor

nate-chandler commented Feb 3, 2021

Hi @kateinoigakukun , thanks for looking at this! We're planning to change the way that "references" to async functions get passed (they will always be async function pointers) and that will most likely result in this function (irgen::getAsyncFunctionAndSize) getting deleted. I don't fully understand the ramifications of this change, so I'd like to hold off on taking it for now.

@kateinoigakukun
Copy link
Member Author

Thanks for your response!

they will always be async function pointers

It seems simpler way! OK, I'll close this and take a look after the change again 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants