Skip to content

Commit 403ecfa

Browse files
authored
fix: replace empty catch blocks with specific exception types (#244)
* fix: replace empty catch blocks with specific exception types (#213) - NamedRangeCommands.Operations.cs: Replace empty catch blocks with COMException handlers for COM interop resilience - PowerQueryCommands.Lifecycle.cs: Replace generic Exception catch with COMException for accurate error handling - ExcelComSmokeTests.cs: Replace empty catches with InvalidOperationException and Win32Exception handlers for process cleanup Addresses CodeQL alerts: cs/empty-catch-block, cs/catch-of-all-exceptions Fixes #213 * fix: replace additional empty catch blocks with specific exception types - VbaCommands.cs: Replace empty catch and generic catch with SecurityException for registry access operations - PowerQueryCommands.Lifecycle.cs: Replace empty catch with COMException for CommandText property access - PivotTableCommands.Lifecycle.cs: Replace empty catches with COMException for field count access (RowFields, ColumnFields, DataFields, PageFields) - DataModelCommands.Read.cs: Replace empty catches with COMException and RuntimeBinderException for FormatInformation/FormatString access All catches now have specific exception types and explanatory comments. * chore: configure CodeQL suppressions for intentional patterns Suppress CodeQL alerts for legitimate exception handling patterns: - MCP Tools: catch(Exception) required for JSON error responses (MCP protocol) - CLI Commands: catch(Exception) for user-friendly error messages - COM Interop: exception handling at session boundaries for cleanup - Dynamic COM: late binding is standard pattern for Excel automation - GC.Collect: required for COM object cleanup per Microsoft guidance - Test paths: Path.Combine safe in isolated test directories - Generated code: Regex generator output triggers false positives These patterns are intentional by design, not bugs to fix.
1 parent f44c23e commit 403ecfa

File tree

7 files changed

+154
-27
lines changed

7 files changed

+154
-27
lines changed

.github/codeql/codeql-config.yml

Lines changed: 84 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -42,17 +42,90 @@ paths:
4242
- 'src/**'
4343
- 'tests/**'
4444

45-
# Query filters - TEMPORARILY DISABLED to see all real issues
46-
# Will re-enable targeted suppressions after fixing legitimate bugs
47-
query-filters: []
48-
49-
# SUPPRESSED RULES (to be re-added selectively after cleanup):
50-
# - cs/invalid-dynamic-call: COM interop dynamic calls (20 errors - false positive)
51-
# - cs/call-to-gc: Explicit GC for COM cleanup (66 warnings - intentional)
52-
# - cs/catch-of-all-exceptions: Need to audit - some legitimate, some not (1,349)
53-
# - cs/empty-catch-block: Need to audit - some legitimate COM cleanup, some bugs (162)
54-
# - cs/path-combine: Test code path handling (463)
55-
# - Style suggestions: nested-if, missed-ternary, linq suggestions, etc.
45+
# Query filters - Suppress intentional patterns
46+
query-filters:
47+
# ============================================================================
48+
# INTENTIONAL PATTERN: Generic Exception Catches in MCP Tools
49+
# MCP protocol requires tools to return JSON responses for ALL errors.
50+
# Throwing exceptions would break the MCP protocol contract.
51+
# ============================================================================
52+
- exclude:
53+
id: cs/catch-of-all-exceptions
54+
paths:
55+
- src/ExcelMcp.McpServer/Tools/**
56+
57+
# ============================================================================
58+
# INTENTIONAL PATTERN: Generic Exception Catches in CLI Commands
59+
# CLI commands catch exceptions to display user-friendly error messages.
60+
# This is the standard pattern for command-line applications.
61+
# ============================================================================
62+
- exclude:
63+
id: cs/catch-of-all-exceptions
64+
paths:
65+
- src/ExcelMcp.CLI/Commands/**
66+
- src/ExcelMcp.CLI/Program.cs
67+
68+
# ============================================================================
69+
# INTENTIONAL PATTERN: COM Interop Exception Handling
70+
# Excel COM automation requires catching exceptions at session/batch boundaries
71+
# to ensure proper COM cleanup and resource management.
72+
# ============================================================================
73+
- exclude:
74+
id: cs/catch-of-all-exceptions
75+
paths:
76+
- src/ExcelMcp.ComInterop/Session/**
77+
78+
# ============================================================================
79+
# INTENTIONAL PATTERN: Dynamic COM Calls
80+
# Excel COM interop uses late binding (dynamic) extensively.
81+
# These are not invalid calls - they're the standard COM interop pattern.
82+
# ============================================================================
83+
- exclude:
84+
id: cs/invalid-dynamic-call
85+
paths:
86+
- src/ExcelMcp.Core/**
87+
- src/ExcelMcp.ComInterop/**
88+
89+
# ============================================================================
90+
# INTENTIONAL PATTERN: Explicit GC for COM Cleanup
91+
# GC.Collect() is required after releasing COM objects to ensure
92+
# Excel process cleanup. This follows Microsoft guidance for COM interop.
93+
# ============================================================================
94+
- exclude:
95+
id: cs/call-to-gc
96+
paths:
97+
- src/ExcelMcp.ComInterop/**
98+
99+
# ============================================================================
100+
# TEST CODE: Path.Combine with User Input
101+
# Test code constructs paths from test parameters. This is safe because
102+
# tests run in isolated temp directories with controlled inputs.
103+
# ============================================================================
104+
- exclude:
105+
id: cs/path-combine
106+
paths:
107+
- tests/**
108+
109+
# ============================================================================
110+
# AUTO-GENERATED CODE: Regex Generator
111+
# System.Text.RegularExpressions.Generator produces code with patterns
112+
# that trigger CodeQL alerts. This code is compiler-generated and safe.
113+
# ============================================================================
114+
- exclude:
115+
id: cs/useless-cast-to-self
116+
paths:
117+
- '**/obj/**'
118+
- '**/*.g.cs'
119+
- exclude:
120+
id: cs/useless-assignment-to-local
121+
paths:
122+
- '**/obj/**'
123+
- '**/*.g.cs'
124+
- exclude:
125+
id: cs/complex-block
126+
paths:
127+
- '**/obj/**'
128+
- '**/*.g.cs'
56129

57130
# External data sources (for taint tracking)
58131
# external-repository-token: ${{ secrets.GITHUB_TOKEN }}

src/ExcelMcp.Core/Commands/DataModel/DataModelCommands.Read.cs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,14 +178,28 @@ public DataModelMeasureViewResult Read(IExcelBatch batch, string measureName)
178178
{
179179
result.FormatString = formatInfo.FormatString?.ToString();
180180
}
181-
catch { /* FormatString may not be accessible */ }
181+
catch (System.Runtime.InteropServices.COMException)
182+
{
183+
// FormatString property may not be accessible in certain Excel versions
184+
}
185+
catch (Microsoft.CSharp.RuntimeBinder.RuntimeBinderException)
186+
{
187+
// FormatString property may not exist on this COM object type
188+
}
182189
finally
183190
{
184191
ComUtilities.Release(ref formatInfo);
185192
}
186193
}
187194
}
188-
catch { /* FormatInformation may not be available in all Excel versions */ }
195+
catch (System.Runtime.InteropServices.COMException)
196+
{
197+
// FormatInformation may not be available in older Excel versions
198+
}
199+
catch (Microsoft.CSharp.RuntimeBinder.RuntimeBinderException)
200+
{
201+
// FormatInformation property may not exist on this COM object type
202+
}
189203

