So many "it can't be done" comments. Here's an outline of how to approach the problem.
Here's some C code with pointer arithmetic from OpenJPEG. This module has has buffer overflows reported in security advisories, so it's a good place to start.
static void opj_dwt_deinterleave_h(const OPJ_INT32 *OPJ_RESTRICT a,
OPJ_INT32 *OPJ_RESTRICT b,
OPJ_INT32 dn,
OPJ_INT32 sn,
OPJ_INT32 cas)
{
OPJ_INT32 i;
OPJ_INT32 * OPJ_RESTRICT l_dest = b;
const OPJ_INT32 * OPJ_RESTRICT l_src = a + cas;
for (i = 0; i < sn; ++i) {
*l_dest++ = *l_src;
l_src += 2;
}
l_dest = b + sn;
l_src = a + 1 - cas;
for (i = 0; i < dn; ++i) {
*l_dest++ = *l_src;
l_src += 2;
}
So how would an analyzer proceed?
First, expand OBJ_RESTRICT, which is defined as C "restrict". That means no aliasing. Nice to know.
Which parameters are arrays? This function calls no other functions, so this is decidable from the code here. Parameters a and b are potentially arrays.
Pointer arithmetic is detected at *l_dest++
and at l_src = a + cas
. l_dest gets its value from b. So parameters a and b are definitely arrays. *l_dest++ appears on the left side of an assignment, so b is mutated.
We can now write the function definition in Rust.
fn opj_dwt_deinterleave_h(a: &[i32], b: &mut[i32], dn: i32, sn: i32, cas: i32)
That's straightforward, safe Rust.
OK, here's a pointer that gets mutated.
`OPJ_INT32 * OPJ_RESTRICT l_dest = b;`
What do we do there? l_dest always points to
some part of b. So it can be expressed as a
subscript into b. So
let mut l_dest: usize = 0;
Next,
const OPJ_INT32 * OPJ_RESTRICT l_src = a + cas;
which always points to some part of a. So
let mut l_src: usize = cas as usize;
Now the hard part, pointer arithmetic in the first FOR loop.
for (i = 0; i < sn; ++i) {
*l_dest++ = *l_src;
l_src += 2;
}
The "for" statement is such a common C idiom that it needs to be recognized. Corrode does that. So
for i in 0..sn {
Now, we know that l_dest points to somewhere in b
, and l_src
points to somewhere in a
. So we just have to calculate the subscript.
b[l_dest] = a[l_src];
Now we need to figure out the incrementation.
l_dest++
increments by one size of the thing pointed to,
so it's
l_dest += 1;
and
l_src += 2;
And that's the first loop, converted to safe Rust.
This is a bit long, but I wanted to show that this is not an impossible problem.
There are hard cases to resolve. Those involve cases where you have a pointer that's hard to tie back to the underlying array. Those may need human assistance. But most code doesn't do that, unless it's a storage allocator. If you can determine which array a pointer points to, you can convert pointer arithmetic into subscripts automatically.
After conversion to Rust, subscript checking will protect against buffer overflow attacks.
So, this is not impossible. Just hard. A good thesis project for someone getting their CS degree.