From 76f90508006a16fb36af666cb7611b4c74e08f54 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 1 Jul 2026 17:55:18 +0100 Subject: [PATCH] Add string with interior null --- cpp2rust/converter/converter.cpp | 14 +++-- .../refcount/string_literal_interior_null.rs | 44 +++++++++++++++ .../unsafe/string_literal_interior_null.rs | 53 +++++++++++++++++++ tests/unit/string_literal_interior_null.cpp | 29 ++++++++++ 4 files changed, 137 insertions(+), 3 deletions(-) create mode 100644 tests/unit/out/refcount/string_literal_interior_null.rs create mode 100644 tests/unit/out/unsafe/string_literal_interior_null.rs create mode 100644 tests/unit/string_literal_interior_null.cpp diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index c287f319..65929016 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -1991,8 +1991,15 @@ bool Converter::VisitStringLiteral(clang::StringLiteral *expr) { GetEscapedStringLiteral(expr, 1))); return false; } - assert(!expr->getString().contains('\0') && - "interior null byte in string literal"); + if (expr->getString().contains('\0')) { + std::string out = "(&["; + for (unsigned char c : expr->getString()) { + out += getTypedLiteral(std::to_string(c).c_str(), CharRustType()) + ", "; + } + out += getTypedLiteral("0", CharRustType()) + "])"; + StrCat(out); + return false; + } StrCat(std::format("c{}", GetEscapedStringLiteral(expr, 0))); return false; } @@ -2927,7 +2934,8 @@ bool Converter::VisitCompoundLiteralExpr(clang::CompoundLiteralExpr *expr) { bool Converter::VisitArraySubscriptExpr(clang::ArraySubscriptExpr *expr) { auto *base = expr->getBase(); - if (base->IgnoreCasts()->getType()->isPointerType()) { + if (base->IgnoreCasts()->getType()->isPointerType() || + clang::isa(base->IgnoreCasts())) { ConvertPointerSubscript(expr); } else { ConvertArraySubscript(base, expr->getIdx(), expr->getType()); diff --git a/tests/unit/out/refcount/string_literal_interior_null.rs b/tests/unit/out/refcount/string_literal_interior_null.rs new file mode 100644 index 00000000..4df8ad38 --- /dev/null +++ b/tests/unit/out/refcount/string_literal_interior_null.rs @@ -0,0 +1,44 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::{Read, Seek, Write}; +use std::os::fd::AsFd; +use std::rc::{Rc, Weak}; +pub fn sum_bytes_0(buf: Ptr, len: u32) -> i32 { + let buf: Value> = Rc::new(RefCell::new(buf)); + let len: Value = Rc::new(RefCell::new(len)); + let sum: Value = Rc::new(RefCell::new(0)); + let i: Value = Rc::new(RefCell::new(0_u32)); + 'loop_: while ((*i.borrow()) < (*len.borrow())) { + (*sum.borrow_mut()) += (((*buf.borrow()).offset((*i.borrow()) as isize).read()) as i32); + (*i.borrow_mut()).postfix_inc(); + } + return (*sum.borrow()); +} +thread_local!( + pub static g_packet_1: Value> = + Rc::new(RefCell::new(Ptr::from_string_literal(b"\x01\0"))); +); +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let a: Value = Rc::new(RefCell::new( + ({ sum_bytes_0(Ptr::from_string_literal(b"\x01\0"), 2_u32) }), + )); + let b: Value = Rc::new(RefCell::new( + ({ sum_bytes_0((*g_packet_1.with(Value::clone).borrow()).clone(), 2_u32) }), + )); + assert!(((*a.borrow()) == (*b.borrow()))); + assert!(((*a.borrow()) == 1)); + let c: Value = Rc::new(RefCell::new( + ((b"\r\n.\r\n"[(0) as usize] as i32) + (b"\r\n.\r\n"[(3) as usize] as i32)), + )); + assert!(((*c.borrow()) == ((('\r' as u8) as i32) + (('\r' as u8) as i32)))); + let idx: Value = Rc::new(RefCell::new(1)); + let d: Value = Rc::new(RefCell::new((b"abcd"[(*idx.borrow()) as usize] as i32))); + assert!(((*d.borrow()) == (('b' as u8) as i32))); + return 0; +} diff --git a/tests/unit/out/unsafe/string_literal_interior_null.rs b/tests/unit/out/unsafe/string_literal_interior_null.rs new file mode 100644 index 00000000..27d5c041 --- /dev/null +++ b/tests/unit/out/unsafe/string_literal_interior_null.rs @@ -0,0 +1,53 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::{Read, Seek, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +pub unsafe fn sum_bytes_0(mut buf: *const libc::c_char, mut len: u32) -> i32 { + let mut sum: i32 = 0; + let mut i: u32 = 0_u32; + 'loop_: while ((i) < (len)) { + sum += (((*buf.offset((i) as isize)) as u8) as i32); + i.postfix_inc(); + } + return sum; +} +pub static mut g_packet_1: *const libc::c_char = unsafe { + (&[ + (1 as libc::c_char), + (0 as libc::c_char), + (0 as libc::c_char), + ]) + .as_ptr() +}; +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut a: i32 = (unsafe { + sum_bytes_0( + (&[ + (1 as libc::c_char), + (0 as libc::c_char), + (0 as libc::c_char), + ]) + .as_ptr(), + 2_u32, + ) + }); + let mut b: i32 = (unsafe { sum_bytes_0(g_packet_1, 2_u32) }); + assert!(((a) == (b))); + assert!(((a) == (1))); + let mut c: i32 = (((*c"\r\n.\r\n".as_ptr().offset((0) as isize)) as i32) + + ((*c"\r\n.\r\n".as_ptr().offset((3) as isize)) as i32)); + assert!(((c) == ((('\r' as libc::c_char) as i32) + (('\r' as libc::c_char) as i32)))); + let mut idx: i32 = 1; + let mut d: i32 = ((*c"abcd".as_ptr().offset((idx) as isize)) as i32); + assert!(((d) == (('b' as libc::c_char) as i32))); + return 0; +} diff --git a/tests/unit/string_literal_interior_null.cpp b/tests/unit/string_literal_interior_null.cpp new file mode 100644 index 00000000..a922a364 --- /dev/null +++ b/tests/unit/string_literal_interior_null.cpp @@ -0,0 +1,29 @@ +#include +#include + +static int sum_bytes(const char *buf, unsigned len) { + int sum = 0; + for (unsigned i = 0; i < len; i++) { + sum += (unsigned char)buf[i]; + } + return sum; +} + +static const char *g_packet = "\x01\x00"; + +int main() { + int a = sum_bytes("\x01\x00", 2); + int b = sum_bytes(g_packet, 2); + + assert(a == b); + assert(a == 1); + + int c = "\r\n.\r\n"[0] + "\r\n.\r\n"[3]; + assert(c == '\r' + '\r'); + + int idx = 1; + int d = "abcd"[idx]; + assert(d == 'b'); + + return 0; +}