Rust调用Gmail API触发减法溢出Panic问题求助
Rust调用Gmail API时的溢出panic问题解决
我是Rust新手,用yup_oauth2完成认证后,尝试通过google_gmail1库调用Gmail API读取邮件,运行代码时触发thread 'main' panicked at 'attempt to subtract with overflow'错误,错误栈指向google-apis-common-5.0.2/src/lib.rs:691:27。排查发现是代码里出现0减1的溢出操作,修改了库的相关代码片段,但需要彻底解决。
我的实现代码
use yup_oauth2::{InstalledFlowAuthenticator, InstalledFlowReturnMethod}; use tokio::io::{stdout, AsyncWriteExt as _}; extern crate google_gmail1 as gmail1; use gmail1::api::Message; use gmail1::{Result, Error}; use std::fs; use gmail1::{Gmail, oauth2, hyper , hyper_rustls , chrono, FieldMask}; #[tokio::main] async fn main() { let secret = yup_oauth2::read_application_secret("D:\\email-summarizer\\src\\client_secret.json") .await .expect("D:\\email-summarizer\\src\\client_secret.json"); let auth = InstalledFlowAuthenticator::builder(secret, InstalledFlowReturnMethod::HTTPRedirect) .persist_tokens_to_disk("tokencache.json") .build() .await .unwrap(); let scopes = &["https://www.googleapis.com/auth/drive.file"]; let mut hub = Gmail::new( hyper::Client::builder().build( hyper_rustls::HttpsConnectorBuilder::new().with_native_roots().https_or_http().enable_http1().enable_http2().build()), auth); let mut req = Message::default(); let result = hub.users().messages_import(req, "userId") .process_for_calendar(true) .never_mark_spam(true) .internal_date_source("Lorem") .deleted(false) .upload_resumable(fs::File::open("D:\\email-summarizer\\src\\file.ext").unwrap(), "application/octet-stream".parse().unwrap()).await; match result { Err(e) => match e { Error::HttpError(_) |Error::Io(_) |Error::MissingAPIKey |Error::MissingToken(_) |Error::Cancelled |Error::UploadSizeLimitExceeded(_, _) |Error::Failure(_) |Error::BadRequest(_) |Error::FieldClash(_) |Error::JsonDecodeError(_, _) => println!("{}", e), }, Ok(res) => println!("Success: {:?}", res), } }
错误回溯信息
0: std::panicking::begin_panic_handler at /rustc/fc594f15669680fa70d255faec3ca3fb507c3405/library\std\src\panicking.rs:575 1: core::panicking::panic_fmt at /rustc/fc594f15669680fa70d255faec3ca3fb507c3405/library\core\src\panicking.rs:64 2: core::panicking::panic at /rustc/fc594f15669680fa70d255faec3ca3fb507c3405/library\core\src\panicking.rs:111 3: google_apis_common::impl$14::upload::async_fn$0<alloc::boxed::Box<dyn<google_apis_common::auth::GetToken>,alloc::alloc::Global>,hyper_rustls::connector::HttpsConnector<hyper::client::connect::http::HttpConnector<hyper::client::connect::dns::GaiResolver> at C:\Users\DC\.cargo\registry\src\github.com-1ecc6299db9ec823\google-apis-common-5.0.2\src\lib.rs:691 4: google_gmail1::api::impl$110::doit::async_fn$0<hyper_rustls::connector::HttpsConnector<hyper::client::connect::http::HttpConnector<hyper::client::connect::dns::GaiResolver> >,std::fs::File> at C:\Users\DC\.cargo\registry\src\github.com-1ecc6299db9ec823\google-gmail1-5.0.2+20230116\src\api.rs:9036 5: google_gmail1::api::impl$110::upload_resumable::async_fn$0<hyper_rustls::connector::HttpsConnector<hyper::client::connect::http::HttpConnector<hyper::client::connect::dns::GaiResolver> >,std::fs::File> at C:\Users\DC\.cargo\registry\src\github.com-1ecc6299db9ec823\google-gmail1-5.0.2+20230116\src\api.rs:9090 6: email_summarizer::main::async_block$0 at .\src\main.rs:41 7: tokio::runtime::park::impl$4::block_on::closure$0<enum2$<email_summarizer::main::async_block_env$0> > at C:\Users\DC\.cargo\registry\src\github.com-1ecc6299db9ec823\tokio-1.27.0\src\runtime\park.rs:283 8: tokio::runtime::coop::with_budget at C:\Users\DC\.cargo\registry\src\github.com-1ecc6299db9ec823\tokio-1.27.0\src\runtime\coop.rs:107 9: tokio::runtime::coop::budget at C:\Users\DC\.cargo\registry\src\github.com-1ecc6299db9ec823\tokio-1.27.0\src\runtime\coop.rs:73 10: tokio::runtime::park::CachedParkThread::block_on<enum2$<email_summarizer::main::async_block_env$0> > at C:\Users\DC\.cargo\registry\src\github.com-1ecc6299db9ec823\tokio-1.27.0\src\runtime\park.rs:283 11: tokio::runtime::context::BlockingRegionGuard::block_on<enum2$<email_summarizer::main::async_block_env$0> > at C:\Users\DC\.cargo\registry\src\github.com-1ecc6299db9ec823\tokio-1.27.0\src\runtime\context.rs:315 12: tokio::runtime::scheduler::multi_thread::MultiThread::block_on<enum2$<email_summarizer::main::async_block_env$0> > at C:\Users\DC\.cargo\registry\src\github.com-1ecc6299db9ec823\tokio-1.27.0\src\runtime\scheduler\multi_thread\mod.rs:66 13: tokio::runtime::runtime::Runtime::block_on<enum2$<email_summarizer::main::async_block_env$0> > at C:\Users\DC\.cargo\registry\src\github.com-1ecc6299db9ec823\tokio-1.27.0\src\runtime\runtime.rs:304 14: email_summarizer::main at .\src\main.rs:43 15: core::ops::function::FnOnce::call_once<void (*)(),tuple$<> > at /rustc/fc594f15669680fa70d255faec3ca3fb507c3405\library\core\src\ops\function.rs:507 note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose back
尝试修改的代码片段
原代码(google-apis-common-5.0.2/src/lib.rs:691):
let mut section_reader = self.reader.take(request_size); let mut req_bytes = vec![]; section_reader.read_to_end(&mut req_bytes).unwrap(); let range_header = ContentRange { range: Some(Chunk { first: start, last: start + request_size - 1, }), total_length: self.content_length, }; if self.delegate.cancel_chunk_upload(&range_header) { return None;
修改后代码:
let mut section_reader = self.reader.take(request_size); let mut req_bytes = vec![]; section_reader.read_to_end(&mut req_bytes).unwrap(); let range_header = ContentRange { range: Some(Chunk { first: start, last: start + request_size - idx.wrapping_sub(1), }), total_length: self.content_length, }; if self.delegate.cancel_chunk_upload(&range_header) { return None;
彻底解决方法
1. 修复库中的溢出逻辑
问题根源是当request_size为0时,start + request_size -1会触发无符号整数溢出(0-1在无符号类型下会溢出)。正确的修复应该使用无符号安全的减法逻辑:
let last = start + request_size.wrapping_sub(1);
或者添加条件判断避免溢出:
let last = if request_size == 0 { start } else { start + request_size - 1 };
将原代码中的last: start + request_size - 1替换为上述安全逻辑即可。
2. 用Cargo Patch持久化修改
直接修改本地库文件会在重新编译时被覆盖,推荐用cargo patch保存修改:
- 在项目根目录创建
.cargo/patches/google-apis-common-5.0.2目录 - 将修改后的
lib.rs放入该目录 - 在
Cargo.toml中添加:
[patch.crates-io] google-apis-common = { path = ".cargo/patches/google-apis-common-5.0.2" }
3. 检查上传文件合法性
你的代码调用了messages_import的upload_resumable方法,空文件会导致request_size为0触发溢出。可以在代码中添加文件大小检查:
let file = fs::File::open("D:\\email-summarizer\\src\\file.ext").unwrap(); let metadata = file.metadata().unwrap(); if metadata.len() == 0 { eprintln!("Error: Upload file is empty"); return; } // 后续调用upload_resumable let result = hub.users().messages_import(req, "userId") // ...其他参数 .upload_resumable(file, "application/octet-stream".parse().unwrap()).await;
4. 升级库版本
检查google-apis-common是否有更新版本,新版本可能已修复该溢出问题。在Cargo.toml中更新依赖:
google-gmail1 = ">=5.0.3"
内容的提问来源于stack exchange,提问作者glitch_123
相关产品推荐
相关产品推荐

