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

Expose sqlite's sqlite3_create_collation() #2564

Merged
merged 16 commits into from
Apr 15, 2021

Conversation

TaKO8Ki
Copy link
Member

@TaKO8Ki TaKO8Ki commented Nov 12, 2020

I've taken over #2495.

Copy link
Member

@weiznich weiznich left a comment

Choose a reason for hiding this comment

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

Thanks for reactivating this PR I left another round of comments. As this is touching unsafe code I would like to get this correct.
I encourage @diesel-rs/reviewers to have an independent look at the unsafe code parts.

diesel/src/sqlite/connection/mod.rs Outdated Show resolved Hide resolved
diesel/src/sqlite/connection/mod.rs Outdated Show resolved Hide resolved
};
}
let args = unsafe { slice::from_raw_parts(value_ptr, num_args as _) };
let args = build_sql_function_args::<ArgsSqlType, Args>(args);
Copy link
Member

Choose a reason for hiding this comment

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

Technically this calls FromSql::from_sql internally which also can panic. Therefore I think that should be moved into the catch_unwind block below.

diesel/src/sqlite/connection/raw.rs Show resolved Hide resolved
Comment on lines 454 to 525
assert_fail!(
"An unknown error occurred. user_ptr is a null pointer. This should never happen."
);
});

for (ptr, len, side) in &[(rhs_ptr, rhs_len, "rhs"), (lhs_ptr, lhs_len, "lhs")] {
if *len < 0 {
assert_fail!(
"An unknown error occurred. {}_len is negative. This should never happen.",
side
);
}
if ptr.is_null() {
assert_fail!(
"An unknown error occurred. {}_ptr is a null pointer. This should never happen.",
side
);
Copy link
Member

Choose a reason for hiding this comment

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

The other function implementations return errors in this case instead of aborting. I would favor that here too as this is more consistent + we do not control the sqlite source code so we cannot assume to much there.

std::cmp::Ordering::Less => -1,
});
let result = std::panic::catch_unwind(f);
result.unwrap_or_else(|_| std::process::abort())
Copy link
Member

Choose a reason for hiding this comment

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

We should just set the an error here like done for the other both cases above.

Copy link
Member Author

Choose a reason for hiding this comment

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

So you mean I should set an error by using context_error_str?

Copy link
Member

Choose a reason for hiding this comment

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

👍

z33ky and others added 14 commits March 29, 2021 11:11
Panics across FFI boundaries cause undefined behavior in current Rust.
The aggregator functions are callbacks invoked from C (libsqlite).
To safe-guard against panics, std::panic::catch_unwind() is used. On
panic the functions now return with an error result indicating the
unexpected panic occurred.

std::panic::catch_unwind() requires types to implement
std::panic::UnwindSafe, a marker trait indicating that care must be
taken since panics introduce control-flow that is not very visible.
Refer to https://doc.rust-lang.org/std/panic/trait.UnwindSafe.html for a
more detailed explanation.
For SqliteAggregatorFunction::step() we must use
std::panic::AssertUnwindSafe, since &mut references are never considered
UnwindSafe, and the requirement to ensure unwind-safety is documented on
the method.
Of note is that in safe Rust, even if the method is not unwind-safe
the language still guarantees memory-safety. The marker trait is mainly
to prevent logic bugs.
This encompasses the pattern of eprintln!() + std::process::abort() and
adds a request to open an issue if the message is observed.
This is essentially the same treatment that custom aggregate functions
got in ee2f792.
Co-authored-by: Georg Semmler <Georg_semmler_05@web.de>
This fixes the handling of panics in custom SQLite functions
by having a `catch_unwind` before ffi the boundary and by correctly
setting the required `UnwindSafe` trait bounds in a similar way as it is
done by rusqlite.
@weiznich weiznich marked this pull request as ready for review March 31, 2021 09:55
@weiznich weiznich changed the title [WIP] Expose sqlite's sqlite3_create_collation() Expose sqlite's sqlite3_create_collation() Apr 1, 2021
@weiznich weiznich requested a review from a team April 1, 2021 18:01
@TaKO8Ki
Copy link
Member Author

TaKO8Ki commented Apr 15, 2021

@weiznich
Thank you for your help. Looks good to me.

CHANGELOG.md Outdated Show resolved Hide resolved
@weiznich weiznich merged commit a944168 into diesel-rs:master Apr 15, 2021
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.

3 participants