diff options
author | Yusuke Sasaki <yusuke.sasaki.nuem@gmail.com> | 2020-01-29 17:05:42 +0900 |
---|---|---|
committer | Wez Furlong <wez@wezfurlong.org> | 2020-01-29 08:17:31 -0800 |
commit | 747bbf07a5c2515ed2f828ba75227ed2272fab76 (patch) | |
tree | 20ffd941eb2e53c6c1ffb415e129d004ea3b2019 | |
parent | e43929d52795a047942a5c14281707bf8c69d5c4 (diff) | |
download | ssh2-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.rs | 44 |
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) +} |