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

C/C++ errorhandling #3001

Merged
merged 34 commits into from
Aug 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
e621a12
use of typedef and enum in c api
Wumpf Aug 11, 2023
07c0220
wip
Wumpf Aug 11, 2023
b33c87a
c error handling utlities, handle all failure modes of rr_recording_s…
Wumpf Aug 11, 2023
3e93522
remove accidental old generated files
Wumpf Aug 11, 2023
76a6fc6
set error to ok if everything is alright, split rerun_c modules
Wumpf Aug 11, 2023
f64e974
start implementing cpp status object
Wumpf Aug 11, 2023
ff7e06d
test setup for log testing, tests for recording stream creation failure
Wumpf Aug 11, 2023
21821d6
recording stream save & connect errors
Wumpf Aug 15, 2023
d7b7ec8
fix warnings on roundtrip tests
Wumpf Aug 15, 2023
d08df12
c api logging errors
Wumpf Aug 15, 2023
d8468eb
fix file save error test
Wumpf Aug 15, 2023
46c8f4d
fix c example
Wumpf Aug 15, 2023
6f79500
tests and api for basic logging failures
Wumpf Aug 15, 2023
0157c70
Make status nodiscard, not return values
Wumpf Aug 16, 2023
cde29c8
remove unused static assertion macro again
Wumpf Aug 16, 2023
49cc529
fix missing exception header (gcc error)
Wumpf Aug 16, 2023
c119d6c
fix rust warnings
Wumpf Aug 16, 2023
f720c2b
depend on loguru in tests but no longer in the sdk
Wumpf Aug 16, 2023
71edc12
readd ldl for linux builds of rerun_cpp
Wumpf Aug 16, 2023
b6db515
fix error message character truncation and add test
Wumpf Aug 16, 2023
ca14ddd
lib pthread for linux builds
Wumpf Aug 16, 2023
2b4d337
error OK constant
Wumpf Aug 17, 2023
86a6b21
argument/parameter confusion fix
Wumpf Aug 17, 2023
06f2cbb
nicer error handling on rust side using `Result` and less unsafe mark…
Wumpf Aug 17, 2023
3e279a8
call status consistently error in c api
Wumpf Aug 17, 2023
0d32772
better description doc
Wumpf Aug 17, 2023
127d899
use c error in c example and no longer touch it when no error occurred
Wumpf Aug 17, 2023
5ab851f
typo fix
Wumpf Aug 17, 2023
dc3a361
explicit is_ok/is_err for Status
Wumpf Aug 17, 2023
e57b798
rename log_error to log
Wumpf Aug 17, 2023
242f72f
rename log_error_on_failure to log_error
Wumpf Aug 17, 2023
8c9ea96
missing doc string
Wumpf Aug 17, 2023
bd094f9
rename C++ status types to error
Wumpf Aug 17, 2023
370bb25
codegen
Wumpf Aug 17, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,22 @@ if(NOT DEFINED CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 17)
endif()

# ------------------------------------------------------------------------------
# Loguru logging library (https://github.com/emilk/loguru):
set(CMAKE_DL_LIBS "dl") # Required by Loguru for backtraces

# Loguru, see https://github.com/emilk/loguru/blob/master/loguru_cmake_example/CMakeLists.txt
include(FetchContent)
FetchContent_Declare(LoguruGitRepo
GIT_REPOSITORY "https://github.com/emilk/loguru" # can be a filesystem path
GIT_TAG "master"
)

# set any loguru compile-time flags before calling MakeAvailable()
set(LOGURU_STACKTRACES 1)
FetchContent_MakeAvailable(LoguruGitRepo) # defines target 'loguru::loguru'

# ------------------------------------------------------------------------------
add_subdirectory(rerun_cpp) # The Rerun C++ SDK library
add_subdirectory(examples/cpp/minimal)
add_subdirectory(tests/cpp)
2 changes: 1 addition & 1 deletion crates/re_types/source_hash.txt

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

115 changes: 115 additions & 0 deletions crates/rerun_c/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
use crate::{CError, CErrorCode};

impl CError {
pub const OK: CError = CError {
code: CErrorCode::Ok,
message: [0; 512],
};

pub fn new(code: CErrorCode, message: &str) -> Self {
let mut message_c = [0; 512];

// Copy string character by character.
// Ensure that when truncating is necessary, we don't truncate in the middle of a UTF-8 character!
let mut bytes_next = 0;
for c in message.chars() {
if bytes_next + c.len_utf8() >= message_c.len() {
re_log::warn_once!("Error message was too long for C error description buffer. Full message\n{message}");
break;
}

let mut bytes = [0; 4];
c.encode_utf8(&mut bytes);

for byte in &bytes[..c.len_utf8()] {
message_c[bytes_next] = *byte as _;
bytes_next += 1;
}
}

// Fill the rest with nulls.
for byte in &mut message_c[bytes_next..] {
*byte = 0;
}

Self {
code,
message: message_c,
}
}

pub fn unexpected_null(parameter_name: &str) -> Self {
Self::new(
CErrorCode::UnexpectedNullArgument,
&format!("Unexpected null passed for parameter '{parameter_name:?}'"),
)
}

pub fn invalid_str_argument(parameter_name: &str, utf8_error: std::str::Utf8Error) -> Self {
CError::new(
CErrorCode::InvalidStringArgument,
&format!("Argument {parameter_name:?} is not valid UTF-8: {utf8_error}",),
)
}

pub fn invalid_recording_stream_handle() -> Self {
CError::new(
CErrorCode::InvalidRecordingStreamHandle,
"Recording stream handle does not point to an existing recording stream.",
)
}

#[allow(unsafe_code)]
pub(crate) fn write_error(self, error: *mut CError) {
if let Some(error) = unsafe { error.as_mut() } {
*error = self;
};
}
}

#[cfg(test)]
mod tests {
use std::ffi::{c_char, CStr};

use crate::{CError, CErrorCode};

#[test]
#[allow(unsafe_code)]
fn write_error_handles_message_overflow() {
// With ASCII character.
let description = "a".repeat(1024);
let error = CError::new(CErrorCode::Ok, &description);
let num_expected_bytes = error.message.len() - 1;
assert_eq!(
unsafe { CStr::from_ptr(&error.message as *const c_char) }.to_str(),
Ok(&description[..num_expected_bytes])
);

// With 2 byte UTF8 character
let description = "œ".repeat(1024);
let error = CError::new(CErrorCode::Ok, &description);
let num_expected_bytes = ((error.message.len() - 1) / 2) * 2;
assert_eq!(
unsafe { CStr::from_ptr(&error.message as *const c_char) }.to_str(),
Ok(&description[..num_expected_bytes])
);

// With 3 byte UTF8 character
let description = "∂".repeat(1024);
let error = CError::new(CErrorCode::Ok, &description);
let num_expected_bytes = ((error.message.len() - 1) / 3) * 3;
assert_eq!(
unsafe { CStr::from_ptr(&error.message as *const c_char) }.to_str(),
Ok(&description[..num_expected_bytes])
);

// With 4 byte UTF8 character
let description = "😀".repeat(1024);
let error = CError::new(CErrorCode::Ok, &description);
let num_expected_bytes = ((error.message.len() - 1) / 4) * 4;
assert_eq!(
unsafe { CStr::from_ptr(&error.message as *const c_char) }.to_str(),
Ok(&description[..num_expected_bytes])
);
}
}
Loading