Files
compiler-explorer/lib/tooling/x86to6502-tool.ts
Matt Godbolt c4bb7f7c68 Fix unsafe type casting in assembly processing tools (#7767)
## Summary

Fixes unsafe type casting in assembly processing tools that was causing
`TypeError: text.split is not a function` runtime crashes.

## Root Cause Analysis

**COMPILER-EXPLORER-C2N** (57 occurrences) and **COMPILER-EXPLORER-AWW**
(184 occurrences):

The issue stemmed from tools making unsafe assumptions about
`compilationInfo.asm` type:

```typescript
// CompilationInfo.asm type (from types/compilation/compilation.interfaces.ts:168)
asm?: ParsedAsmResultLine[] | string;  // "Temp hack until we get all code to agree on type of asm"
```

**The bug sequence:**
1. `base-compiler.ts:3120` converts string assembly to parsed format:
`result.asm = [{text: result.asm}]`
2. Tools unsafely cast back to string: `compilationInfo.asm as string`
3. `AsmParser.processBinaryAsm()` calls `splitLines(asmResult)` 
4. If `asm` is actually `ParsedAsmResultLine[]`, `splitLines()` receives
an array
5. `text.split()` fails because arrays don't have `.split()` method

**Affected tools:** osaca-tool, x86to6502-tool, llvm-mca-tool

## Changes

### New Helper Functions in `utils.ts`:

1. **`extractTextLines(asm: string | any[]): string[]`**
   - Safely extracts text lines from union types
- Throws descriptive errors for unexpected types (will surface in
Sentry)

2. **`normalizeAsmToString(asm: string | any[] | undefined): string`**
- Centralizes the common pattern of converting union type to string for
parser consumption
   - Handles undefined gracefully

### Tool Fixes:

- **Removed unsafe casts**: `compilationInfo.asm as string` →
`normalizeAsmToString(compilationInfo.asm)`
- **Added null checks**: Explicit error handling for missing assembly
data
- **Type safety**: No more runtime type assumptions

## Impact

- Eliminates root cause of `text.split is not a function` errors (241+
occurrences combined)
- Maintains existing functionality - tools continue to work normally
- Better error messages when assembly data is missing
- Centralizes type handling logic for future maintainability

**Note:** The underlying architectural issue (union type "temp hack")
remains, but tools now handle it safely without crashes.

Fixes COMPILER-EXPLORER-C2N
Fixes COMPILER-EXPLORER-AWW

🤖 Generated with [Claude Code](https://claude.ai/code)

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Mats Jun Larsen <mats@jun.codes>
2025-06-11 18:04:25 -05:00

76 lines
3.2 KiB
TypeScript

// Copyright (c) 2023, Compiler Explorer Team
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
// import {CompilationInfo} from '../../types/compilation/compilation.interfaces.js';
import {CompilationInfo} from '../../types/compilation/compilation.interfaces.js';
import {ToolResult} from '../../types/tool.interfaces.js';
import {AsmParser} from '../parsers/asm-parser.js';
import * as utils from '../utils.js';
import {BaseTool} from './base-tool.js';
export class x86to6502Tool extends BaseTool {
static get key() {
return 'x86to6502-tool';
}
override async runTool(compilationInfo: CompilationInfo, _inputFilepath?: string, args?: string[]) {
if (compilationInfo.filters.intel) {
return new Promise<ToolResult>(resolve => {
resolve(this.createErrorResponse('<need AT&T notation assembly>'));
});
}
if (compilationInfo.filters.binary) {
return new Promise<ToolResult>(resolve => {
resolve(this.createErrorResponse('<cannot run x86to6502 on binary>'));
});
}
if (!compilationInfo.asm) {
return this.createErrorResponse('<no assembly output available>');
}
const parser = new AsmParser();
const filters = Object.assign({}, compilationInfo.filters);
const asmString = utils.normalizeAsmToString(compilationInfo.asm);
const result = parser.process(asmString, filters);
const asm = result.asm
.map(obj => {
if (typeof obj.text !== 'string' || obj.text.trim() === '') {
return '';
}
if (/.*:/.test(obj.text)) {
return obj.text.replace(/^\s*/, '');
}
return obj.text.replace(/^\s*/, '\t');
})
.join('\n');
return super.runTool(compilationInfo, undefined, args, asm);
}
}