Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

brili: Problem when deserializing large integer constants from JSON #304

Open
keikun555 opened this issue Nov 16, 2023 · 7 comments
Open

Comments

@keikun555
Copy link

To reproduce:

❯ cat test/overflow.bril
@main() {
  x: int = const 9223372036854775807;
  one: int = const 1;
  three: int = const 3;
  y: int = add x one;
  print y;
  y: int = mul x three;
  print y;
}
❯
❯ bril2json < test/overflow.bril | brili
-9223372036854775807
-9223372036854775808
❯ bril2json < test/overflow.bril | brilirs
-9223372036854775808
9223372036854775805
❯

The Bril documentation on integers writes:

int: 64-bit, two’s complement, signed integers.

I wonder which one is correct?

@Pat-Lafon
Copy link
Contributor

The brilirs version is consistent with the Wrapping<i64> type in Rust. https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=24433b06279415b718abed7a1ae3ad55

I would guess brili is doing the multiplication with a larger integer format and then truncating down to 64 bits.

@keikun555
Copy link
Author

It might be the JSON parser in typescript truncating the input integer before it can be converted to a bigint

let prog = JSON.parse(await readStdin()) as bril.Program;

@Pat-Lafon
Copy link
Contributor

Try printing out x then to see if the value is different. Might also be interesting to print out val here before it gets converted to bigInt

bril/brili.ts

Line 466 in daaff28

let val = getInt(instr, state.env, 0) * getInt(instr, state.env, 1);

@keikun555
Copy link
Author

keikun555 commented Nov 16, 2023

So looks like it's part of the problem.

❯ cat test/bignumber.bril
@main() {
  x: int = const 9223372036854775807;
  print x;
}
❯ bril2json < test/bignumber.bril | brili
9223372036854775808
❯ bril2json < test/bignumber.bril | brilirs
9223372036854775807

Here's a StackOverflow page that talks about JSON.parse and numbers.

@keikun555
Copy link
Author

Also logged the val using this diff

❯ git diff | cat
diff --git a/brili.ts b/brili.ts
index 2a88470..ba00ea6 100644
--- a/brili.ts
+++ b/brili.ts
@@ -464,6 +464,7 @@ function evalInstr(instr: bril.Instruction, state: State): Action {

   case "mul": {
     let val = getInt(instr, state.env, 0) * getInt(instr, state.env, 1);
+    console.log(val);
     val = BigInt.asIntN(64, val);
     state.env.set(instr.dest, val);
     return NEXT;
❯ bril2json < test/bril2z3/overflow.bril | deno run --no-config vendor/bril/brili.ts
-9223372036854775807
27670116110564327424n # <== from the change
-9223372036854775808
❯

@keikun555
Copy link
Author

There's also a JS package for JSON parsing with bigints

@sampsyo sampsyo changed the title Brili and Brilirs have different overflow calculations brili: Problem when deserializing large integer constants from JSON Nov 17, 2023
@sampsyo
Copy link
Owner

sampsyo commented Nov 17, 2023

Thanks for reporting this! Fortunately, it's pretty easy to confirm that JSON deserialization is causing the problem; there's no need to observe it "in situ" in the interpreter:

$ deno
JSODeno 1.37.2
exit using ctrl+d, ctrl+c, or close()
REPL is running with all permissions allowed.
To specify permissions, run `deno repl` with allow flags.
> JSON.parse("9223372036854775807")
9223372036854776000

It's too bad that JSON.parse doesn't seem to be flexible enough to fix this. I am not wild about taking a whole new JSON parsing dependency for the interpreter, but it may be the only option until the relevant ECMAScript proposal is adopted. :(

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

No branches or pull requests

3 participants