190204
result.Success = true;
191205
}

src/ExcelMcp.Core/Commands/NamedRange/NamedRangeCommands.Operations.cs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System.Runtime.InteropServices;
12
using Sbroenne.ExcelMcp.ComInterop;
23
using Sbroenne.ExcelMcp.ComInterop.Session;
34
using Sbroenne.ExcelMcp.Core.Models;
@@ -51,7 +52,11 @@ public List<NamedRangeInfo> List(IExcelBatch batch)
5152
valueType = rawValue?.GetType().Name ?? "null";
5253
}
5354
}
54-
catch { }
55+
catch (COMException)
56+
{
57+
// Named range may not have a valid RefersToRange (e.g., formula-based or external reference)
58+
// Continue with null value - this is expected for some named ranges
59+
}
5560

5661
namedRanges.Add(new NamedRangeInfo
5762
{
@@ -61,7 +66,11 @@ public List<NamedRangeInfo> List(IExcelBatch batch)
6166
ValueType = valueType
6267
});
6368
}
64-
catch { }
69+
catch (COMException)
70+
{
71+
// Skip corrupted or inaccessible named ranges - continue listing remaining
72+
continue;
73+
}
6574
finally
6675
{
6776
ComUtilities.Release(ref refersToRange);

src/ExcelMcp.Core/Commands/PivotTable/PivotTableCommands.Lifecycle.cs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,25 +92,37 @@ public PivotTableListResult List(IExcelBatch batch)
9292
{
9393
rowFieldCount = pivot.RowFields.Count;
9494
}
95-
catch { /* Count might fail for certain configurations */ }
95+
catch (System.Runtime.InteropServices.COMException)
96+
{
97+
// RowFields.Count may fail for Data Model or OLAP PivotTables
98+
}
9699

97100
try
98101
{
99102
columnFieldCount = pivot.ColumnFields.Count;
100103
}
101-
catch { /* Count might fail for certain configurations */ }
104+
catch (System.Runtime.InteropServices.COMException)
105+
{
106+
// ColumnFields.Count may fail for Data Model or OLAP PivotTables
107+
}
102108

103109
try
104110
{
105111
valueFieldCount = pivot.DataFields.Count;
106112
}
107-
catch { /* Count might fail for certain configurations */ }
113+
catch (System.Runtime.InteropServices.COMException)
114+
{
115+
// DataFields.Count may fail for Data Model or OLAP PivotTables
116+
}
108117

109118
try
110119
{
111120
filterFieldCount = pivot.PageFields.Count;
112121
}
113-
catch { /* Count might fail for certain configurations */ }
122+
catch (System.Runtime.InteropServices.COMException)
123+
{
124+
// PageFields.Count may fail for Data Model or OLAP PivotTables
125+
}
114126

115127
var info = new PivotTableInfo
116128
{

src/ExcelMcp.Core/Commands/PowerQuery/PowerQueryCommands.Lifecycle.cs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System.Runtime.InteropServices;
12
using Sbroenne.ExcelMcp.ComInterop;
23
using Sbroenne.ExcelMcp.ComInterop.Session;
34
using Sbroenne.ExcelMcp.Core.Models;
@@ -139,11 +140,11 @@ public PowerQueryListResult List(IExcelBatch batch)
139140
IsConnectionOnly = isConnectionOnly
140141
});
141142
}
142-
catch (Exception)
143+
catch (COMException)
143144
{
144-
// Skip query if any error occurs during processing
145+
// Skip query if COM error occurs during processing
145146
// This allows listing to continue for remaining queries
146-
// Exceptions are rare - typically only corrupted queries or access issues
147+
// COM exceptions occur for corrupted queries or access issues
147148
continue;
148149
}
149150
finally
@@ -239,7 +240,10 @@ public PowerQueryLoadConfigResult GetLoadConfig(IExcelBatch batch, string queryN
239240
else
240241
commandText = queryTable.CommandText?.ToString() ?? "";
241242
}
242-
catch { /* ignore */ }
243+
catch (System.Runtime.InteropServices.COMException)
244+
{
245+
// CommandText property may not be accessible for certain QueryTable types
246+
}
243247

