From bd908d4c0e9cc4717928e63d7ed64cd9ffe0bfce Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Sun, 7 Jul 2013 13:30:48 -0700 Subject: [PATCH] std and rustc: explicitly pass c strings to c functions When strings lose their trailing null, this pattern will become dangerous: let foo = "bar"; let foo_ptr: *u8 = &foo[0]; Instead we should use c_strs to handle this correctly. --- src/librustc/middle/trans/base.rs | 9 ++- src/libstd/libc.rs | 4 +- src/libstd/os.rs | 94 ++++++++++++++------------- src/libstd/ptr.rs | 101 ++++++++++++++++-------------- 4 files changed, 112 insertions(+), 96 deletions(-) diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 5b048558fd11..bfcc1e1b6a16 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -2400,11 +2400,10 @@ pub fn create_entry_wrapper(ccx: @mut CrateContext, (rust_main, args) }; - let result = llvm::LLVMBuildCall(bld, - start_fn, - &args[0], - args.len() as c_uint, - noname()); + let result = do args.as_imm_buf |buf, len| { + llvm::LLVMBuildCall(bld, start_fn, buf, len as c_uint, noname()) + }; + llvm::LLVMBuildRet(bld, result); } } diff --git a/src/libstd/libc.rs b/src/libstd/libc.rs index f96d3ce263ec..678704fe0983 100644 --- a/src/libstd/libc.rs +++ b/src/libstd/libc.rs @@ -2652,7 +2652,7 @@ pub mod funcs { pub fn execvpe(c: *c_char, argv: **c_char, envp: **c_char) -> c_int; #[link_name = "_getcwd"] - pub fn getcwd(buf: *c_char, size: size_t) -> *c_char; + pub fn getcwd(buf: *mut c_char, size: size_t) -> *c_char; #[link_name = "_getpid"] pub fn getpid() -> c_int; #[link_name = "_isatty"] @@ -2804,7 +2804,7 @@ pub mod funcs { pub fn execvp(c: *c_char, argv: **c_char) -> c_int; pub fn fork() -> pid_t; pub fn fpathconf(filedes: c_int, name: c_int) -> c_long; - pub fn getcwd(buf: *c_char, size: size_t) -> *c_char; + pub fn getcwd(buf: *mut c_char, size: size_t) -> *c_char; pub fn getegid() -> gid_t; pub fn geteuid() -> uid_t; pub fn getgid() -> gid_t ; diff --git a/src/libstd/os.rs b/src/libstd/os.rs index fb4f14d33c60..48a14d6893ed 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -74,14 +74,15 @@ pub static TMPBUF_SZ : uint = 1000u; static BUF_BYTES : uint = 2048u; pub fn getcwd() -> Path { - let buf = [0 as libc::c_char, ..BUF_BYTES]; - unsafe { - if(0 as *libc::c_char == libc::getcwd( - &buf[0], - BUF_BYTES as libc::size_t)) { - fail!(); + let mut buf = [0 as libc::c_char, ..BUF_BYTES]; + do buf.as_mut_buf |buf, len| { + unsafe { + if libc::getcwd(buf, len as size_t).is_null() { + fail!() + } + + Path(str::raw::from_c_str(buf as *c_char)) } - Path(str::raw::from_c_str(&buf[0])) } } @@ -464,18 +465,18 @@ pub fn self_exe_path() -> Option { unsafe { use libc::funcs::posix01::unistd::readlink; - let mut path_str = str::with_capacity(TMPBUF_SZ); - let len = do path_str.to_c_str().with_ref |buf| { - let buf = buf as *mut c_char; - do "/proc/self/exe".to_c_str().with_ref |proc_self_buf| { - readlink(proc_self_buf, buf, TMPBUF_SZ as size_t) + let mut path = [0 as c_char, .. TMPBUF_SZ]; + + do path.as_mut_buf |buf, len| { + let len = do "/proc/self/exe".to_c_str.with_ref |proc_self_buf| { + readlink(proc_self_buf, buf, len as size_t) as uint + }; + + if len == -1 { + None + } else { + Some(str::raw::from_buf_len(buf as *u8, len)) } - }; - if len == -1 { - None - } else { - str::raw::set_len(&mut path_str, len as uint); - Some(path_str) } } } @@ -699,13 +700,15 @@ pub fn list_dir(p: &Path) -> ~[~str] { extern { fn rust_list_dir_val(ptr: *dirent_t) -> *libc::c_char; } - let input = p.to_str(); let mut strings = ~[]; - let input_ptr = ::cast::transmute(&input[0]); debug!("os::list_dir -- BEFORE OPENDIR"); - let dir_ptr = opendir(input_ptr); + + let dir_ptr = do p.to_c_str().with_ref |buf| { + opendir(buf) + }; + if (dir_ptr as uint != 0) { - debug!("os::list_dir -- opendir() SUCCESS"); + debug!("os::list_dir -- opendir() SUCCESS"); let mut entry_ptr = readdir(dir_ptr); while (entry_ptr as uint != 0) { strings.push(str::raw::from_c_str(rust_list_dir_val( @@ -715,7 +718,7 @@ pub fn list_dir(p: &Path) -> ~[~str] { closedir(dir_ptr); } else { - debug!("os::list_dir -- opendir() FAILURE"); + debug!("os::list_dir -- opendir() FAILURE"); } debug!( "os::list_dir -- AFTER -- #: %?", @@ -1043,14 +1046,15 @@ pub fn last_os_error() -> ~str { } let mut buf = [0 as c_char, ..TMPBUF_SZ]; - unsafe { - let err = strerror_r(errno() as c_int, &mut buf[0], - TMPBUF_SZ as size_t); - if err < 0 { - fail!("strerror_r failure"); - } - str::raw::from_c_str(&buf[0]) + do buf.as_mut_buf |buf, len| { + unsafe { + if strerror_r(errno() as c_int, buf, len as size_t) < 0 { + fail!("strerror_r failure"); + } + + str::raw::from_c_str(buf as *c_char) + } } } @@ -1076,23 +1080,29 @@ pub fn last_os_error() -> ~str { static FORMAT_MESSAGE_FROM_SYSTEM: DWORD = 0x00001000; static FORMAT_MESSAGE_IGNORE_INSERTS: DWORD = 0x00000200; - let mut buf = [0 as c_char, ..TMPBUF_SZ]; - // This value is calculated from the macro // MAKELANGID(LANG_SYSTEM_DEFAULT, SUBLANG_SYS_DEFAULT) let langId = 0x0800 as DWORD; let err = errno() as DWORD; - unsafe { - let res = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - ptr::mut_null(), err, langId, - &mut buf[0], TMPBUF_SZ as DWORD, - ptr::null()); - if res == 0 { - fail!("[%?] FormatMessage failure", errno()); - } - str::raw::from_c_str(&buf[0]) + let mut buf = [0 as c_char, ..TMPBUF_SZ]; + + do buf.as_imm_buf |buf, len| { + unsafe { + let res = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + ptr::mut_null(), + err, + langId, + buf, + len as DWORD, + ptr::null()); + if res == 0 { + fail!("[%?] FormatMessage failure", errno()); + } + + str::raw::from_c_str(buf) + } } } diff --git a/src/libstd/ptr.rs b/src/libstd/ptr.rs index 77222490f171..88a915a1e559 100644 --- a/src/libstd/ptr.rs +++ b/src/libstd/ptr.rs @@ -442,6 +442,7 @@ pub mod ptr_tests { use super::*; use prelude::*; + use c_str::ToCStr; use cast; use libc; use str; @@ -486,7 +487,6 @@ pub mod ptr_tests { #[test] fn test_position() { - use c_str::ToCStr; use libc::c_char; do "hello".to_c_str().with_ref |p| { @@ -500,8 +500,6 @@ pub mod ptr_tests { #[test] fn test_buf_len() { - use c_str::ToCStr; - do "hello".to_c_str().with_ref |p0| { do "there".to_c_str().with_ref |p1| { do "thing".to_c_str().with_ref |p2| { @@ -608,66 +606,75 @@ pub mod ptr_tests { #[test] fn test_ptr_array_each_with_len() { unsafe { - let one = ~"oneOne"; - let two = ~"twoTwo"; - let three = ~"threeThree"; - let arr: ~[*i8] = ~[ - ::cast::transmute(&one[0]), - ::cast::transmute(&two[0]), - ::cast::transmute(&three[0]), + let one = "oneOne".to_c_str(); + let two = "twoTwo".to_c_str(); + let three = "threeThree".to_c_str(); + let arr = ~[ + one.with_ref(|buf| buf), + two.with_ref(|buf| buf), + three.with_ref(|buf| buf), ]; let expected_arr = [ one, two, three ]; - let arr_ptr = &arr[0]; - let mut ctr = 0; - let mut iteration_count = 0; - array_each_with_len(arr_ptr, arr.len(), - |e| { - let actual = str::raw::from_c_str(e); - let expected = expected_arr[ctr].clone(); - debug!( - "test_ptr_array_each e: %s, a: %s", - expected, actual); - assert_eq!(actual, expected); - ctr += 1; - iteration_count += 1; - }); - assert_eq!(iteration_count, 3u); + + do arr.as_imm_buf |arr_ptr, arr_len| { + let mut ctr = 0; + let mut iteration_count = 0; + do array_each_with_len(arr_ptr, arr_len) |e| { + let actual = str::raw::from_c_str(e); + let expected = do expected_arr[ctr].with_ref |buf| { + str::raw::from_c_str(buf) + }; + debug!( + "test_ptr_array_each_with_len e: %s, a: %s", + expected, actual); + assert_eq!(actual, expected); + ctr += 1; + iteration_count += 1; + } + assert_eq!(iteration_count, 3u); + } } } + #[test] fn test_ptr_array_each() { unsafe { - let one = ~"oneOne"; - let two = ~"twoTwo"; - let three = ~"threeThree"; - let arr: ~[*i8] = ~[ - ::cast::transmute(&one[0]), - ::cast::transmute(&two[0]), - ::cast::transmute(&three[0]), + let one = "oneOne".to_c_str(); + let two = "twoTwo".to_c_str(); + let three = "threeThree".to_c_str(); + let arr = ~[ + one.with_ref(|buf| buf), + two.with_ref(|buf| buf), + three.with_ref(|buf| buf), // fake a null terminator - 0 as *i8 + null(), ]; let expected_arr = [ one, two, three ]; - let arr_ptr = &arr[0]; - let mut ctr = 0; - let mut iteration_count = 0; - array_each(arr_ptr, |e| { - let actual = str::raw::from_c_str(e); - let expected = expected_arr[ctr].clone(); - debug!( - "test_ptr_array_each e: %s, a: %s", - expected, actual); - assert_eq!(actual, expected); - ctr += 1; - iteration_count += 1; - }); - assert_eq!(iteration_count, 3); + + do arr.as_imm_buf |arr_ptr, arr_len| { + let mut ctr = 0; + let mut iteration_count = 0; + do array_each(arr_ptr) |e| { + let actual = str::raw::from_c_str(e); + let expected = do expected_arr[ctr].with_ref |buf| { + str::raw::from_c_str(buf) + }; + debug!( + "test_ptr_array_each e: %s, a: %s", + expected, actual); + assert_eq!(actual, expected); + ctr += 1; + iteration_count += 1; + } + assert_eq!(iteration_count, 3); + } } } + #[test] #[should_fail] #[ignore(cfg(windows))]