> For the complete documentation index, see [llms.txt](https://ir0nstone.gitbook.io/notes/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://ir0nstone.gitbook.io/notes/binexp/browser-exploitation/an-introduction-to-turbofan/a-typer-bug.md).

# A Typer Bug

One of my favourite writeups and bugs is [this writeup](https://abiondo.me/2019/01/02/exploiting-math-expm1-v8/) about exploiting mis-speculation bugs, based on [this](https://project-zero.issues.chromium.org/issues/42450781) report by Project Zero.

Conceptually, the bug is actually very simple. In JavaScript, there are two types of zero - `0` and `-0`. This is because JavaScript implements the [IEEE Standard for Floating-Point Arithmetic (IEEE 754)](https://ieeexplore.ieee.org/document/8766229), which has signed zeroes, but I still think it's stupid.

The bug is found in the [`Math.expm1`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/expm1) function, which calculates $$e$$ to the power of a number and then subtracts $$1$$. The typer, as described in the report, sets the type of `Math.expm1` to be `Union(PlainNumber, NaN)` (found [here ](https://source.chromium.org/chromium/v8/v8.git/+/9680338c622d4693f984b49fb24d101acd2d8112:src/compiler/typer.cc;l=1437)and [here](https://source.chromium.org/chromium/v8/v8.git/+/9680338c622d4693f984b49fb24d101acd2d8112:src/compiler/operation-typer.cc;l=420)) - that is, regardless of the input to `Math.expm1`, the output will either be classified as a `PlainNumber` (any floating-point number except `-0`) or `NaN`. The problem, however, is that `Math.expm(-0) = -0`, so the typer is wrong.

As shown in the PoC, we can abuse this fact to cause mis-speculation. The idea is to compare `Math.expm(-0)` to `-0`. While this is actually `true`, when optimized, Turbofan will use the incorrect type and note that `-0` is not a possible output, so it will optimize it away for speed and set the value to `false`:

```javascript
function foo() {  
  return Object.is(Math.expm1(-0), -0);  
}  
  
console.log(foo());  
%OptimizeFunctionOnNextCall(foo);  
console.log(foo());  
```

When you run this in d8:

```
% d8 --allow-natives-syntax expm1-poc.js
true
false
```

Once you get to this point, you have everything you need. The idea is to create something else that would normally trigger a check but the JIT compiler has optimized the check away. For example:

```javascript
function foo(x) {
    let a = [1.1, 2.2];
    let b = Object.is(Math.expm1(x), -0);
    return a[b * 1337];
}
```

Since `b` is optimized to be `false`, which is equivalent to `0`, the bounds check is removed and, in theory, we would access OOB at index `1337`! From here, it's the same as the classic OOB challenge.

**However**, the typer is a little smarter than this, and since `b` can only possibly be `0` it will fold out `b` entirely and the whole function will just return `1.1`. There are several tricks required to stop this folding, but I won't go over them right now - I recommend you check out the rest of [the writeup](https://abiondo.me/2019/01/02/exploiting-math-expm1-v8/), which is of a CTF challenge based on this bug. [The report](https://project-zero.issues.chromium.org/issues/42450781) also contains information on achieving an OOB.

TODO finish this

## More Writeups

* [FizzBuzz's Turboflan writeup](https://www.willsroot.io/2021/04/turboflan-picoctf-2021-writeup-v8.html)
* [P0ch1ta's writeup of CVE-2025-2135](https://keksite.in/posts/CVE-2025-2135/)
* [Faith's writeup for CVE-2020-16040](https://faraz.faith/2021-01-07-cve-2020-16040-analysis/)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://ir0nstone.gitbook.io/notes/binexp/browser-exploitation/an-introduction-to-turbofan/a-typer-bug.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