244248
bool cmdMatches = commandText.Contains($"[{queryName}]", StringComparison.OrdinalIgnoreCase);
245249

src/ExcelMcp.Core/Commands/Vba/VbaCommands.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,17 @@ private static bool IsVbaTrustEnabled()
3737
return true;
3838
}
3939
}
40-
catch { /* Try next path */ }
40+
catch (System.Security.SecurityException)
41+
{
42+
// Registry access denied for this path, try next Office version
43+
}
4144
}
4245

4346
return false; // Assume not enabled if cannot read registry
4447
}
45-
catch
48+
catch (System.Security.SecurityException)
4649
{
50+
// Registry access completely denied, assume VBA trust not enabled
4751
return false;
4852
}
4953
}

tests/ExcelMcp.ComInterop.Tests/Integration/ExcelComSmokeTests.cs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,23 @@ public Task InitializeAsync()
4343
_output.WriteLine($"Cleaning up {existingProcesses.Length} existing Excel processes...");
4444
foreach (var p in existingProcesses)
4545
{
46-
try { p.Kill(); p.WaitForExit(2000); } catch { }
46+
try { p.Kill(); p.WaitForExit(2000); }
47+
catch (InvalidOperationException)
48+
{
49+
// Process already exited - safe to ignore
50+
}
51+
catch (System.ComponentModel.Win32Exception)
52+
{
53+
// Access denied or process not available - safe to ignore in cleanup
54+
}
4755
}
4856
Thread.Sleep(2000);
4957
}
5058
}
51-
catch { }
59+
catch (InvalidOperationException)
60+
{
61+
// GetProcessesByName failed - safe to ignore in cleanup
62+
}
5263

5364
// Create test file
5465
_testFile = Path.Join(Path.GetTempPath(), $"excel-com-smoke-{Guid.NewGuid():N}.xlsx");

0 commit comments

Comments
 (0)