summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYusuke Sasaki <yusuke.sasaki.nuem@gmail.com>2020-01-29 17:05:42 +0900
committerWez Furlong <wez@wezfurlong.org>2020-01-29 08:17:31 -0800
commit747bbf07a5c2515ed2f828ba75227ed2272fab76 (patch)
tree20ffd941eb2e53c6c1ffb415e129d004ea3b2019
parente43929d52795a047942a5c14281707bf8c69d5c4 (diff)
downloadssh2-rs-747bbf07a5c2515ed2f828ba75227ed2272fab76.zip
copy the error message obtained in last_error
The pointer obtained by `libssh2_session_last_error` points to the buffer that `LIBSSH2_SESSION` holds internally, so its contents may be overwritten by the next API call. This patch changes the data type for storing error messages inside `Error` from `&'static str` to `Cow<'static, str>`.
-rw-r--r--src/error.rs44
1 files changed, 33 insertions, 11 deletions
diff --git a/src/error.rs b/src/error.rs
index 7ae0431..be12eed 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -1,4 +1,5 @@
use libc;
+use std::borrow::Cow;
use std::error;
use std::ffi::NulError;
use std::fmt;
@@ -13,21 +14,26 @@ use {raw, Session};
#[allow(missing_copy_implementations)]
pub struct Error {
code: libc::c_int,
- msg: &'static str,
+ msg: Cow<'static, str>,
}
impl Error {
#[doc(hidden)]
pub fn last_error_raw(raw: *mut raw::LIBSSH2_SESSION) -> Option<Error> {
- static STATIC: () = ();
unsafe {
- let mut msg = 0 as *mut _;
- let rc = raw::libssh2_session_last_error(raw, &mut msg, 0 as *mut _, 0);
+ let mut msg = null_mut();
+ let rc = raw::libssh2_session_last_error(raw, &mut msg, null_mut(), 0);
if rc == 0 {
return None;
}
- let s = ::opt_bytes(&STATIC, msg).unwrap();
- Some(Error::new(rc, str::from_utf8(s).unwrap()))
+
+ // The pointer stored in `msg` points to the internal buffer of
+ // LIBSSH2_SESSION, so the error message should be copied before
+ // it is overwritten by the next API call.
+ Some(Self {
+ code: rc,
+ msg: make_error_message(msg),
+ })
}
}
@@ -43,15 +49,20 @@ impl Error {
#[doc(hidden)]
pub fn from_session_error_raw(raw: *mut raw::LIBSSH2_SESSION, rc: libc::c_int) -> Error {
- static STATIC: () = ();
unsafe {
let mut msg = null_mut();
let res = raw::libssh2_session_last_error(raw, &mut msg, null_mut(), 0);
if res != rc {
return Self::from_errno(rc);
}
- let s = ::opt_bytes(&STATIC, msg).unwrap();
- Error::new(rc, str::from_utf8(s).unwrap())
+
+ // The pointer stored in `msg` points to the internal buffer of
+ // LIBSSH2_SESSION, so the error message should be copied before
+ // it is overwritten by the next API call.
+ Self {
+ code: rc,
+ msg: make_error_message(msg),
+ }
}
}
@@ -66,7 +77,7 @@ impl Error {
pub fn new(code: libc::c_int, msg: &'static str) -> Error {
Error {
code: code,
- msg: msg,
+ msg: Cow::Borrowed(msg),
}
}
@@ -164,7 +175,7 @@ impl Error {
/// Get the message corresponding to this error
pub fn message(&self) -> &str {
- self.msg
+ &*self.msg
}
/// Return the code for this error
@@ -205,3 +216,14 @@ impl From<NulError> for Error {
)
}
}
+
+unsafe fn make_error_message(msg: *mut libc::c_char) -> Cow<'static, str> {
+ const FALLBACK: Cow<'_, str> = Cow::Borrowed("<failed to fetch the error message>");
+ ::opt_bytes(&(), msg)
+ .and_then(|msg| {
+ str::from_utf8(msg)
+ .map(|msg| Cow::Owned(msg.to_owned()))
+ .ok()
+ })
+ .unwrap_or_else(|| FALLBACK)
+}