Skip to content

Latest commit

 

History

History
271 lines (211 loc) · 7.03 KB

File metadata and controls

271 lines (211 loc) · 7.03 KB

Null Handling Fix for Breakpoint Results

Issue Identified

In src/backend/adapter.ts, the setFunctionBreakPointsRequest method incorrectly treated breakpoint results as arrays, accessing them with result[0] and result[1], when they are actually objects (or null for failed breakpoints).

Root Cause

The addBreakPoint method in src/backend/mi2/mi2.ts returns:

  • A breakpoint object with properties like number, line, file when successful
  • null when parsing fails or GDB returns an error

However, setFunctionBreakPointsRequest was treating results as if they were arrays:

if (result[0]) {
    breakpoints.push({ line: result[1].line });
}

This is incorrect because:

  1. result is not an array - it's either an object or null
  2. result[0] and result[1] would always be undefined for objects
  3. No null-checking was performed

Comparison with Other Callers

✅ setBreakPointsRequest (Correct)

const results = (await Promise.all(promises)).filter((r) => r !== null);
response.body = {
    breakpoints: results.map((bp: any) => ({
        line: bp.line,
        id: bp.number,
        verified: true,
    })),
};

This correctly:

  • Filters out null results
  • Accesses object properties (bp.line, bp.number)

❌ setFunctionBreakPointsRequest (Incorrect - Before Fix)

results.forEach((result) => {
    if (result[0]) {  // ❌ Treating object as array
        breakpoints.push({ line: result[1].line });  // ❌ Array access
    }
});

This incorrectly:

  • Treats result as an array
  • Doesn't properly check for null
  • Would fail to add any breakpoints

Fixed Code

After Fix

results.forEach((result) => {
    // Filter out null results (failed breakpoints) and use breakpoint object properties
    if (result !== null) {
        breakpoints.push({ 
            line: result.line,
            id: result.number,
            verified: true
        });
    }
});

This correctly:

  • Checks for null explicitly
  • Accesses object properties (result.line, result.number)
  • Includes id and verified fields for consistency with setBreakPointsRequest

Breakpoint Object Structure

Returned by addBreakPoint

// Success case
{
    number: 5,           // Breakpoint number from GDB
    line: 10,            // Line number
    file: 'test.c',      // File path
    condition?: string,  // Optional condition
    countCondition?: string  // Optional hit count
}

// Failure case
null

NOT an Array

The result is not structured as:

[boolean, { line: number }]  // ❌ WRONG

Impact Analysis

Before Fix

  • Function breakpoints would never be properly registered
  • result[0] would always be undefined for object results
  • result[1] would cause runtime errors when accessed
  • Breakpoints would silently fail to work

After Fix

  • Function breakpoints are properly registered
  • Null results are filtered out
  • Object properties are correctly accessed
  • Consistent behavior with file breakpoints

Test Coverage

Created comprehensive tests in __tests__/backend/breakpoint-error-handling.test.ts:

Test Categories

  1. Null Return Handling (3 tests)

    • Parsing failures return null
    • GDB errors return null
    • Successful breakpoints return objects
  2. Adapter Result Handling (4 tests)

    • Filtering null results
    • Handling all-null results
    • Mapping to DAP format
    • Mixed null and valid results
  3. Object Structure (3 tests)

    • Consistent object structure
    • Not an array
    • Property access vs index access
  4. Error Scenarios (3 tests)

    • Invalid file paths
    • Invalid line numbers
    • Missing optional fields
  5. Type Safety (3 tests)

    • Null vs valid distinction
    • Promise type handling

Test Results

✓ 16 new tests added
✓ All 96 tests passing
✓ 100% pass rate

Code Quality Improvements

Before

  • Type Safety: Poor (treating objects as arrays)
  • Null Handling: Missing
  • Consistency: Inconsistent with other methods
  • Maintainability: Confusing code

After

  • Type Safety: Good (proper object property access)
  • Null Handling: Explicit null checks
  • Consistency: Matches setBreakPointsRequest pattern
  • Maintainability: Clear and understandable

Verification

Manual Testing Checklist

  • Set function breakpoints in GDB
  • Verify breakpoints are hit
  • Test with invalid function names (should handle gracefully)
  • Test with conditional function breakpoints
  • Test with multiple function breakpoints

Automated Testing

npm test
# Test Suites: 3 passed, 3 total
# Tests:       96 passed, 96 total

Build Verification

npm run build
# extension (webpack 5.105.4) compiled successfully
# adapter (webpack 5.105.4) compiled successfully

Related Changes

Files Modified

  1. src/backend/adapter.ts - Fixed setFunctionBreakPointsRequest
  2. __tests__/backend/breakpoint-error-handling.test.ts - Added comprehensive tests

Files Verified (No Changes Needed)

  1. src/backend/mi2/mi2.ts - Already returns correct format
  2. src/backend/adapter.ts - setBreakPointsRequest already correct

Best Practices Applied

  1. Explicit Null Checks: Use result !== null instead of truthy checks
  2. Object Property Access: Use dot notation (result.line) not array access
  3. Consistent Patterns: Match existing correct implementations
  4. Comprehensive Testing: Cover success, failure, and edge cases
  5. Type Safety: Treat values according to their actual types

Migration Notes

For Users

  • No breaking changes
  • Function breakpoints will now work correctly
  • Previously broken functionality is now fixed

For Developers

  • Always check return type of addBreakPoint (object or null)
  • Use .filter(r => r !== null) before processing results
  • Access properties by name, not by index
  • Follow the pattern in setBreakPointsRequest for consistency

Future Improvements

Potential Enhancements

  1. Stronger Typing:

    interface Breakpoint {
        number: number;
        line: number;
        file: string;
        condition?: string;
        countCondition?: string;
    }
    
    addBreakPoint(bp: any): Promise<Breakpoint | null>
  2. Error Objects Instead of Null:

    interface BreakpointResult {
        success: boolean;
        breakpoint?: Breakpoint;
        error?: string;
    }
  3. Validation:

    function isValidBreakpoint(bp: any): bp is Breakpoint {
        return bp !== null && 
               typeof bp.number === 'number' &&
               typeof bp.line === 'number';
    }

Summary

Fixed critical bug where function breakpoints were treated as arrays instead of objects, causing them to fail silently. The fix:

  • ✅ Properly checks for null results
  • ✅ Accesses object properties correctly
  • ✅ Maintains consistency with other breakpoint methods
  • ✅ Includes comprehensive test coverage
  • ✅ No breaking changes

Status: ✅ Fixed, tested, and verified