Skip to content

fix(codegen): check narrowed int32 operand#1195

Open
Kuhai9801 wants to merge 3 commits into
0xMiden:nextfrom
Kuhai9801:fix-int32-uint-narrowing-1182
Open

fix(codegen): check narrowed int32 operand#1195
Kuhai9801 wants to merge 3 commits into
0xMiden:nextfrom
Kuhai9801:fix-int32-uint-narrowing-1182

Conversation

@Kuhai9801

Copy link
Copy Markdown

Closes #1182

int32_to_uint and try_int32_to_uint were duplicating the word below the value being narrowed before applying the unsigned range mask. With another live value below the operand, checked narrowing could reject a valid value or accept an out-of-range value based on the wrong stack word.

This changes both helpers to duplicate the top stack value before masking. The full-width n == 32 case uses a zero mask so the mask construction does not shift by 32.

Regression coverage compiles HIR snippets and executes them through the package evaluator:

  • checked casts from u32 and i32 to i1, u8, and u16;
  • overflowing u8 addition, which covers the try_int32_to_uint path;
  • live guard values below the checked operand, so the old dup.1 behavior fails on both valid and invalid inputs.

@Kuhai9801 Kuhai9801 marked this pull request as ready for review June 18, 2026 23:44
@Kuhai9801 Kuhai9801 force-pushed the fix-int32-uint-narrowing-1182 branch from a2cf5b6 to c116211 Compare June 21, 2026 20:44
Comment thread codegen/masm/src/emit/mod.rs Outdated
assert_eq!(emitter.stack()[0], Type::I32);
}

#[test]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This test is essentially tautological - IMO it isn't useful, so I'd remove it. Tests should be behavioral (i.e. test that the output is correct for specific inputs), and when based on specific prior failures, we can specifically exercise those as a form of regression testing.

Comment thread tests/integration/src/codegen/int32.rs Outdated
let rhs = block.borrow().arguments()[3] as ValueRef;

let (overflowed, _sum) = builder.add_overflowing(lhs, rhs, span).unwrap();
// Keep both guards live below the sum so overflowing arithmetic must validate the sum,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The wording of this is pretty unclear, because it is referring to a specific failure mode of the original code that is fixed. I would remove this comment, and instead provide a comment that explains the purpose of the guard values (which is essentially to have stuff on the operand stack that would cause an error if values on the operand stack were consumed incorrectly).

Comment thread codegen/masm/src/emit/int32.rs Outdated
// Copy the input
self.emit(masm::Instruction::Dup1, span);
// Apply the mask
// A 32-bit target has no unused high bits, so use a zero mask without shifting by 32.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
// A 32-bit target has no unused high bits, so use a zero mask without shifting by 32.
// If the target bit width is 32, then use an empty mask

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.

int32_to_uint checks dup.1 instead of the value being narrowed

2 participants