Skip to content
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

Fix segfault on tagged output #175

Merged
merged 3 commits into from
May 21, 2024
Merged

Conversation

ausbin
Copy link
Contributor

@ausbin ausbin commented May 21, 2024

Currently, record_output() segfaults when passed a pointer to a tag. This IR, for example, segfaults on my system:

@example = internal constant [3 x i8] c"hi\00"

define i64 @kernel() #0 {
...
  call void @__quantum__rt__tuple_record_output(i64 4, ptr @example)
...

This appears to be because record_output() calls CString.from_raw() on a pointer not managed by CString. This commit uses CStr.from_ptr() instead and adds some tests to catch future regressions (hopefully).

I am not a Rust programmer so hopefully I am doing this right. But at least cargo test passes for me now (the new tests fail with the existing code) and my example IR file no longer segfaults.

Currently, record_output() segfaults when passed a pointer to a tag.
This IR, for example, segfaults on my system:

    @example = internal constant [3 x i8] c"hi\00"

    define i64 @kernel() #0 {
    ...
      call void @__quantum__rt__tuple_record_output(i64 4, ptr @example)
    ...

This appears to be because record_output() calls CString.from_raw() on a
pointer not managed by CString[1]. This commit uses CStr.from_ptr()
instead and adds some tests to catch future regressions (hopefully).

[1]: https://doc.rust-lang.org/std/ffi/struct.CString.html#method.from_raw
@ausbin ausbin requested review from idavis, billti and swernli as code owners May 21, 2024 09:40
@ausbin
Copy link
Contributor Author

ausbin commented May 21, 2024

@microsoft-github-policy-service agree

@ausbin
Copy link
Contributor Author

ausbin commented May 21, 2024

Here's a full example file, if it's useful for trying to reproduce:

; ModuleID = 'LLVMDialectModule'
source_filename = "LLVMDialectModule"

@tag_ret = internal constant [4 x i8] c"ret\00"
@tag_discarded = internal constant [10 x i8] c"discarded\00"

define i64 @kernel() #0 {
  call void @__quantum__rt__initialize(ptr null)
  call void @__quantum__qis__h__body(ptr null)
  call void @__quantum__qis__cx__body(ptr null, ptr inttoptr (i64 1 to ptr))
  call void @__quantum__qis__cx__body(ptr null, ptr inttoptr (i64 2 to ptr))
  call void @__quantum__qis__cx__body(ptr null, ptr inttoptr (i64 3 to ptr))
  call void @__quantum__qis__cx__body(ptr null, ptr inttoptr (i64 4 to ptr))
  call void @__quantum__rt__tuple_record_output(i64 5, ptr @tag_ret)
  call void @__quantum__qis__mz__body(ptr null, ptr null)
  call void @__quantum__qis__mz__body(ptr inttoptr (i64 1 to ptr), ptr inttoptr (i64 1 to ptr))
  call void @__quantum__qis__mz__body(ptr inttoptr (i64 2 to ptr), ptr inttoptr (i64 2 to ptr))
  call void @__quantum__qis__mz__body(ptr inttoptr (i64 3 to ptr), ptr inttoptr (i64 3 to ptr))
  call void @__quantum__qis__mz__body(ptr inttoptr (i64 4 to ptr), ptr inttoptr (i64 4 to ptr))
  call void @__quantum__rt__result_record_output(ptr null, ptr null)
  call void @__quantum__rt__result_record_output(ptr inttoptr (i64 1 to ptr), ptr null)
  call void @__quantum__rt__result_record_output(ptr inttoptr (i64 2 to ptr), ptr null)
  call void @__quantum__rt__result_record_output(ptr inttoptr (i64 3 to ptr), ptr null)
  call void @__quantum__rt__result_record_output(ptr inttoptr (i64 4 to ptr), ptr null)
  call void @__quantum__rt__tuple_record_output(i64 0, ptr @tag_discarded)
  ret i64 0
}

declare void @__quantum__qis__h__body(ptr %0)

declare void @__quantum__qis__cx__body(ptr %0, ptr %1)

declare void @__quantum__rt__initialize(ptr %0)

declare void @__quantum__qis__mz__body(ptr %0, ptr %1)

declare void @__quantum__rt__tuple_record_output(i64 %0, ptr %1)

declare void @__quantum__rt__result_record_output(ptr %0, ptr %1)

attributes #0 = { "entry_point" "output_labeling_schema"="qwerty_v1" "qir_profiles"="base_profile" "required_num_qubits"="5" "required_num_results"="5" }

!llvm.module.flags = !{!0, !1, !2, !3, !4}

!0 = !{i32 2, !"Debug Info Version", i32 3}
!1 = !{i32 1, !"dynamic_qubit_management", i1 false}
!2 = !{i32 1, !"dynamic_result_management", i1 false}
!3 = !{i32 1, !"qir_major_version", i32 1}
!4 = !{i32 1, !"qir_minor_version", i32 0}

The __quantum__rt__tuple_record_output() call is the relevant part

Copy link
Collaborator

@swernli swernli left a comment

Choose a reason for hiding this comment

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

Tried the changes out locally with tagged output using typed pointers and it worked as expected. Thanks for the fix!

@swernli swernli merged commit aa5d39b into qir-alliance:main May 21, 2024
15 checks passed
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.

2 participants