Skip to content

Add safe cstring rules#250

Open
lucic71 wants to merge 10 commits into
Cpp2Rust:masterfrom
lucic71:safe-cstring
Open

Add safe cstring rules#250
lucic71 wants to merge 10 commits into
Cpp2Rust:masterfrom
lucic71:safe-cstring

Conversation

@lucic71

@lucic71 lucic71 commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

No description provided.

@lucic71

lucic71 commented Jul 13, 2026

Copy link
Copy Markdown
Contributor Author

@nunoplopes do you think it's better to implement most of the cstring functions as part of Ptr<u8>? The current rules are not very idiomatic

Comment thread rules/cstring/tgt_refcount.rs Outdated

fn f4(a0: AnyPtr, a1: AnyPtr, a2: usize) -> AnyPtr {
a0.memcpy(&a1, a2 as usize);
let __tmp: Vec<u8> = (0..a2)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why can't we use memcpy here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

f4 is memmove. memmove allows overlap between src and dst, memcpy does not (it's UB). Maybe it would be a good idea to add an assert inside Ptr::memcpy to panic on overlapping regions.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But our implementation of memcpy is ok with overlaps. There's no point in reinventing the wheel.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not ok if dst > src. For the following code:

#include <string.h>

int main(void) {
    char buf[6] = {1, 2, 3, 4, 5, 6};

    memmove(buf + 2, buf, 4);

    for (int i = 0; i < 6; i++) {
      printf("%d ", buf[i]);
    }
    printf("\n");

    return 0;
}

The output is:

C:                                 1 2 1 2 3 4 (correct, it's a shift right)
memmove translated as Ptr::memcpy: 1 2 1 2 1 2 (wrong)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think an assert on overlapping Ptr::memcpy would be useful. Memcpy with overlapping memory is UB in C

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know it's UB in C. But our safe Rust implementation can handle overlapping memory. So let's use it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this case I will change the implementation of Ptr::memcpy to fully behave as memmove

Comment thread rules/cstring/tgt_refcount.rs Outdated
Comment thread rules/cstring/tgt_refcount.rs Outdated
Comment thread rules/cstring/tgt_refcount.rs Outdated
Comment thread rules/cstring/tgt_refcount.rs Outdated
}
}

unsafe fn f7(a0: Ptr<u8>) -> usize {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unsafe

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment thread rules/cstring/tgt_refcount.rs Outdated
let mut __p2 = a1.clone();
let mut __i: usize = 0;
loop {
if __i == a2 {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can decrement a2; there's no need for __i

@lucic71 lucic71 Jul 15, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It makes no difference, a2 is textually replaced inside the rule. We cannot decrement a2 until it reaches 0, we need to save it in a variable eitherway

let mut __p = a0.reinterpret_cast::<u8>();
let mut __i: usize = 0;
loop {
if __i == a2 {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here; can be decremented

@lucic71 lucic71 Jul 15, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It makes no difference, a2 is textually replaced inside the rule. We cannot decrement a2 until it reaches 0, we need to save it in a variable eitherway

Comment thread rules/cstring/tgt_refcount.rs Outdated
break __i;
}
let mut __q = a1.clone();
let __hit = loop {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would rather read a1 into a local vector. seems easier to optimize.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No longer relevant. I replaced the __hit = loop idiom with CStringIterator


fn f18(a0: Ptr<u8>, a1: Ptr<u8>) -> Ptr<u8> {
let mut __p = a0.clone();
loop {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this code should be using CStringIterator instead. becomes a lot smaller.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Also used CStringIterator in other rules

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants