From 68fb19224e57654a4292a927802e767b08fe01ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9lio=20Rocha?= Date: Mon, 29 Jul 2024 11:00:01 +0100 Subject: [PATCH 1/4] bump to 9.30 --- docs/description/S100.md | 12 +- docs/description/S1006.md | 14 +- docs/description/S101.md | 10 +- docs/description/S103.md | 2 +- docs/description/S104.md | 7 +- docs/description/S1048.md | 33 ++- docs/description/S105.md | 7 +- docs/description/S106.md | 16 +- docs/description/S1066.md | 18 +- docs/description/S1067.md | 11 +- docs/description/S107.md | 13 +- docs/description/S1075.md | 18 +- docs/description/S108.md | 9 +- docs/description/S109.md | 26 +- docs/description/S110.md | 18 +- docs/description/S1104.md | 38 +-- docs/description/S1109.md | 9 +- docs/description/S1110.md | 7 +- docs/description/S1116.md | 10 +- docs/description/S1117.md | 15 +- docs/description/S1118.md | 18 +- docs/description/S112.md | 45 ++-- docs/description/S1121.md | 29 ++- docs/description/S1123.md | 7 +- docs/description/S1125.md | 16 +- docs/description/S1128.md | 31 ++- docs/description/S113.md | 6 +- docs/description/S1133.md | 4 +- docs/description/S1134.md | 10 +- docs/description/S1135.md | 40 +-- docs/description/S1147.md | 11 +- docs/description/S1151.md | 10 +- docs/description/S1155.md | 7 +- docs/description/S1163.md | 10 +- docs/description/S1168.md | 11 +- docs/description/S1172.md | 24 +- docs/description/S1185.md | 12 +- docs/description/S1186.md | 15 +- docs/description/S1192.md | 20 +- docs/description/S1199.md | 25 +- docs/description/S1200.md | 14 +- docs/description/S1206.md | 27 +- docs/description/S121.md | 9 +- docs/description/S1210.md | 15 +- docs/description/S1215.md | 27 +- docs/description/S122.md | 8 +- docs/description/S1226.md | 8 +- docs/description/S1227.md | 6 +- docs/description/S1244.md | 35 +-- docs/description/S125.md | 7 +- docs/description/S126.md | 16 +- docs/description/S1264.md | 7 +- docs/description/S127.md | 23 +- docs/description/S1301.md | 9 +- docs/description/S1309.md | 4 +- docs/description/S131.md | 10 +- docs/description/S1312.md | 15 +- docs/description/S1313.md | 27 +- docs/description/S134.md | 24 +- docs/description/S138.md | 8 +- docs/description/S1449.md | 19 +- docs/description/S1450.md | 7 +- docs/description/S1451.md | 11 +- docs/description/S1479.md | 158 ++++++++---- docs/description/S1481.md | 28 +- docs/description/S1541.md | 5 +- docs/description/S1607.md | 17 +- docs/description/S1643.md | 4 +- docs/description/S1656.md | 8 +- docs/description/S1659.md | 4 +- docs/description/S1694.md | 127 +++++---- docs/description/S1696.md | 22 +- docs/description/S1698.md | 21 +- docs/description/S1699.md | 22 +- docs/description/S1751.md | 22 +- docs/description/S1764.md | 16 +- docs/description/S1821.md | 10 +- docs/description/S1848.md | 10 +- docs/description/S1854.md | 29 ++- docs/description/S1858.md | 11 +- docs/description/S1862.md | 18 +- docs/description/S1871.md | 28 +- docs/description/S1905.md | 31 ++- docs/description/S1939.md | 6 +- docs/description/S1940.md | 4 +- docs/description/S1944.md | 27 +- docs/description/S1994.md | 23 +- docs/description/S2053.md | 81 +++--- docs/description/S2068.md | 18 +- docs/description/S2092.md | 20 +- docs/description/S2094.md | 19 +- docs/description/S2114.md | 15 +- docs/description/S2115.md | 131 ++++++---- docs/description/S2123.md | 32 ++- docs/description/S2139.md | 23 +- docs/description/S2148.md | 11 +- docs/description/S2156.md | 8 +- docs/description/S2166.md | 8 +- docs/description/S2178.md | 37 +-- docs/description/S2183.md | 37 +-- docs/description/S2184.md | 17 +- docs/description/S2187.md | 66 ++--- docs/description/S2190.md | 30 ++- docs/description/S2197.md | 7 +- docs/description/S2198.md | 14 +- docs/description/S2201.md | 26 +- docs/description/S2219.md | 17 +- docs/description/S2221.md | 19 +- docs/description/S2222.md | 21 +- docs/description/S2223.md | 17 +- docs/description/S2225.md | 12 +- docs/description/S2234.md | 5 +- docs/description/S2245.md | 15 +- docs/description/S2251.md | 22 +- docs/description/S2252.md | 12 +- docs/description/S2257.md | 7 +- docs/description/S2259.md | 49 ++-- docs/description/S2275.md | 16 +- docs/description/S2290.md | 22 +- docs/description/S2291.md | 26 +- docs/description/S2292.md | 7 +- docs/description/S2302.md | 11 +- docs/description/S2306.md | 12 +- docs/description/S2326.md | 7 +- docs/description/S2327.md | 8 +- docs/description/S2328.md | 19 +- docs/description/S2330.md | 13 +- docs/description/S2333.md | 4 +- docs/description/S2339.md | 18 +- docs/description/S2342.md | 11 +- docs/description/S2344.md | 4 +- docs/description/S2345.md | 26 +- docs/description/S2346.md | 19 +- docs/description/S2357.md | 12 +- docs/description/S2360.md | 6 +- docs/description/S2365.md | 41 +-- docs/description/S2368.md | 25 +- docs/description/S2372.md | 14 +- docs/description/S2376.md | 7 +- docs/description/S2386.md | 16 +- docs/description/S2387.md | 12 +- docs/description/S2436.md | 6 +- docs/description/S2437.md | 30 ++- docs/description/S2445.md | 11 +- docs/description/S2479.md | 14 +- docs/description/S2486.md | 12 +- docs/description/S2551.md | 31 ++- docs/description/S2583.md | 14 +- docs/description/S2589.md | 55 ++-- docs/description/S2612.md | 25 +- docs/description/S2629.md | 36 +-- docs/description/S2674.md | 13 +- docs/description/S2681.md | 19 +- docs/description/S2688.md | 17 +- docs/description/S2692.md | 16 +- docs/description/S2696.md | 20 +- docs/description/S2699.md | 45 ++-- docs/description/S2701.md | 31 ++- docs/description/S2737.md | 10 +- docs/description/S2743.md | 19 +- docs/description/S2755.md | 75 +++--- docs/description/S2757.md | 10 +- docs/description/S2760.md | 9 +- docs/description/S2761.md | 2 +- docs/description/S2857.md | 7 +- docs/description/S2925.md | 20 +- docs/description/S2930.md | 50 ++-- docs/description/S2931.md | 13 +- docs/description/S2933.md | 18 +- docs/description/S2934.md | 21 +- docs/description/S2952.md | 12 +- docs/description/S2953.md | 48 ++-- docs/description/S2955.md | 15 +- docs/description/S2970.md | 38 +-- docs/description/S2971.md | 20 +- docs/description/S2995.md | 30 ++- docs/description/S2996.md | 10 +- docs/description/S2997.md | 22 +- docs/description/S3005.md | 20 +- docs/description/S3010.md | 9 +- docs/description/S3011.md | 14 +- docs/description/S3052.md | 10 +- docs/description/S3059.md | 11 +- docs/description/S3060.md | 26 +- docs/description/S3063.md | 11 +- docs/description/S3168.md | 17 +- docs/description/S3169.md | 10 +- docs/description/S3172.md | 6 +- docs/description/S3215.md | 10 +- docs/description/S3216.md | 15 +- docs/description/S3217.md | 25 +- docs/description/S3218.md | 10 +- docs/description/S3220.md | 12 +- docs/description/S3234.md | 15 +- docs/description/S3235.md | 4 +- docs/description/S3236.md | 11 +- docs/description/S3237.md | 28 +- docs/description/S3240.md | 4 +- docs/description/S3241.md | 7 +- docs/description/S3242.md | 9 +- docs/description/S3244.md | 28 +- docs/description/S3246.md | 21 +- docs/description/S3247.md | 45 +++- docs/description/S3249.md | 18 +- docs/description/S3251.md | 11 +- docs/description/S3253.md | 8 +- docs/description/S3254.md | 8 +- docs/description/S3256.md | 8 +- docs/description/S3257.md | 23 +- docs/description/S3260.md | 27 +- docs/description/S3261.md | 4 +- docs/description/S3262.md | 7 +- docs/description/S3263.md | 7 +- docs/description/S3264.md | 8 +- docs/description/S3265.md | 22 +- docs/description/S3267.md | 4 +- docs/description/S3329.md | 80 +++--- docs/description/S3330.md | 23 +- docs/description/S3343.md | 19 +- docs/description/S3346.md | 36 ++- docs/description/S3353.md | 27 +- docs/description/S3358.md | 2 +- docs/description/S3363.md | 23 +- docs/description/S3366.md | 24 +- docs/description/S3376.md | 14 +- docs/description/S3397.md | 11 +- docs/description/S3398.md | 7 +- docs/description/S3400.md | 9 +- docs/description/S3415.md | 26 +- docs/description/S3416.md | 30 ++- docs/description/S3427.md | 27 +- docs/description/S3431.md | 11 +- docs/description/S3433.md | 22 +- docs/description/S3440.md | 12 +- docs/description/S3441.md | 7 +- docs/description/S3442.md | 26 +- docs/description/S3443.md | 25 +- docs/description/S3444.md | 12 +- docs/description/S3445.md | 36 +-- docs/description/S3447.md | 19 +- docs/description/S3449.md | 14 +- docs/description/S3450.md | 7 +- docs/description/S3451.md | 25 +- docs/description/S3453.md | 15 +- docs/description/S3456.md | 19 +- docs/description/S3457.md | 28 +- docs/description/S3458.md | 7 +- docs/description/S3459.md | 9 +- docs/description/S3464.md | 11 +- docs/description/S3466.md | 15 +- docs/description/S3532.md | 9 +- docs/description/S3597.md | 11 +- docs/description/S3598.md | 24 +- docs/description/S3600.md | 11 +- docs/description/S3603.md | 18 +- docs/description/S3604.md | 12 +- docs/description/S3610.md | 17 +- docs/description/S3626.md | 7 +- docs/description/S3655.md | 18 +- docs/description/S3717.md | 12 +- docs/description/S3776.md | 73 +++--- docs/description/S3869.md | 18 +- docs/description/S3871.md | 20 +- docs/description/S3872.md | 8 +- docs/description/S3874.md | 18 +- docs/description/S3875.md | 10 +- docs/description/S3876.md | 7 +- docs/description/S3877.md | 11 +- docs/description/S3878.md | 7 +- docs/description/S3880.md | 7 +- docs/description/S3881.md | 13 +- docs/description/S3884.md | 17 +- docs/description/S3885.md | 12 +- docs/description/S3887.md | 25 +- docs/description/S3889.md | 12 +- docs/description/S3897.md | 10 +- docs/description/S3898.md | 10 +- docs/description/S3900.md | 15 +- docs/description/S3902.md | 14 +- docs/description/S3903.md | 7 +- docs/description/S3904.md | 21 +- docs/description/S3906.md | 8 +- docs/description/S3908.md | 10 +- docs/description/S3909.md | 9 +- docs/description/S3923.md | 8 +- docs/description/S3925.md | 36 ++- docs/description/S3926.md | 14 +- docs/description/S3927.md | 22 +- docs/description/S3928.md | 9 +- docs/description/S3937.md | 9 +- docs/description/S3949.md | 17 +- docs/description/S3956.md | 8 +- docs/description/S3962.md | 9 +- docs/description/S3963.md | 9 +- docs/description/S3966.md | 22 +- docs/description/S3967.md | 7 +- docs/description/S3971.md | 7 +- docs/description/S3972.md | 12 +- docs/description/S3973.md | 9 +- docs/description/S3981.md | 5 +- docs/description/S3984.md | 9 +- docs/description/S3990.md | 7 +- docs/description/S3992.md | 9 +- docs/description/S3993.md | 7 +- docs/description/S3994.md | 13 +- docs/description/S3995.md | 12 +- docs/description/S3996.md | 9 +- docs/description/S3997.md | 13 +- docs/description/S3998.md | 20 +- docs/description/S4000.md | 8 +- docs/description/S4002.md | 4 +- docs/description/S4004.md | 18 +- docs/description/S4005.md | 17 +- docs/description/S4015.md | 21 +- docs/description/S4016.md | 10 +- docs/description/S4017.md | 7 +- docs/description/S4018.md | 7 +- docs/description/S4019.md | 20 +- docs/description/S4022.md | 7 +- docs/description/S4023.md | 36 +-- docs/description/S4025.md | 12 +- docs/description/S4026.md | 12 +- docs/description/S4027.md | 12 +- docs/description/S4035.md | 20 +- docs/description/S4036.md | 14 +- docs/description/S4039.md | 18 +- docs/description/S4040.md | 11 +- docs/description/S4041.md | 12 +- docs/description/S4047.md | 10 +- docs/description/S4049.md | 13 +- docs/description/S4050.md | 11 +- docs/description/S4052.md | 12 +- docs/description/S4055.md | 6 +- docs/description/S4056.md | 16 +- docs/description/S4057.md | 13 +- docs/description/S4058.md | 10 +- docs/description/S4059.md | 9 +- docs/description/S4060.md | 9 +- docs/description/S4061.md | 14 +- docs/description/S4069.md | 12 +- docs/description/S4070.md | 7 +- docs/description/S4136.md | 19 +- docs/description/S4143.md | 8 +- docs/description/S4144.md | 10 +- docs/description/S4158.md | 11 +- docs/description/S4159.md | 35 +-- docs/description/S4200.md | 12 +- docs/description/S4201.md | 7 +- docs/description/S4210.md | 10 +- docs/description/S4211.md | 48 ++-- docs/description/S4212.md | 19 +- docs/description/S4214.md | 11 +- docs/description/S4220.md | 9 +- docs/description/S4225.md | 7 +- docs/description/S4226.md | 10 +- docs/description/S4260.md | 19 +- docs/description/S4261.md | 14 +- docs/description/S4275.md | 16 +- docs/description/S4277.md | 19 +- docs/description/S4347.md | 177 +++++++++++++ docs/description/S4423.md | 102 ++++---- docs/description/S4426.md | 146 ++++++----- docs/description/S4428.md | 21 +- docs/description/S4433.md | 63 +++-- docs/description/S4456.md | 17 +- docs/description/S4457.md | 17 +- docs/description/S4462.md | 19 +- docs/description/S4487.md | 9 +- docs/description/S4502.md | 19 +- docs/description/S4507.md | 33 ++- docs/description/S4524.md | 22 +- docs/description/S4545.md | 17 +- docs/description/S4581.md | 6 +- docs/description/S4583.md | 20 +- docs/description/S4586.md | 23 +- docs/description/S4635.md | 21 +- docs/description/S4663.md | 2 +- docs/description/S4790.md | 21 +- docs/description/S4792.md | 18 +- docs/description/S4830.md | 79 +++--- docs/description/S5034.md | 33 ++- docs/description/S5042.md | 13 +- docs/description/S5122.md | 15 +- docs/description/S5332.md | 71 +++-- docs/description/S5344.md | 344 +++++++++++++++++++++++++ docs/description/S5443.md | 21 +- docs/description/S5445.md | 97 ++++--- docs/description/S5542.md | 84 +++--- docs/description/S5547.md | 73 +++--- docs/description/S5659.md | 81 +++--- docs/description/S5693.md | 11 +- docs/description/S5753.md | 18 +- docs/description/S5766.md | 30 ++- docs/description/S5773.md | 76 +++--- docs/description/S5856.md | 27 +- docs/description/S6354.md | 19 +- docs/description/S6377.md | 92 +++++++ docs/description/S6419.md | 10 +- docs/description/S6420.md | 13 +- docs/description/S6421.md | 10 +- docs/description/S6422.md | 14 +- docs/description/S6423.md | 18 +- docs/description/S6424.md | 14 +- docs/description/S6444.md | 10 +- docs/description/S6507.md | 9 +- docs/description/S6513.md | 13 +- docs/description/S6561.md | 30 ++- docs/description/S6562.md | 31 ++- docs/description/S6563.md | 41 +-- docs/description/S6566.md | 32 ++- docs/description/S6575.md | 29 ++- docs/description/S6580.md | 23 +- docs/description/S6585.md | 28 +- docs/description/S6588.md | 24 +- docs/description/S6602.md | 29 ++- docs/description/S6603.md | 25 +- docs/description/S6605.md | 38 +-- docs/description/S6607.md | 28 +- docs/description/S6608.md | 119 +++++---- docs/description/S6609.md | 39 +-- docs/description/S6610.md | 31 ++- docs/description/S6612.md | 30 ++- docs/description/S6613.md | 29 ++- docs/description/S6617.md | 36 +-- docs/description/S6618.md | 33 ++- docs/description/S6640.md | 26 +- docs/description/S6664.md | 28 +- docs/description/S6667.md | 20 +- docs/description/S6668.md | 25 +- docs/description/S6669.md | 31 ++- docs/description/S6670.md | 21 +- docs/description/S6672.md | 34 ++- docs/description/S6673.md | 47 ++-- docs/description/S6674.md | 23 +- docs/description/S6675.md | 51 ++-- docs/description/S6677.md | 17 +- docs/description/S6678.md | 20 +- docs/description/S6781.md | 268 +++++++++++++++++++ docs/description/S6797.md | 15 +- docs/description/S6798.md | 18 +- docs/description/S6800.md | 16 +- docs/description/S6802.md | 21 +- docs/description/S6803.md | 26 +- docs/description/S6930.md | 51 ++-- docs/description/S6931.md | 47 ++-- docs/description/S6932.md | 227 ++++++++++++++++ docs/description/S6934.md | 31 ++- docs/description/S6960.md | 247 ++++++++++++++++++ docs/description/S6961.md | 64 +++++ docs/description/S6962.md | 92 +++++++ docs/description/S6964.md | 121 +++++++++ docs/description/S6965.md | 75 ++++++ docs/description/S6966.md | 65 +++++ docs/description/S6967.md | 88 +++++++ docs/description/S6968.md | 82 ++++++ docs/description/S818.md | 4 +- docs/description/S881.md | 6 +- docs/description/S907.md | 5 +- docs/description/S927.md | 17 +- docs/description/description.json | 69 ++++- docs/patterns.json | 80 +++++- src/Analyzer/Analyzer.csproj | 2 +- src/DocsGenerator/DocsGenerator.csproj | 2 +- 463 files changed, 7398 insertions(+), 3760 deletions(-) create mode 100644 docs/description/S4347.md create mode 100644 docs/description/S5344.md create mode 100644 docs/description/S6377.md create mode 100644 docs/description/S6781.md create mode 100644 docs/description/S6932.md create mode 100644 docs/description/S6960.md create mode 100644 docs/description/S6961.md create mode 100644 docs/description/S6962.md create mode 100644 docs/description/S6964.md create mode 100644 docs/description/S6965.md create mode 100644 docs/description/S6966.md create mode 100644 docs/description/S6967.md create mode 100644 docs/description/S6968.md diff --git a/docs/description/S100.md b/docs/description/S100.md index aad592d..42009b3 100644 --- a/docs/description/S100.md +++ b/docs/description/S100.md @@ -1,9 +1,9 @@ ## Why is this an issue? - + Shared naming conventions allow teams to collaborate efficiently. - + This rule raises an issue when a method or a property name is not PascalCased. - + For example, the method public int doSomething() {...} // Noncompliant @@ -13,7 +13,7 @@ should be renamed to public int DoSomething() {...} ### Exceptions - + - The rule ignores members in types marked with `ComImportAttribute` or `InterfaceTypeAttribute`. - The rule ignores `extern` methods. - To reduce noise, two consecutive upper-case characters are allowed unless they form the full name. So, `MyXMethod` is compliant, but @@ -25,8 +25,8 @@ should be renamed to void My_method(){...} // Compliant by exception ## Resources - + ### Documentation - + [Microsoft Capitalization Conventions](https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/capitalization-conventions) \ No newline at end of file diff --git a/docs/description/S1006.md b/docs/description/S1006.md index 6d2d5d9..0907d3d 100644 --- a/docs/description/S1006.md +++ b/docs/description/S1006.md @@ -1,5 +1,5 @@ ## Why is this an issue? - + [Default arguments](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/named-and-optional-arguments#optional-arguments) are determined by the static type of the object. @@ -20,10 +20,12 @@ arguments](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/cla Base b = new Derived(); b.Run(); // Here the default value of distance is 42, not 5 -If a default argument is different for a parameter in an overriding method, the value used in the call will be different when calls are made via the base or derived object, which may be contrary to developer expectations. - +If a default argument is different for a parameter in an overriding method, the value used in the call will be different when calls are made via +the base or derived object, which may be contrary to developer expectations. + Default parameter values in [explicit interface -implementations](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/interfaces/explicit-interface-implementation) will be never used, because the static type of the object will always be the implemented interface. Thus, specifying default values in this case is confusing. +implementations](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/interfaces/explicit-interface-implementation) will be never used, because the static type of the object will always be the implemented interface. Thus, specifying default +values in this case is confusing. interface IRunner { @@ -111,9 +113,9 @@ implementations](https://learn.microsoft.com/en-us/dotnet/csharp/programming-gui } ## Resources - + ### Documentation - + - [Optional arguments](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/named-and-optional-arguments#optional-arguments) - [Explicit Interface Implementation](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/interfaces/explicit-interface-implementation) \ No newline at end of file diff --git a/docs/description/S101.md b/docs/description/S101.md index 9ee9877..dd92d6a 100644 --- a/docs/description/S101.md +++ b/docs/description/S101.md @@ -1,9 +1,9 @@ ## Why is this an issue? - + Shared naming conventions allow teams to collaborate efficiently. - + This rule raises an issue when a type name is not PascalCased. - + For example, the classes class my_class {...} @@ -15,7 +15,7 @@ should be renamed to class SomeName42 {...} ### Exceptions - + - The rule ignores types marked with `ComImportAttribute` or `InterfaceTypeAttribute`. - To reduce noise, two consecutive upper case characters are allowed unless they form the full type name. So, `MyXClass` is compliant, but `XC` is not. @@ -27,7 +27,7 @@ should be renamed to class Some_Name_XC {...} // Noncompliant because of XC, should be Some_Name_Xc ## Resources - + ### Documentation - [Microsoft Capitalization diff --git a/docs/description/S103.md b/docs/description/S103.md index 991f9f0..1a91d9f 100644 --- a/docs/description/S103.md +++ b/docs/description/S103.md @@ -1,3 +1,3 @@ ## Why is this an issue? - + Scrolling horizontally to see a full line of code lowers the code readability. \ No newline at end of file diff --git a/docs/description/S104.md b/docs/description/S104.md index 4c5794c..890c705 100644 --- a/docs/description/S104.md +++ b/docs/description/S104.md @@ -1,5 +1,6 @@ ## Why is this an issue? - + When a source file grows too much, it can accumulate numerous responsibilities and become challenging to understand and maintain. - -Above a specific threshold, refactor the file into smaller files whose code focuses on well-defined tasks. Those smaller files will be easier to understand and test. \ No newline at end of file + +Above a specific threshold, refactor the file into smaller files whose code focuses on well-defined tasks. Those smaller files will be easier to +understand and test. \ No newline at end of file diff --git a/docs/description/S1048.md b/docs/description/S1048.md index 276a7b9..eb1d2ba 100644 --- a/docs/description/S1048.md +++ b/docs/description/S1048.md @@ -1,15 +1,19 @@ ## Why is this an issue? - -The [finalizers](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/finalizers) are used to perform [any necessary final clean-up](https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/fundamentals#unmanaged-resources) when the garbage collector is collecting a class instance. The programmer has no control over when the finalizer is called; the garbage collector decides when to call it. - -When creating a finalizer, it should never throw an exception, as there is a high risk of having the application terminated leaving unmanaged resources without a graceful cleanup. - + +The [finalizers](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/finalizers) are used to perform +[any necessary final clean-up](https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/fundamentals#unmanaged-resources) when +the garbage collector is collecting a class instance. The programmer has no control over when the finalizer is called; the garbage collector decides +when to call it. + +When creating a finalizer, it should never throw an exception, as there is a high risk of having the application terminated leaving unmanaged +resources without a graceful cleanup. + The rule raises an issue on `throw` statements used in a finalizer. - + ## How to fix it - + ### Code examples - + #### Noncompliant code example class MyClass @@ -31,15 +35,16 @@ The rule raises an issue on `throw` statements used in a finalizer. } ### Going the extra mile - + In general object finalization can be a complex and error-prone operation and should not be implemented except within the [dispose pattern](https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose). - -When [cleaning up unmanaged resources](https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/unmanaged), it is recommended to implement the dispose pattern or, to cover uncalled [`Dispose`](https://learn.microsoft.com/en-us/dotnet/api/system.idisposable.dispose) method by the consumer, implement [`SafeHandle`](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.safehandle). - + +When [cleaning up unmanaged resources](https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/unmanaged), it is +recommended to implement the dispose pattern or, to cover uncalled [`Dispose`](https://learn.microsoft.com/en-us/dotnet/api/system.idisposable.dispose) method by the consumer, implement [`SafeHandle`](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.safehandle). + ## Resources - + ### Documentation - + - Microsoft Learn - [Fundamentals of garbage collection](https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/fundamentals) - Microsoft Learn - [Cleaning up unmanaged resources](https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/unmanaged) diff --git a/docs/description/S105.md b/docs/description/S105.md index 63d21c2..0e8c108 100644 --- a/docs/description/S105.md +++ b/docs/description/S105.md @@ -1,5 +1,6 @@ ## Why is this an issue? - -The tab width can differ from one development environment to another. Using tabs may require other developers to configure their environment (text editor, preferences, etc.) to read source code. - + +The tab width can differ from one development environment to another. Using tabs may require other developers to configure their environment (text +editor, preferences, etc.) to read source code. + That is why using spaces is preferable. \ No newline at end of file diff --git a/docs/description/S106.md b/docs/description/S106.md index a3db319..9faa120 100644 --- a/docs/description/S106.md +++ b/docs/description/S106.md @@ -1,16 +1,18 @@ ## Why is this an issue? - -In software development, logs serve as a record of events within an application, providing crucial insights for debugging. When logging, it is essential to ensure that the logs are: - + +In software development, logs serve as a record of events within an application, providing crucial insights for debugging. When logging, it is +essential to ensure that the logs are: + - easily accessible - uniformly formatted for readability - properly recorded - securely logged when dealing with sensitive data -Those requirements are not met if a program directly writes to the standard outputs (e.g., Console). That is why defining and using a dedicated logger is highly recommended. - +Those requirements are not met if a program directly writes to the standard outputs (e.g., Console). That is why defining and using a dedicated +logger is highly recommended. + ### Exceptions - + The rule doesn’t raise an issue for: - Console Applications @@ -18,7 +20,7 @@ The rule doesn’t raise an issue for: - Calls included in DEBUG preprocessor branches (`#if DEBUG`) ### Code examples - + The following noncompliant code: public class MyClass diff --git a/docs/description/S1066.md b/docs/description/S1066.md index 10ee9cd..ac2336a 100644 --- a/docs/description/S1066.md +++ b/docs/description/S1066.md @@ -1,9 +1,10 @@ ## Why is this an issue? - -Nested code - blocks of code inside blocks of code - is eventually necessary, but increases complexity. This is why keeping the code as flat as possible, by avoiding unnecessary nesting, is considered a good practice. - + +Nested code - blocks of code inside blocks of code - is eventually necessary, but increases complexity. This is why keeping the code as flat as +possible, by avoiding unnecessary nesting, is considered a good practice. + Merging `if` statements when possible will decrease the nesting of the code and improve its readability. - + Code like if (condition1) @@ -22,11 +23,12 @@ Will be more readable as } ## How to fix it - -If merging the conditions seems to result in a more complex code, extracting the condition or part of it in a named function or variable is a better approach to fix readability. - + +If merging the conditions seems to result in a more complex code, extracting the condition or part of it in a named function or variable is a +better approach to fix readability. + ### Code examples - + #### Noncompliant code example if (file != null) diff --git a/docs/description/S1067.md b/docs/description/S1067.md index 331108f..d0ee132 100644 --- a/docs/description/S1067.md +++ b/docs/description/S1067.md @@ -1,11 +1,12 @@ ## Why is this an issue? - -The complexity of an expression is defined by the number of `&&`, `||` and `condition ? ifTrue : ifFalse` operators it contains. - + +The complexity of an expression is defined by the number of `&&`, `||` and `condition ? ifTrue : ifFalse` +operators it contains. + A single expression’s complexity should not become too high to keep the code readable. - + ### Noncompliant code example - + With the default threshold value of 3 if (((condition1 && condition2) || (condition3 && condition4)) && condition5) { ... } diff --git a/docs/description/S107.md b/docs/description/S107.md index d66a45c..e2d19cc 100644 --- a/docs/description/S107.md +++ b/docs/description/S107.md @@ -1,6 +1,7 @@ ## Why is this an issue? - -Methods with a long parameter list are difficult to use because maintainers must figure out the role of each parameter and keep track of their position. + +Methods with a long parameter list are difficult to use because maintainers must figure out the role of each parameter and keep track of their +position. void SetCoordinates(int x1, int y1, int z1, int x2, int y2, int z2) // Noncompliant { @@ -8,7 +9,7 @@ Methods with a long parameter list are difficult to use because maintainers must } The solution can be to: - + - Split the method into smaller ones // Each function does a part of what the original setCoordinates function was doing, so confusion risks are lower @@ -33,11 +34,11 @@ The solution can be to: } This rule raises an issue when a method has more parameters than the provided threshold. - + ### Exceptions - + The rule does not count the parameters intended for a base class constructor. - + With a maximum number of 4 parameters: public class BaseClass diff --git a/docs/description/S1075.md b/docs/description/S1075.md index 4deb38d..b80f81b 100644 --- a/docs/description/S1075.md +++ b/docs/description/S1075.md @@ -1,22 +1,22 @@ ## Why is this an issue? - + Hard-coding a URI makes it difficult to test a program for a variety of reasons: - + - path literals are not always portable across operating systems - a given absolute path may not exist in a specific test environment - a specified Internet URL may not be available when executing the tests - production environment filesystems usually differ from the development environment In addition, hard-coded URIs can contain sensitive information, like IP addresses, and they should not be stored in the code. - + For all those reasons, a URI should never be hard coded. Instead, it should be replaced by a customizable parameter. - + Further, even if the elements of a URI are obtained dynamically, portability can still be limited if the path delimiters are hard-coded. - + This rule raises an issue when URIs or path delimiters are hard-coded. - + ### Exceptions - + This rule does not raise an issue when an ASP.NET virtual path is passed as an argument to one of the following: - methods: `System.Web.HttpServerUtilityBase.MapPath()`, `System.Web.HttpRequestBase.MapPath()`, @@ -25,9 +25,9 @@ This rule does not raise an issue when an ASP.NET virtual path is passed as an a - constructors of: `Microsoft.AspNetCore.Mvc.VirtualFileResult`, `Microsoft.AspNetCore.Routing.VirtualPathData` ## How to fix it - + ### Code examples - + #### Noncompliant code example public class Foo { diff --git a/docs/description/S108.md b/docs/description/S108.md index 2a992f9..c3f43de 100644 --- a/docs/description/S108.md +++ b/docs/description/S108.md @@ -1,11 +1,12 @@ ## Why is this an issue? - -An empty code block is confusing. It will require some effort from maintainers to determine if it is intentional or indicates the implementation is incomplete. + +An empty code block is confusing. It will require some effort from maintainers to determine if it is intentional or indicates the implementation is +incomplete. for (int i = 0; i < 42; i++){} // Noncompliant: is the block empty on purpose, or is code missing? Removing or filling the empty code blocks takes away ambiguity and generally results in a more straightforward and less surprising code. - + ### Exceptions - + The rule ignores code blocks that contain comments. \ No newline at end of file diff --git a/docs/description/S109.md b/docs/description/S109.md index f15a732..d71bf21 100644 --- a/docs/description/S109.md +++ b/docs/description/S109.md @@ -1,13 +1,16 @@ -A magic number is a hard-coded numerical value that may lack context or meaning. They should not be used because they can make the code less readable and maintainable. - +A magic number is a hard-coded numerical value that may lack context or meaning. They should not be used because they can make the code less +readable and maintainable. + ## Why is this an issue? - -Magic numbers make the code more complex to understand as it requires the reader to have knowledge about the global context to understand the number itself. Their usage may seem obvious when writing the code, but it may not be the case for another developer or later once the context faded away. -1, 0, and 1 are not considered magic numbers. - + +Magic numbers make the code more complex to understand as it requires the reader to have knowledge about the global context to understand the +number itself. Their usage may seem obvious when writing the code, but it may not be the case for another developer or later once the context faded +away. -1, 0, and 1 are not considered magic numbers. + ### Exceptions - + This rule doesn’t raise an issue when the magic number is used as part of: - + - the `GetHashCode` method - a variable/field declaration - the single argument of an attribute @@ -16,11 +19,12 @@ This rule doesn’t raise an issue when the magic number is used as part of: - a default value for a method argument ## How to fix it - -Replacing them with a constant allows us to provide a meaningful name associated with the value. Instead of adding complexity to the code, it brings clarity and helps to understand the context and the global meaning. - + +Replacing them with a constant allows us to provide a meaningful name associated with the value. Instead of adding complexity to the code, it +brings clarity and helps to understand the context and the global meaning. + ### Code examples - + #### Noncompliant code example public void DoSomething() diff --git a/docs/description/S110.md b/docs/description/S110.md index e325e93..9bae75e 100644 --- a/docs/description/S110.md +++ b/docs/description/S110.md @@ -1,14 +1,16 @@ ## Why is this an issue? - -Inheritance is one of the most valuable concepts in object-oriented programming. It’s a way to categorize and reuse code by creating collections of attributes and behaviors called classes, which can be based on previously created classes. - -But abusing this concept by creating a deep inheritance tree can lead to complex and unmaintainable source code. Often, an inheritance tree becoming too deep is the symptom of systematic use of "inheritance" when other approaches like "composition" would be better suited. - + +Inheritance is one of the most valuable concepts in object-oriented programming. It’s a way to categorize and reuse code by creating collections of +attributes and behaviors called classes, which can be based on previously created classes. + +But abusing this concept by creating a deep inheritance tree can lead to complex and unmaintainable source code. Often, an inheritance tree +becoming too deep is the symptom of systematic use of "inheritance" when other approaches like "composition" would be better suited. + This rule raises an issue when the inheritance tree, starting from `Object`, has a greater depth than is allowed. - + ## Resources - + ### Documentation - + [Composition over inheritance: difference between composition and inheritance in object-oriented programming](https://en.wikipedia.org/wiki/Composition_over_inheritance) \ No newline at end of file diff --git a/docs/description/S1104.md b/docs/description/S1104.md index dbb170a..c31e5f4 100644 --- a/docs/description/S1104.md +++ b/docs/description/S1104.md @@ -1,31 +1,35 @@ ## Why is this an issue? - + Public fields in public classes do not respect the encapsulation principle and have three main disadvantages: - + - Additional behavior such as validation cannot be added. - The internal representation is exposed, and cannot be changed afterwards. - Member values are subject to change from anywhere in the code and may not meet the programmer’s assumptions. To prevent unauthorized modifications, private attributes and accessor methods (set and get) should be used. - + Note that due to optimizations on simple properties, public fields provide only very little performance gain. - + ### What is the potential impact? - + Public fields can be modified by any part of the code and this can lead to unexpected changes and hard-to-trace bugs. - -Public fields don’t hide the implementation details. As a consequence, it is no longer possible to change how the data is stored internally without impacting the client code of the class. - + +Public fields don’t hide the implementation details. As a consequence, it is no longer possible to change how the data is stored internally without +impacting the client code of the class. + The code is harder to maintain. - + ### Exceptions - + Fields marked as `readonly` or `const` are ignored by this rule. - -Fields inside classes or structs annotated with the `StructLayoutAttribute` are ignored by this rule. - + +Fields inside classes or structs annotated with `[StructLayout]` are ignored by this rule. + +Fields inside classes or structs annotated with `[Serializable]` are ignored by this rule unless they are annotated with +`[NonSerialized]`. + ## How to fix it - + Depending on your needs: - Use auto-implemented properties: @@ -38,7 +42,7 @@ Depending on your needs: - Mark field as `readonly` or `const`. ### Code examples - + #### Noncompliant code example public class Foo @@ -71,9 +75,9 @@ Depending on your needs: } ### Pitfalls - + Please be aware that changing a field by a property in a software that uses serialization could lead to binary incompatibility. - + ## Resources - CWE - [CWE-493 - Critical Public Variable Without Final Modifier](https://cwe.mitre.org/data/definitions/493) \ No newline at end of file diff --git a/docs/description/S1109.md b/docs/description/S1109.md index 22d7658..58a0051 100644 --- a/docs/description/S1109.md +++ b/docs/description/S1109.md @@ -1,7 +1,8 @@ ## Why is this an issue? - -Shared coding conventions make it possible for a team to efficiently collaborate. This rule makes it mandatory to place a close curly brace at the beginning of a line. - + +Shared coding conventions make it possible for a team to efficiently collaborate. This rule makes it mandatory to place a close curly brace at the +beginning of a line. + ### Noncompliant code example if(condition) @@ -16,7 +17,7 @@ Shared coding conventions make it possible for a team to efficiently collaborate } ### Exceptions - + When blocks are inlined (open and close curly braces on the same line), no issue is triggered. if(condition) {doSomething();} \ No newline at end of file diff --git a/docs/description/S1110.md b/docs/description/S1110.md index 57254ea..9768e09 100644 --- a/docs/description/S1110.md +++ b/docs/description/S1110.md @@ -1,11 +1,12 @@ ## Why is this an issue? - + Parentheses can disambiguate the order of operations in complex expressions and make the code easier to understand. a = (b * c) + (d * e); // Compliant: the intent is clear. -Redundant parentheses are parenthesis that do not change the behavior of the code, and do not clarify the intent. They can mislead and complexify the code. They should be removed. - +Redundant parentheses are parenthesis that do not change the behavior of the code, and do not clarify the intent. They can mislead and complexify +the code. They should be removed. + ### Noncompliant code example int x = ((y / 2 + 1)); // Noncompliant diff --git a/docs/description/S1116.md b/docs/description/S1116.md index 9c56cf7..1e2cca5 100644 --- a/docs/description/S1116.md +++ b/docs/description/S1116.md @@ -1,9 +1,11 @@ ## Why is this an issue? - -Empty statements represented by a semicolon `;` are statements that do not perform any operation. They are often the result of a typo or a misunderstanding of the language syntax. It is a good practice to remove empty statements since they don’t add value and lead to confusion and errors. - + +Empty statements represented by a semicolon `;` are statements that do not perform any operation. They are often the result of a typo or +a misunderstanding of the language syntax. It is a good practice to remove empty statements since they don’t add value and lead to confusion and +errors. + ### Code examples - + #### Noncompliant code example void DoSomething() diff --git a/docs/description/S1117.md b/docs/description/S1117.md index b42b7c3..1af05ce 100644 --- a/docs/description/S1117.md +++ b/docs/description/S1117.md @@ -1,18 +1,19 @@ ## Why is this an issue? - + Shadowing occurs when a local variable has the same name as a variable, field, or property in an outer scope. - + This can lead to three main problems: - + - Confusion: The same name can refer to different variables in different parts of the scope, making the code hard to read and understand. - Unintended Behavior: You might accidentally use the wrong variable, leading to hard-to-detect bugs. - Maintenance Issues: If the inner variable is removed or renamed, the code’s behavior might change unexpectedly because the outer variable is now being used. -To avoid these problems, rename the shadowing, shadowed, or both variables/fields/properties to accurately represent their purpose with unique and meaningful names. It improves clarity and allows reasoning locally about the code without considering other software parts. - +To avoid these problems, rename the shadowing, shadowed, or both variables/fields/properties to accurately represent their purpose with unique and +meaningful names. It improves clarity and allows reasoning locally about the code without considering other software parts. + This rule focuses on variables shadowing fields or properties. - + ### Noncompliant code example class Foo @@ -28,7 +29,7 @@ This rule focuses on variables shadowing fields or properties. } ## Resources - + ### Documentation - Microsoft Learn - [Fields](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/fields) diff --git a/docs/description/S1118.md b/docs/description/S1118.md index 263a347..55ff93a 100644 --- a/docs/description/S1118.md +++ b/docs/description/S1118.md @@ -1,15 +1,17 @@ ## Why is this an issue? - -Whenever there are portions of code that are duplicated and do not depend on the state of their container class, they can be centralized inside a "utility class". A utility class is a class that only has static members, hence it should not be instantiated. - + +Whenever there are portions of code that are duplicated and do not depend on the state of their container class, they can be centralized inside a +"utility class". A utility class is a class that only has static members, hence it should not be instantiated. + ## How to fix it - -To prevent the class from being instantiated, you should define a non-public constructor. This will prevent the compiler from implicitly generating a public parameterless constructor. - + +To prevent the class from being instantiated, you should define a non-public constructor. This will prevent the compiler from implicitly generating +a public parameterless constructor. + Alternatively, adding the `static` keyword as class modifier will also prevent it from being instantiated. - + ### Code examples - + #### Noncompliant code example public class StringUtils // Noncompliant: implicit public constructor diff --git a/docs/description/S112.md b/docs/description/S112.md index c74fa24..32c40fc 100644 --- a/docs/description/S112.md +++ b/docs/description/S112.md @@ -1,29 +1,38 @@ This rule raises an issue when a general or reserved exception is thrown. - + ## Why is this an issue? - -Throwing general exceptions such as `Exception`, `SystemException` and `ApplicationException` will have a negative impact on any code trying to catch these exceptions. - -From a consumer perspective, it is generally a best practice to only catch exceptions you intend to handle. Other exceptions should ideally be let to propagate up the stack trace so that they can be dealt with appropriately. When a general exception is thrown, it forces consumers to catch exceptions they do not intend to handle, which they then have to re-throw. - -Besides, when working with a general type of exception, the only way to distinguish between multiple exceptions is to check their message, which is error-prone and difficult to maintain. Legitimate exceptions may be unintentionally silenced and errors may be hidden. - -For instance, if an exception such as `StackOverflowException` is caught and not re-thrown, it may prevent the program from terminating gracefully. - -When throwing an exception, it is therefore recommended to throw the most specific exception possible so that it can be handled intentionally by consumers. - -Additionally, some reserved exceptions should not be thrown manually. Exceptions such as `IndexOutOfRangeException`, `NullReferenceException`, `OutOfMemoryException` or `ExecutionEngineException` will be thrown automatically by the runtime when the corresponding error occurs. Many of them indicate serious errors, which the application may not be able to recover from. It is therefore recommended to avoid throwing them as well as using them as base classes. - + +Throwing general exceptions such as `Exception`, `SystemException` and `ApplicationException` will have a negative +impact on any code trying to catch these exceptions. + +From a consumer perspective, it is generally a best practice to only catch exceptions you intend to handle. Other exceptions should ideally be let +to propagate up the stack trace so that they can be dealt with appropriately. When a general exception is thrown, it forces consumers to catch +exceptions they do not intend to handle, which they then have to re-throw. + +Besides, when working with a general type of exception, the only way to distinguish between multiple exceptions is to check their message, which is +error-prone and difficult to maintain. Legitimate exceptions may be unintentionally silenced and errors may be hidden. + +For instance, if an exception such as `StackOverflowException` is caught and not re-thrown, it may prevent the program from terminating +gracefully. + +When throwing an exception, it is therefore recommended to throw the most specific exception possible so that it can be handled intentionally by +consumers. + +Additionally, some reserved exceptions should not be thrown manually. Exceptions such as `IndexOutOfRangeException`, +`NullReferenceException`, `OutOfMemoryException` or `ExecutionEngineException` will be thrown automatically by the +runtime when the corresponding error occurs. Many of them indicate serious errors, which the application may not be able to recover from. It is +therefore recommended to avoid throwing them as well as using them as base classes. + ## How to fix it - + To fix this issue, make sure to throw specific exceptions that are relevant to the context in which they arise. It is recommended to either: - + - Throw a subtype of `Exception` when one matches. For instance `ArgumentException` could be raised when an unexpected argument is provided to a function. - Define a custom exception type that derives from `Exception` or one of its subclasses. ### Code examples - + #### Noncompliant code example public void DoSomething(object obj) @@ -47,7 +56,7 @@ To fix this issue, make sure to throw specific exceptions that are relevant to t } ## Resources - + ### Standards - CWE - [CWE-397 Declaration of Throws for Generic Exception](https://cwe.mitre.org/data/definitions/397) \ No newline at end of file diff --git a/docs/description/S1121.md b/docs/description/S1121.md index f65cc19..c8c2e4d 100644 --- a/docs/description/S1121.md +++ b/docs/description/S1121.md @@ -1,11 +1,13 @@ ## Why is this an issue? - -A common code smell that can hinder the clarity of source code is making assignments within sub-expressions. This practice involves assigning a value to a variable inside a larger expression, such as within a loop or a conditional statement. - -This practice essentially gives a side-effect to a larger expression, thus making it less readable. This often leads to confusion and potential errors. - + +A common code smell that can hinder the clarity of source code is making assignments within sub-expressions. This practice involves assigning a +value to a variable inside a larger expression, such as within a loop or a conditional statement. + +This practice essentially gives a side-effect to a larger expression, thus making it less readable. This often leads to confusion and potential +errors. + ### Exceptions - + Assignments inside lambda and delegate expressions are allowed. var result = Foo(() => @@ -16,7 +18,7 @@ Assignments inside lambda and delegate expressions are allowed. } The rule also ignores the following patterns: - + - Chained assignments var a = b = c = 10; @@ -34,15 +36,16 @@ The rule also ignores the following patterns: public MyClass Instance => instance ?? (instance = new MyClass()); ## How to fix it - + Making assignments within sub-expressions can hinder the clarity of source code. - -This practice essentially gives a side-effect to a larger expression, thus making it less readable. This often leads to confusion and potential errors. - + +This practice essentially gives a side-effect to a larger expression, thus making it less readable. This often leads to confusion and potential +errors. + Extracting assignments into separate statements is encouraged to keep the code clear and straightforward. - + ### Code examples - + #### Noncompliant code example if (string.IsNullOrEmpty(result = str.Substring(index, length))) // Noncompliant diff --git a/docs/description/S1123.md b/docs/description/S1123.md index c40843c..04d93c9 100644 --- a/docs/description/S1123.md +++ b/docs/description/S1123.md @@ -1,7 +1,8 @@ ## Why is this an issue? - -The `Obsolete` attribute can be applied with or without a message argument. Marking something `Obsolete` without including advice on why it’s obsolete or what to use instead will lead maintainers to waste time trying to figure those things out. - + +The `Obsolete` attribute can be applied with or without a message argument. Marking something `Obsolete` without including +advice on why it’s obsolete or what to use instead will lead maintainers to waste time trying to figure those things out. + ### Noncompliant code example public class Car diff --git a/docs/description/S1125.md b/docs/description/S1125.md index 0fa032a..408be84 100644 --- a/docs/description/S1125.md +++ b/docs/description/S1125.md @@ -1,13 +1,17 @@ ## Why is this an issue? - -A boolean literal can be represented in two different ways: `true` or `false`. They can be combined with logical operators (`!, &&, ||, ==, !=`) to produce logical expressions that represent truth values. However, comparing a boolean literal to a variable or expression that evaluates to a boolean value is unnecessary and can make the code harder to read and understand. The more complex a boolean expression is, the harder it will be for developers to understand its meaning and expected behavior, and it will favour the introduction of new bugs. - + +A boolean literal can be represented in two different ways: `true` or `false`. They can be combined with logical operators +(`!, &&, ||, ==, !=`) to produce logical expressions that represent truth values. However, comparing a boolean literal to a +variable or expression that evaluates to a boolean value is unnecessary and can make the code harder to read and understand. The more complex a +boolean expression is, the harder it will be for developers to understand its meaning and expected behavior, and it will favour the introduction of +new bugs. + ## How to fix it - + Remove redundant boolean literals from expressions to improve readability and make the code more maintainable. - + ### Code examples - + #### Noncompliant code example if (booleanMethod() == true) { /* ... */ } diff --git a/docs/description/S1128.md b/docs/description/S1128.md index b533014..fea7df3 100644 --- a/docs/description/S1128.md +++ b/docs/description/S1128.md @@ -1,19 +1,23 @@ ## Why is this an issue? - -Unnecessary `using` directives refer to importing namespaces, types or creating aliases that are not used or referenced anywhere in the code. - + +Unnecessary `using` directives refer to importing namespaces, types or creating aliases that are not used or referenced anywhere in the +code. + Although they don’t affect the runtime behavior of the application after compilation, removing them will: - + - Improve the readability and maintainability of the code. - Help avoid potential naming conflicts. - Improve the build time, as the compiler has fewer lines to read and fewer types to resolve. - Reduce the number of items the code editor will show for auto-completion, thereby showing fewer irrelevant suggestions. -Starting with C# 10, it’s possible to define [global usings](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-directive#global-modifier) for an entire project. They reduce the need for repetitive namespace inclusions, but can also mask which namespaces are truly necessary for the code at hand. Over-relying on them can lead to less transparent code dependencies, especially for newcomers to the project. - +Starting with C# 10, it’s possible to define [global usings](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-directive#global-modifier) for an entire +project. They reduce the need for repetitive namespace inclusions, but can also mask which namespaces are truly necessary for the code at hand. +Over-relying on them can lead to less transparent code dependencies, especially for newcomers to the project. + ### Exceptions - -The rule will not raise a warning for `global using` directives, even if none of the types of that namespace are used in the project: + +The rule will not raise a warning for `global using` directives, even if none of the types of that namespace are used in the +project: global using System.Net.Sockets; // Compliant by exception @@ -23,11 +27,12 @@ Unnecessary `using` directives are ignored in ASP.NET Core projects in the follo - `_ViewImports.cshtml` ## How to fix it - -While it’s not difficult to remove these unneeded lines manually, modern code editors support the removal of every unnecessary `using` directive with a single click from every file of the project. - + +While it’s not difficult to remove these unneeded lines manually, modern code editors support the removal of every unnecessary `using` +directive with a single click from every file of the project. + ### Code examples - + #### Noncompliant code example using System.IO; @@ -60,7 +65,7 @@ While it’s not difficult to remove these unneeded lines manually, modern code } ## Resources - + ### Documentation - [MSDN - using directives](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-directive) diff --git a/docs/description/S113.md b/docs/description/S113.md index d090100..1219be2 100644 --- a/docs/description/S113.md +++ b/docs/description/S113.md @@ -1,9 +1,9 @@ ## Why is this an issue? - + Some tools work better when files end with an empty line. - + This rule simply generates an issue if it is missing. - + For example, a Git diff looks like this if the empty line is missing at the end of the file: +class Test diff --git a/docs/description/S1133.md b/docs/description/S1133.md index 27778c4..9325c1c 100644 --- a/docs/description/S1133.md +++ b/docs/description/S1133.md @@ -1,7 +1,7 @@ ## Why is this an issue? - + This rule is meant to be used as a way to track code which is marked as being deprecated. Deprecated code should eventually be removed. - + ### Noncompliant code example [Obsolete] // Noncompliant diff --git a/docs/description/S1134.md b/docs/description/S1134.md index 2aea878..e541ddf 100644 --- a/docs/description/S1134.md +++ b/docs/description/S1134.md @@ -1,9 +1,9 @@ ## Why is this an issue? - + `FIXME` tags are commonly used to mark places where a bug is suspected, but which the developer wants to deal with later. - + Sometimes the developer will not have the time or will simply forget to get back to that tag. - + This rule is meant to track those tags and to ensure that they do not go unnoticed. private int Divide(int numerator, int denominator) @@ -12,7 +12,7 @@ This rule is meant to track those tags and to ensure that they do not go unnotic } ## Resources - + ### Documentation - + - CWE - [CWE-546 - Suspicious Comment](https://cwe.mitre.org/data/definitions/546) \ No newline at end of file diff --git a/docs/description/S1135.md b/docs/description/S1135.md index de22819..671c3b9 100644 --- a/docs/description/S1135.md +++ b/docs/description/S1135.md @@ -1,21 +1,29 @@ ## Why is this an issue? - -Developers often use `TODO` tags to mark areas in the code where additional work or improvements are needed but are not implemented immediately. However, these `TODO` tags sometimes get overlooked or forgotten, leading to incomplete or unfinished code. This rule aims to identify and address unattended `TODO` tags to ensure a clean and maintainable codebase. This description explores why this is a problem and how it can be fixed to improve the overall code quality. - + +Developers often use `TODO` tags to mark areas in the code where additional work or improvements are needed but are not implemented +immediately. However, these `TODO` tags sometimes get overlooked or forgotten, leading to incomplete or unfinished code. This rule aims to +identify and address unattended `TODO` tags to ensure a clean and maintainable codebase. This description explores why this is a problem +and how it can be fixed to improve the overall code quality. + ### What is the potential impact? - + Unattended `TODO` tags in code can have significant implications for the development process and the overall codebase. - -Incomplete Functionality: When developers leave `TODO` tags without implementing the corresponding code, it results in incomplete functionality within the software. This can lead to unexpected behavior or missing features, adversely affecting the end-user experience. - -Missed Bug Fixes: If developers do not promptly address `TODO` tags, they might overlook critical bug fixes and security updates. Delayed bug fixes can result in more severe issues and increase the effort required to resolve them later. - -Impact on Collaboration: In team-based development environments, unattended `TODO` tags can hinder collaboration. Other team members might not be aware of the intended changes, leading to conflicts or redundant efforts in the codebase. - -Codebase Bloat: The accumulation of unattended `TODO` tags over time can clutter the codebase and make it difficult to distinguish between work in progress and completed code. This bloat can make it challenging to maintain an organized and efficient codebase. - -Addressing this code smell is essential to ensure a maintainable, readable, reliable codebase and promote effective collaboration among developers. - + +Incomplete Functionality: When developers leave `TODO` tags without implementing the corresponding code, it results in incomplete +functionality within the software. This can lead to unexpected behavior or missing features, adversely affecting the end-user experience. + +Missed Bug Fixes: If developers do not promptly address `TODO` tags, they might overlook critical bug fixes and security updates. +Delayed bug fixes can result in more severe issues and increase the effort required to resolve them later. + +Impact on Collaboration: In team-based development environments, unattended `TODO` tags can hinder collaboration. Other team members +might not be aware of the intended changes, leading to conflicts or redundant efforts in the codebase. + +Codebase Bloat: The accumulation of unattended `TODO` tags over time can clutter the codebase and make it difficult to distinguish +between work in progress and completed code. This bloat can make it challenging to maintain an organized and efficient codebase. + +Addressing this code smell is essential to ensure a maintainable, readable, reliable codebase and promote effective collaboration among +developers. + ### Noncompliant code example private void DoSomething() @@ -24,5 +32,5 @@ Addressing this code smell is essential to ensure a maintainable, readable, reli } ## Resources - + - CWE - [CWE-546 - Suspicious Comment](https://cwe.mitre.org/data/definitions/546) \ No newline at end of file diff --git a/docs/description/S1147.md b/docs/description/S1147.md index 3a461f0..5d09881 100644 --- a/docs/description/S1147.md +++ b/docs/description/S1147.md @@ -1,14 +1,15 @@ ## Why is this an issue? - -Calling `Environment.Exit(exitCode)` or `Application.Exit()` terminates the process and returns an exit code to the operating system.. - + +Calling `Environment.Exit(exitCode)` or `Application.Exit()` terminates the process and returns an exit code to the operating +system.. + Each of these methods should be used with extreme care, and only when the intent is to stop the whole application. - + ### Noncompliant code example Environment.Exit(0); Application.Exit(); ### Exceptions - + These methods are ignored inside `Main`. \ No newline at end of file diff --git a/docs/description/S1151.md b/docs/description/S1151.md index 32f724f..bb949c5 100644 --- a/docs/description/S1151.md +++ b/docs/description/S1151.md @@ -1,9 +1,11 @@ ## Why is this an issue? - -The `switch` statement should be used only to clearly define some new branches in the control flow. As soon as a `case` clause contains too many statements this highly decreases the readability of the overall control flow statement. In such case, the content of the `case` clause should be extracted into a dedicated method. - + +The `switch` statement should be used only to clearly define some new branches in the control flow. As soon as a `case` +clause contains too many statements this highly decreases the readability of the overall control flow statement. In such case, the content of the +`case` clause should be extracted into a dedicated method. + ### Noncompliant code example - + With the default threshold of 8: switch (myVariable) diff --git a/docs/description/S1155.md b/docs/description/S1155.md index 4fbc128..4f35227 100644 --- a/docs/description/S1155.md +++ b/docs/description/S1155.md @@ -1,8 +1,9 @@ ## Why is this an issue? - + When you call `Any()`, it clearly communicates the code’s intention, which is to check if the collection is empty. Using `Count() -== 0` for this purpose is less direct and makes the code slightly more complex. However, there are some cases where special attention should be paid: - +== 0` for this purpose is less direct and makes the code slightly more complex. However, there are some cases where special attention should be +paid: + - if the collection is an `EntityFramework` or other ORM query, calling `Count()` will cause executing a potentially massive SQL query and could put a large overhead on the application database. Calling `Any()` will also connect to the database, but will generate much more efficient SQL. diff --git a/docs/description/S1163.md b/docs/description/S1163.md index f508d24..c084c68 100644 --- a/docs/description/S1163.md +++ b/docs/description/S1163.md @@ -1,6 +1,8 @@ ## Why is this an issue? - -If an exception is already being thrown within the `try` block or caught in a `catch` block, throwing another exception in the `finally` block will override the original exception. This means that the original exception’s message and stack trace will be lost, potentially making it challenging to diagnose and troubleshoot the root cause of the problem. + +If an exception is already being thrown within the `try` block or caught in a `catch` block, throwing another exception in +the `finally` block will override the original exception. This means that the original exception’s message and stack trace will be lost, +potentially making it challenging to diagnose and troubleshoot the root cause of the problem. try { @@ -24,9 +26,9 @@ If an exception is already being thrown within the `try` block or caught in a `c } ## Resources - + ### Documentation - + - [Exceptions and Exception Handling](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/exceptions/) - [Finally blocks](https://learn.microsoft.com/en-us/dotnet/standard/exceptions/how-to-use-finally-blocks) - [How to execute diff --git a/docs/description/S1168.md b/docs/description/S1168.md index 2eebb06..4470470 100644 --- a/docs/description/S1168.md +++ b/docs/description/S1168.md @@ -1,9 +1,10 @@ ## Why is this an issue? - -Returning `null` or `default` instead of an actual collection forces the method callers to explicitly test for null, making the code more complex and less readable. - + +Returning `null` or `default` instead of an actual collection forces the method callers to explicitly test for null, making +the code more complex and less readable. + Moreover, in many cases, `null` or `default` is used as a synonym for empty. - + ### Noncompliant code example public Result[] GetResults() @@ -59,5 +60,5 @@ Moreover, in many cases, `null` or `default` is used as a synonym for empty. public IEnumerable Results => Enumerable.Empty(); ### Exceptions - + Although `string` is a collection, the rule won’t report on it. \ No newline at end of file diff --git a/docs/description/S1172.md b/docs/description/S1172.md index 953d170..c39d2a3 100644 --- a/docs/description/S1172.md +++ b/docs/description/S1172.md @@ -1,13 +1,16 @@ ## Why is this an issue? - -A typical code smell known as unused function parameters refers to parameters declared in a function but not used anywhere within the function’s body. While this might seem harmless at first glance, it can lead to confusion and potential errors in your code. Disregarding the values passed to such parameters, the function’s behavior will be the same, but the programmer’s intention won’t be clearly expressed anymore. Therefore, removing function parameters that are not being utilized is considered best practice. - + +A typical code smell known as unused function parameters refers to parameters declared in a function but not used anywhere within the function’s +body. While this might seem harmless at first glance, it can lead to confusion and potential errors in your code. Disregarding the values passed to +such parameters, the function’s behavior will be the same, but the programmer’s intention won’t be clearly expressed anymore. Therefore, removing +function parameters that are not being utilized is considered best practice. + This rule raises an issue when a `private` method or constructor of a class/struct takes a parameter without using it. - + ### Exceptions - + This rule doesn’t raise any issue in the following contexts: - + - The `this` parameter of extension methods. - Methods decorated with attributes. - Empty methods. @@ -17,11 +20,12 @@ This rule doesn’t raise any issue in the following contexts: - interface implementations. ## How to fix it - -Having unused function parameters in your code can lead to confusion and misunderstanding of a developer’s intention. They reduce code readability and introduce the potential for errors. To avoid these problems, developers should remove unused parameters from function declarations. - + +Having unused function parameters in your code can lead to confusion and misunderstanding of a developer’s intention. They reduce code readability +and introduce the potential for errors. To avoid these problems, developers should remove unused parameters from function declarations. + ### Code examples - + #### Noncompliant code example private void DoSomething(int a, int b) // Noncompliant, "b" is unused diff --git a/docs/description/S1185.md b/docs/description/S1185.md index a4746e5..0449911 100644 --- a/docs/description/S1185.md +++ b/docs/description/S1185.md @@ -1,9 +1,11 @@ ## Why is this an issue? - -Overriding a method just to call the same method from the base class without performing any other actions is useless and misleading. The only time this is justified is in `sealed` overriding methods, where the effect is to lock in the parent class behavior. This rule ignores overrides of `Equals` and `GetHashCode`. - + +Overriding a method just to call the same method from the base class without performing any other actions is useless and misleading. The only time +this is justified is in `sealed` overriding methods, where the effect is to lock in the parent class behavior. This rule ignores overrides +of `Equals` and `GetHashCode`. + NOTE: In some cases it might be dangerous to add or remove empty overrides, as they might be breaking changes. - + ### Noncompliant code example public override void Method() // Noncompliant @@ -19,7 +21,7 @@ NOTE: In some cases it might be dangerous to add or remove empty overrides, as t } ### Exceptions - + If there is an attribute in any level of the overriding chain, then the overridden member is ignored. public class Base diff --git a/docs/description/S1186.md b/docs/description/S1186.md index dc4235b..988fbeb 100644 --- a/docs/description/S1186.md +++ b/docs/description/S1186.md @@ -1,15 +1,16 @@ ## Why is this an issue? - -An empty method is generally considered bad practice and can lead to confusion, readability, and maintenance issues. Empty methods bring no functionality and are misleading to others as they might think the method implementation fulfills a specific and identified requirement. - + +An empty method is generally considered bad practice and can lead to confusion, readability, and maintenance issues. Empty methods bring no +functionality and are misleading to others as they might think the method implementation fulfills a specific and identified requirement. + There are several reasons for a method not to have a body: - + - It is an unintentional omission, and should be fixed to prevent an unexpected behavior in production. - It is not yet, or never will be, supported. In this case an exception should be thrown. - The method is an intentionally-blank override. In this case a nested comment should explain the reason for the blank override. ### Exceptions - + The following empty methods are considered compliant: - empty `virtual` methods as the implementation might not be required in the base class @@ -17,9 +18,9 @@ The following empty methods are considered compliant: - empty overrides in test assemblies for mocking purposes ## How to fix it - + ### Code examples - + #### Noncompliant code example public void ShouldNotBeEmpty() { // Noncompliant - method is empty diff --git a/docs/description/S1192.md b/docs/description/S1192.md index 7485b84..837c038 100644 --- a/docs/description/S1192.md +++ b/docs/description/S1192.md @@ -1,21 +1,23 @@ ## Why is this an issue? - -Duplicated string literals make the process of refactoring complex and error-prone, as any change would need to be propagated on all occurrences. - + +Duplicated string literals make the process of refactoring complex and error-prone, as any change would need to be propagated on all +occurrences. + ### Exceptions - + The following are ignored: - + - literals with fewer than 5 characters - literals matching one of the parameter names - literals used in attributes ## How to fix it - -Use constants to replace the duplicated string literals. Constants can be referenced from many places, but only need to be updated in a single place. - + +Use constants to replace the duplicated string literals. Constants can be referenced from many places, but only need to be updated in a single +place. + ### Code examples - + #### Noncompliant code example public class Foo diff --git a/docs/description/S1199.md b/docs/description/S1199.md index b57c0bd..4a99f63 100644 --- a/docs/description/S1199.md +++ b/docs/description/S1199.md @@ -1,21 +1,22 @@ ## Why is this an issue? - + Nested code blocks create new scopes where variables declared within are inaccessible from the outside, and their lifespan ends with the block. - -Although this may appear beneficial, their usage within a function often suggests that the function is overloaded. Thus, it may violate the Single Responsibility Principle, and the function needs to be broken down into smaller functions. - + +Although this may appear beneficial, their usage within a function often suggests that the function is overloaded. Thus, it may violate the Single +Responsibility Principle, and the function needs to be broken down into smaller functions. + The presence of nested blocks that don’t affect the control flow might suggest possible mistakes in the code. - + ### Exceptions - + The usage of a code block after a `case` is allowed. - + ## How to fix it - + The nested code blocks should be extracted into separate methods. - + ### Code examples - + #### Noncompliant code example public void Evaluate() @@ -48,7 +49,7 @@ The nested code blocks should be extracted into separate methods. } ## Resources - + ### Documentation - + - Wikipedia - [Single Responsibility Principle](https://en.wikipedia.org/wiki/Single-responsibility_principle) \ No newline at end of file diff --git a/docs/description/S1200.md b/docs/description/S1200.md index 0edfc55..4efb1eb 100644 --- a/docs/description/S1200.md +++ b/docs/description/S1200.md @@ -1,7 +1,10 @@ ## Why is this an issue? - -According to the Single Responsibility Principle, introduced by Robert C. Martin in his book "Principles of Object Oriented Design", a class should have only one responsibility: +According to the Single Responsibility Principle, introduced by Robert C. Martin in his book "Principles of Object Oriented Design", a class should +have only one responsibility: + +> +> > If a class has more than one responsibility, then the responsibilities become coupled. > > @@ -9,13 +12,14 @@ According to the Single Responsibility Principle, introduced by Robert C. Martin > > > This kind of coupling leads to fragile designs that break in unexpected ways when changed. +> Classes which rely on many other classes tend to aggregate too many responsibilities and should be split into several smaller ones. - + Nested classes dependencies are not counted as dependencies of the outer class. - + ### Noncompliant code example - + With a threshold of 5: public class Foo // Noncompliant - Foo depends on too many classes: T1, T2, T3, T4, T5, T6 and T7 diff --git a/docs/description/S1206.md b/docs/description/S1206.md index 14a6810..88f1723 100644 --- a/docs/description/S1206.md +++ b/docs/description/S1206.md @@ -1,15 +1,20 @@ ## Why is this an issue? - -Suppose you override [Object.Equals](https://learn.microsoft.com/en-us/dotnet/api/system.object.equals) in a type, you must also override [Object.GetHashCode](https://learn.microsoft.com/en-us/dotnet/api/system.object.gethashcode). If two objects are equal according to the `Equals` method, then calling `GetHashCode` on each of them must yield the same integer. If this is not the case, many collections, such as a [Hashtable](https://learn.microsoft.com/en-us/dotnet/api/system.collections.hashtable) or a [Dictionary](https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.dictionary-2) won’t handle class instances correctly. - -In order to not have unpredictable behavior, `Equals` and `GetHashCode` should be either both inherited, or both overridden. - + +Suppose you override [Object.Equals](https://learn.microsoft.com/en-us/dotnet/api/system.object.equals) in a type, you must also +override [Object.GetHashCode](https://learn.microsoft.com/en-us/dotnet/api/system.object.gethashcode). If two objects are equal according +to the `Equals` method, then calling `GetHashCode` on each of them must yield the same integer. If this is not the case, many +collections, such as a [Hashtable](https://learn.microsoft.com/en-us/dotnet/api/system.collections.hashtable) or a [Dictionary](https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.dictionary-2) won’t handle class instances correctly. + +In order to not have unpredictable behavior, `Equals` and `GetHashCode` should be either both inherited, or both +overridden. + ## How to fix it - -When you override `Equals` then you have to also override `GetHashCode`. You have to override both of them, or simply inherit them. - + +When you override `Equals` then you have to also override `GetHashCode`. You have to override both of them, or simply inherit +them. + ### Code examples - + #### Noncompliant code example class MyClass // Noncompliant: should also override GetHashCode @@ -36,9 +41,9 @@ When you override `Equals` then you have to also override `GetHashCode`. You hav } ## Resources - + ### Documentation - + - CWE - [CWE-581 - Object Model Violation: Just One of Equals and Hashcode Defined](https://cwe.mitre.org/data/definitions/581) - [Object.Equals Method](https://learn.microsoft.com/en-us/dotnet/api/system.object.equals) - [Object.GetHashCode Method](https://learn.microsoft.com/en-us/dotnet/api/system.object.gethashcode) diff --git a/docs/description/S121.md b/docs/description/S121.md index d95e576..3d52992 100644 --- a/docs/description/S121.md +++ b/docs/description/S121.md @@ -1,10 +1,11 @@ Control structures are code statements that impact the program’s control flow (e.g., if statements, for loops, etc.) - + ## Why is this an issue? - + While not technically incorrect, the omission of curly braces can be misleading and may lead to the introduction of errors during maintenance. - -In the following example, the two calls seem to be attached to the `if` statement, but only the first one is, and `CheckSomething` will always be executed: + +In the following example, the two calls seem to be attached to the `if` statement, but only the first one is, and +`CheckSomething` will always be executed: if (condition) // Noncompliant ExecuteSomething(); diff --git a/docs/description/S1210.md b/docs/description/S1210.md index 7010929..03f89b0 100644 --- a/docs/description/S1210.md +++ b/docs/description/S1210.md @@ -1,9 +1,14 @@ ## Why is this an issue? - -When you implement `IComparable` or `IComparable` on a class you should also override `Equals(object)` and overload the comparison operators (`==`, `!=`, `<`, `<=`, `>`, `>=`). That’s because the CLR cannot automatically call your `CompareTo` implementation from `Equals(object)` or from the base comparison operator implementations. Additionally, it is best practice to override `GetHashCode` along with `Equals`. - -This rule raises an issue when a class implements `IComparable` without also overriding `Equals(object)` and the comparison operators. - + +When you implement `IComparable` or `IComparable` on a class you should also override `Equals(object)` +and overload the comparison operators (`==`, `!=`, `<`, `<=`, `>`, +`>=`). That’s because the CLR cannot automatically call your `CompareTo` implementation from `Equals(object)` or +from the base comparison operator implementations. Additionally, it is best practice to override `GetHashCode` along with +`Equals`. + +This rule raises an issue when a class implements `IComparable` without also overriding `Equals(object)` and the comparison +operators. + ### Noncompliant code example public class Foo: IComparable // Noncompliant diff --git a/docs/description/S1215.md b/docs/description/S1215.md index 5d96480..b55bae0 100644 --- a/docs/description/S1215.md +++ b/docs/description/S1215.md @@ -1,11 +1,15 @@ ## Why is this an issue? - -[GC.Collect](https://learn.microsoft.com/en-us/dotnet/api/system.gc.collect) is a method that forces or suggests to the [garbage collector](https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/) to run a collection of objects in the managed heap that are no longer being used and free their memory. - -Calling `GC.Collect` is rarely necessary and can significantly affect application performance. That’s because it is a [tracing garbage collector](https://en.wikipedia.org/wiki/Tracing_garbage_collection) and needs to examine *every object in memory* for cleanup and analyze all reachable objects from every application’s root (static fields, local variables on thread stacks, etc.). - -To perform tracing and memory releasing correctly, the garbage collection [may](https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/latency) need to block all threads currently in execution. That is why, as a general rule, the [performance implications](https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/performance#troubleshoot-performance-issues) of calling `GC.Collect` far outweigh the benefits. - + +[GC.Collect](https://learn.microsoft.com/en-us/dotnet/api/system.gc.collect) is a method that forces or suggests to the [garbage collector](https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/) to run a collection of objects in the managed heap +that are no longer being used and free their memory. + +Calling `GC.Collect` is rarely necessary and can significantly affect application performance. That’s because it is a [tracing garbage collector](https://en.wikipedia.org/wiki/Tracing_garbage_collection) and needs to examine *every object in memory* for +cleanup and analyze all reachable objects from every application’s root (static fields, local variables on thread stacks, etc.). + +To perform tracing and memory releasing correctly, the garbage collection [may](https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/latency) need to block all threads currently in execution. That is +why, as a general rule, the [performance implications](https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/performance#troubleshoot-performance-issues) +of calling `GC.Collect` far outweigh the benefits. + This rule raises an issue when any overload of `Collect` is invoked. static void Main(string[] args) @@ -15,12 +19,13 @@ This rule raises an issue when any overload of `Collect` is invoked. GC.Collect(2, GCCollectionMode.Optimized); // Noncompliant } -There may be exceptions to this rule: for example, you’ve just triggered some event that is unique in the run of your program that caused a lot of long-lived objects to die, and you want to release their memory. - +There may be exceptions to this rule: for example, you’ve just triggered some event that is unique in the run of your program that caused a lot of +long-lived objects to die, and you want to release their memory. + ## Resources - + ### Documentation - + - [Garbage collection](https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/) - [GC.Collect](https://learn.microsoft.com/en-us/dotnet/api/system.gc.collect) - [Garbage collection latency modes](https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/latency) diff --git a/docs/description/S122.md b/docs/description/S122.md index 88a42f8..594e021 100644 --- a/docs/description/S122.md +++ b/docs/description/S122.md @@ -1,5 +1,5 @@ ## Why is this an issue? - + Putting multiple statements on a single line lowers the code readability and makes debugging the code more complex. if (someCondition) DoSomething(); // Noncompliant @@ -12,9 +12,9 @@ Write one statement per line to improve readability. } ### Exceptions - + The rule ignores: - + - block statements - anonymous functions containing a single statement @@ -22,7 +22,7 @@ The rule ignores: Func item1 = o => { var r = false; return r; }; // Noncompliant ## Resources - + ### Documentation - [C# formatting options](https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/csharp-formatting-options) \ No newline at end of file diff --git a/docs/description/S1226.md b/docs/description/S1226.md index 730cf7f..952ba30 100644 --- a/docs/description/S1226.md +++ b/docs/description/S1226.md @@ -1,7 +1,9 @@ ## Why is this an issue? - -While it is technically correct to assign to parameters from within method bodies, doing so before the parameter value is read is likely a bug. Instead, initial values of parameters, caught exceptions, and foreach parameters should be, if not treated as `final`, then at least read before reassignment. - + +While it is technically correct to assign to parameters from within method bodies, doing so before the parameter value is read is likely a bug. +Instead, initial values of parameters, caught exceptions, and foreach parameters should be, if not treated as `final`, then at least read +before reassignment. + ### Noncompliant code example public void DoTheThing(string str, int i, List strings) diff --git a/docs/description/S1227.md b/docs/description/S1227.md index 3bbac65..72234b5 100644 --- a/docs/description/S1227.md +++ b/docs/description/S1227.md @@ -1,9 +1,9 @@ ## Why is this an issue? - + `break;` is an unstructured control flow statement which makes code harder to read. - + Ideally, every loop should have a single termination condition. - + ### Noncompliant code example int i = 0; diff --git a/docs/description/S1244.md b/docs/description/S1244.md index bd7a9b9..40a1f45 100644 --- a/docs/description/S1244.md +++ b/docs/description/S1244.md @@ -1,29 +1,34 @@ ## Why is this an issue? - -Floating point numbers in C# (and in most other programming languages) are not precise. They are a binary approximation of the actual value. This means that even if two floating point numbers appear to be equal, they might not be due to the tiny differences in their binary representation. - + +Floating point numbers in C# (and in most other programming languages) are not precise. They are a binary approximation of the actual value. This +means that even if two floating point numbers appear to be equal, they might not be due to the tiny differences in their binary representation. + Even simple floating point assignments are not simple: float f = 0.100000001f; // 0.1 double d = 0.10000000000000001; // 0.1 (Note: Results may vary based on the compiler and its settings) - -This issue is further compounded by the [non-associative](https://en.wikipedia.org/wiki/Associative_property) nature of floating point arithmetic. The order in which operations are performed can affect the outcome due to the rounding that occurs at each step. Consequently, the outcome of a series of mathematical operations can vary based on the order of operations. - -As a result, using the equality (`==`) or inequality (`!=`) operators with `float` or `double` values is typically a mistake, as it can lead to unexpected behavior. - + +This issue is further compounded by the [non-associative](https://en.wikipedia.org/wiki/Associative_property) nature of floating point +arithmetic. The order in which operations are performed can affect the outcome due to the rounding that occurs at each step. Consequently, the outcome +of a series of mathematical operations can vary based on the order of operations. + +As a result, using the equality (`==`) or inequality (`!=`) operators with `float` or `double` values +is typically a mistake, as it can lead to unexpected behavior. + ## How to fix it - -Consider using a small tolerance value to check if the numbers are "close enough" to be considered equal. This tolerance value, often called `epsilon`, should be chosen based on the specifics of your program. - + +Consider using a small tolerance value to check if the numbers are "close enough" to be considered equal. This tolerance value, often called +`epsilon`, should be chosen based on the specifics of your program. + ### Code examples - + #### Noncompliant code example float myNumber = 3.146f; - if (myNumber == 3.146f) //Noncompliant: due to floating point imprecision, this will likely be false + if (myNumber == 3.146f) // Noncompliant: due to floating point imprecision, this will likely be false { // ... } @@ -49,9 +54,9 @@ Consider using a small tolerance value to check if the numbers are "close enough } ## Resources - + ### Documentation - + - [Floating-Point Arithmetic Complexities](https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html) by David Goldberg - Microsoft Learn - [Floating-point numeric types](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/floating-point-numeric-types#comparing-floating-point-numbers) - Wikipedia - [Associative property](https://en.wikipedia.org/wiki/Associative_property) \ No newline at end of file diff --git a/docs/description/S125.md b/docs/description/S125.md index 7af2d8f..edf5497 100644 --- a/docs/description/S125.md +++ b/docs/description/S125.md @@ -1,5 +1,6 @@ ## Why is this an issue? - -Commented-out code distracts the focus from the actual executed code. It creates a noise that increases maintenance code. And because it is never executed, it quickly becomes out of date and invalid. - + +Commented-out code distracts the focus from the actual executed code. It creates a noise that increases maintenance code. And because it is never +executed, it quickly becomes out of date and invalid. + Commented-out code should be deleted and can be retrieved from source control history if required. \ No newline at end of file diff --git a/docs/description/S126.md b/docs/description/S126.md index eea37c0..f27976b 100644 --- a/docs/description/S126.md +++ b/docs/description/S126.md @@ -1,11 +1,13 @@ ## Why is this an issue? - -This rule applies whenever an `if` statement is followed by one or more `else if` statements; the final `else if` should be followed by an `else` statement. - + +This rule applies whenever an `if` statement is followed by one or more `else if` statements; the final `else if` +should be followed by an `else` statement. + The requirement for a final `else` statement is defensive programming. - -The `else` statement should either take appropriate action or contain a suitable comment as to why no action is taken. This is consistent with the requirement to have a final `default` clause in a `switch` statement. - + +The `else` statement should either take appropriate action or contain a suitable comment as to why no action is taken. This is +consistent with the requirement to have a final `default` clause in a `switch` statement. + ### Noncompliant code example if (x == 0) @@ -33,5 +35,5 @@ The `else` statement should either take appropriate action or contain a suitable } ### Exceptions - + None \ No newline at end of file diff --git a/docs/description/S1264.md b/docs/description/S1264.md index 9ef97de..0f2599c 100644 --- a/docs/description/S1264.md +++ b/docs/description/S1264.md @@ -1,7 +1,8 @@ ## Why is this an issue? - -When only the condition expression is defined in a `for` loop, and the initialization and increment expressions are missing, a `while` loop should be used instead to increase readability. - + +When only the condition expression is defined in a `for` loop, and the initialization and increment expressions are missing, a +`while` loop should be used instead to increase readability. + ### Noncompliant code example for (;condition;) { /*...*/ } diff --git a/docs/description/S127.md b/docs/description/S127.md index b1dcc8c..c8a95f8 100644 --- a/docs/description/S127.md +++ b/docs/description/S127.md @@ -1,21 +1,24 @@ ## Why is this an issue? - -A `for` loop stop condition should test the loop counter against an invariant value (i.e. one that is true at both the beginning and ending of every loop iteration). Ideally, this means that the stop condition is set to a local variable just before the loop begins. - -Stop conditions that are not invariant are slightly less efficient, as well as being difficult to understand and maintain, and likely lead to the introduction of errors in the future. - + +A `for` loop stop condition should test the loop counter against an invariant value (i.e. one that is true at both the beginning and +ending of every loop iteration). Ideally, this means that the stop condition is set to a local variable just before the loop begins. + +Stop conditions that are not invariant are slightly less efficient, as well as being difficult to understand and maintain, and likely lead to the +introduction of errors in the future. + This rule tracks three types of non-invariant stop conditions: - + - When the loop counters are updated in the body of the `for` loop - When the stop condition depend upon a method call - When the stop condition depends on an object property, since such properties could change during the execution of the loop. ## How to fix it - -It’s generally recommended to only update the loop counter in the loop declaration. If skipping elements or iterating at a different pace based on a condition is needed, consider using a while loop or a different structure that better fits the needs. - + +It’s generally recommended to only update the loop counter in the loop declaration. If skipping elements or iterating at a different pace based on +a condition is needed, consider using a while loop or a different structure that better fits the needs. + ### Code examples - + #### Noncompliant code example for (int i = 1; i <= 5; i++) diff --git a/docs/description/S1301.md b/docs/description/S1301.md index 3ec7dc0..74d2e82 100644 --- a/docs/description/S1301.md +++ b/docs/description/S1301.md @@ -1,9 +1,10 @@ ## Why is this an issue? - + `switch` statements and expressions are useful when there are many different cases depending on the value of the same expression. - -When a `switch` statement or expression is simple enough, the code will be more readable with a single `if`, `if-else` or ternary conditional operator. - + +When a `switch` statement or expression is simple enough, the code will be more readable with a single `if`, +`if-else` or ternary conditional operator. + ### Noncompliant code example switch (variable) diff --git a/docs/description/S1309.md b/docs/description/S1309.md index ce33535..65ab4aa 100644 --- a/docs/description/S1309.md +++ b/docs/description/S1309.md @@ -1,7 +1,7 @@ ## Why is this an issue? - + This rule allows you to track the usage of the `SuppressMessage` attributes and `#pragma warning disable` mechanism. - + ### Noncompliant code example [SuppressMessage("", "S100")] diff --git a/docs/description/S131.md b/docs/description/S131.md index 15e3454..e462df5 100644 --- a/docs/description/S131.md +++ b/docs/description/S131.md @@ -1,7 +1,9 @@ ## Why is this an issue? - -The requirement for a final `default` clause is defensive programming. The clause should either take appropriate action, or contain a suitable comment as to why no action is taken. Even when the `switch` covers all current values of an `enum`, a `default` case should still be used because there is no guarantee that the `enum` won’t be extended. - + +The requirement for a final `default` clause is defensive programming. The clause should either take appropriate action, or contain a +suitable comment as to why no action is taken. Even when the `switch` covers all current values of an `enum`, a +`default` case should still be used because there is no guarantee that the `enum` won’t be extended. + ### Noncompliant code example int foo = 42; @@ -31,5 +33,5 @@ The requirement for a final `default` clause is defensive programming. The claus } ## Resources - + - CWE - [CWE-478 - Missing Default Case in Switch Statement](https://cwe.mitre.org/data/definitions/478) \ No newline at end of file diff --git a/docs/description/S1312.md b/docs/description/S1312.md index 1711598..d7e296e 100644 --- a/docs/description/S1312.md +++ b/docs/description/S1312.md @@ -1,7 +1,7 @@ ## Why is this an issue? - + Regardless of the logging framework in use (Microsoft.Extension.Logging, Serilog, Log4net, NLog, …​​), logger fields should be: - + - **private**: this restricts access to the logger from outside the enclosing type (class, struct, record…​). Using any other access modifier would allow other types to use the logger to log messages in the type where it’s defined. - **static**: making the logger field `static` will ensure that the lifetime of the object doesn’t depend on the lifetime @@ -9,8 +9,9 @@ Regardless of the logging framework in use (Microsoft.Extension.Logging, Serilog - **readonly**: marking the field as `readonly` will prevent modifications to the reference of the logger. This ensures that the reference to the logger remains consistent and doesn’t get accidentally reassigned during the lifetime of the enclosing type. -This rule should be activated when [Service Locator Design pattern](https://en.wikipedia.org/wiki/Service_locator_pattern) is followed in place of [Dependency Injection](https://en.wikipedia.org/wiki/Dependency_injection) for logging. - +This rule should be activated when [Service Locator Design pattern](https://en.wikipedia.org/wiki/Service_locator_pattern) is followed +in place of [Dependency Injection](https://en.wikipedia.org/wiki/Dependency_injection) for logging. + The rule supports the most popular logging frameworks: - [Microsoft.Extensions.Logging](https://www.nuget.org/packages/Microsoft.Extensions.Logging) @@ -19,6 +20,10 @@ The rule supports the most popular logging frameworks: - [NLog](https://www.nuget.org/packages/NLog) - [log4net](https://www.nuget.org/packages/log4net) +## How to fix it + +Make the logging field `{private static readonly}`. + ### Noncompliant code example public Logger logger; @@ -28,7 +33,7 @@ The rule supports the most popular logging frameworks: private static readonly Logger logger; ## Resources - + ### Documentation - Microsoft Learn - [Access diff --git a/docs/description/S1313.md b/docs/description/S1313.md index 0565718..18dda59 100644 --- a/docs/description/S1313.md +++ b/docs/description/S1313.md @@ -1,28 +1,35 @@ Hardcoding IP addresses is security-sensitive. It has led in the past to the following vulnerabilities: - + - [CVE-2006-5901](http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2006-5901) - [CVE-2005-3725](http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2005-3725) -Today’s services have an ever-changing architecture due to their scaling and redundancy needs. It is a mistake to think that a service will always have the same IP address. When it does change, the hardcoded IP will have to be modified too. This will have an impact on the product development, delivery, and deployment: +Today’s services have an ever-changing architecture due to their scaling and redundancy needs. It is a mistake to think that a service will always +have the same IP address. When it does change, the hardcoded IP will have to be modified too. This will have an impact on the product development, +delivery, and deployment: - The developers will have to do a rapid fix every time this happens, instead of having an operation team change a configuration file. - It misleads to use the same address in every environment (dev, sys, qa, prod). -Last but not least it has an effect on application security. Attackers might be able to decompile the code and thereby discover a potentially sensitive address. They can perform a Denial of Service attack on the service, try to get access to the system, or try to spoof the IP address to bypass security checks. Such attacks can always be possible, but in the case of a hardcoded IP address solving the issue will take more time, which will increase an attack’s impact. - +Last but not least it has an effect on application security. Attackers might be able to decompile the code and thereby discover a potentially +sensitive address. They can perform a Denial of Service attack on the service, try to get access to the system, or try to spoof the IP address to +bypass security checks. Such attacks can always be possible, but in the case of a hardcoded IP address solving the issue will take more time, which +will increase an attack’s impact. + ## Ask Yourself Whether - + The disclosed IP address is sensitive, e.g.: - Can give information to an attacker about the network topology. - It’s a personal (assigned to an identifiable person) IP address. There is a risk if you answered yes to any of these questions. - + ## Recommended Secure Coding Practices - -Don’t hard-code the IP address in the source code, instead make it configurable with environment variables, configuration files, or a similar approach. Alternatively, if confidentially is not required a domain name can be used since it allows to change the destination quickly without having to rebuild the software. - + +Don’t hard-code the IP address in the source code, instead make it configurable with environment variables, configuration files, or a similar +approach. Alternatively, if confidentially is not required a domain name can be used since it allows to change the destination quickly without having +to rebuild the software. + ## Sensitive Code Example var ip = "192.168.12.42"; @@ -34,7 +41,7 @@ Don’t hard-code the IP address in the source code, instead make it configurabl var address = IPAddress.Parse(ip); ## Exceptions - + No issue is reported for the following cases because they are not considered sensitive: - Loopback addresses 127.0.0.0/8 in CIDR notation (from 127.0.0.0 to 127.255.255.255) diff --git a/docs/description/S134.md b/docs/description/S134.md index 11452ca..defeb0b 100644 --- a/docs/description/S134.md +++ b/docs/description/S134.md @@ -1,15 +1,19 @@ ## Why is this an issue? - -Nested control flow statements `if`, `switch`, `for`, `foreach`, `while`, `do`, and `try` are often key ingredients in creating what’s known as "Spaghetti code". This code smell can make your program difficult to understand and maintain. - -When numerous control structures are placed inside one another, the code becomes a tangled, complex web. This significantly reduces the code’s readability and maintainability, and it also complicates the testing process. - + +Nested control flow statements `if`, `switch`, `for`, `foreach`, `while`, `do`, +and `try` are often key ingredients in creating what’s known as "Spaghetti code". This code smell can make your program difficult to +understand and maintain. + +When numerous control structures are placed inside one another, the code becomes a tangled, complex web. This significantly reduces the code’s +readability and maintainability, and it also complicates the testing process. + ## How to fix it - + ### Code examples - -The following example demonstrates the behavior of the rule with the default threshold of 3 levels of nesting and one of the potential ways to fix the code smell by introducing guard clauses: - + +The following example demonstrates the behavior of the rule with the default threshold of 3 levels of nesting and one of the potential ways to fix +the code smell by introducing guard clauses: + #### Noncompliant code example if (condition1) // Compliant - depth = 1 @@ -58,6 +62,6 @@ The following example demonstrates the behavior of the rule with the default thr } ## Resources - + - [Guard clauses in programming](https://en.wikipedia.org/wiki/Guard_%28computer_science%29) - one of the approaches to reducing the depth of nesting \ No newline at end of file diff --git a/docs/description/S138.md b/docs/description/S138.md index 17983e7..6e2c1f8 100644 --- a/docs/description/S138.md +++ b/docs/description/S138.md @@ -1,9 +1,9 @@ ## Why is this an issue? - + A function that grows too large tends to aggregate too many responsibilities. - + Such functions inevitably become harder to understand and therefore harder to maintain. - + Above a specific threshold, it is strongly advised to refactor into smaller functions which focus on well-defined tasks. - + Those smaller functions will not only be easier to understand, but also probably easier to test. \ No newline at end of file diff --git a/docs/description/S1449.md b/docs/description/S1449.md index 1ccf467..45509c2 100644 --- a/docs/description/S1449.md +++ b/docs/description/S1449.md @@ -1,11 +1,16 @@ ## Why is this an issue? - -`string.ToLower()`, `ToUpper`, `IndexOf`, `LastIndexOf`, and `Compare` are all culture-dependent, as are some (floating point number and `DateTime`-related) calls to `ToString`. Fortunately, all have variants which accept an argument specifying the culture or formatter to use. Leave that argument off and the call will use the system default culture, possibly creating problems with international characters. - -`string.CompareTo()` is also culture specific, but has no overload that takes a culture information, so instead it’s better to use `CompareOrdinal`, or `Compare` with culture. - -Calls without a culture may work fine in the system’s "home" environment, but break in ways that are extremely difficult to diagnose for customers who use different encodings. Such bugs can be nearly, if not completely, impossible to reproduce when it’s time to fix them. - + +`string.ToLower()`, `ToUpper`, `IndexOf`, `LastIndexOf`, and `Compare` are all +culture-dependent, as are some (floating point number and `DateTime`-related) calls to `ToString`. Fortunately, all have +variants which accept an argument specifying the culture or formatter to use. Leave that argument off and the call will use the system default +culture, possibly creating problems with international characters. + +`string.CompareTo()` is also culture specific, but has no overload that takes a culture information, so instead it’s better to use +`CompareOrdinal`, or `Compare` with culture. + +Calls without a culture may work fine in the system’s "home" environment, but break in ways that are extremely difficult to diagnose for customers +who use different encodings. Such bugs can be nearly, if not completely, impossible to reproduce when it’s time to fix them. + ### Noncompliant code example var lowered = someString.ToLower(); //Noncompliant diff --git a/docs/description/S1450.md b/docs/description/S1450.md index cadbacc..d0b7e7c 100644 --- a/docs/description/S1450.md +++ b/docs/description/S1450.md @@ -1,7 +1,8 @@ ## Why is this an issue? - -When the value of a private field is always assigned to in a class' methods before being read, then it is not being used to store class information. Therefore, it should become a local variable in the relevant methods to prevent any misunderstanding. - + +When the value of a private field is always assigned to in a class' methods before being read, then it is not being used to store class +information. Therefore, it should become a local variable in the relevant methods to prevent any misunderstanding. + ### Noncompliant code example public class Foo diff --git a/docs/description/S1451.md b/docs/description/S1451.md index 0d9a558..016d47f 100644 --- a/docs/description/S1451.md +++ b/docs/description/S1451.md @@ -1,11 +1,12 @@ ## Why is this an issue? - + Each source file should start with a header stating file ownership and the license which must be used to distribute the application. - + This rule must be fed with the header text that is expected at the beginning of every file. - -The `headerFormat` must end with an empty line if you want to have an empty line between the file header and the first line for your source file (`using`, `namespace`…​). - + +The `headerFormat` must end with an empty line if you want to have an empty line between the file header and the first line for your +source file (`using`, `namespace`…​). + For example, if you want the source file to look like this // Copyright (c) SonarSource. All Rights Reserved. Licensed under the LGPL License. See License.txt in the project root for license information. diff --git a/docs/description/S1479.md b/docs/description/S1479.md index a61f2ee..581fe28 100644 --- a/docs/description/S1479.md +++ b/docs/description/S1479.md @@ -1,79 +1,127 @@ ## Why is this an issue? - -When [switch](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/selection-statements#the-switch-statement) statements have large sets of case clauses, it is usually an attempt to map two sets of data. A [Dictionary](https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.dictionary-2) should be used instead to make the code more readable and maintainable. - + +When [switch](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/selection-statements#the-switch-statement) +statements have large sets of multi-line `case` clauses, the code becomes hard to read and maintain. + +For example, the [Cognitive Complexity](https://www.sonarsource.com/docs/CognitiveComplexity.pdf) is going to be particularly high. + +In such scenarios, it’s better to refactor the `switch` to only have single-line case clauses. + +When all the `case` clauses of a `switch` statement are single-line, the readability of the code is not affected. Moreover, +`switch` statements with single-line `case` clauses can easily be converted into [`switch` expressions](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/switch-expression), which are +more concise for assignment and avoid the need for `break` statements. + ### Exceptions - -This rule ignores `switch` statements over `Enum` arguments and empty, fall-through cases. - + +This rule ignores: + +- `switch` statements over `Enum` arguments +- fall-through cases +- `return`, `break` and `throw` statements in case clauses + ## How to fix it - -Store all the cases apart from the `default` one in a dictionary and try to get the matching value by calling the [TryGetValue](https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.dictionary-2.trygetvalue) method. - + +Extract the logic of multi-line `case` clauses into separate methods. + ### Code examples - -The example below are using the "Maximum number of case" property set to `4`. - + +The examples below use the "Maximum number of case" property set to `4`. + +Note that from C# 8, you can use [`switch` expression](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/switch-expression). + #### Noncompliant code example - public class TooManyCase + public int MapChar(char ch, int value) { - public int mapValues(char ch) + switch(ch) // Noncompliant { - switch(ch) { // Noncompliant: 5 cases, "default" excluded, more than maximum = 4 - case 'a': - return 1; - case 'b': - case 'c': - return 2; - case 'd': - return 3; - case 'e': - return 4; - case 'f': - case 'g': - case 'h': - return 5; - default: - return 6; - } + case 'a': + return 1; + case 'b': + return 2; + case 'c': + return 3; + // ... + case '-': + if (value > 10) + { + return 42; + } + else if (value < 5 && value > 1) + { + return 21; + } + return 99; + default: + return 1000; } } #### Compliant solution - using System.Collections.Generic; + public int MapChar(char ch, int value) + { + switch(ch) // Compliant: All 5 cases are single line statements + { + case 'a': + return 1; + case 'b': + return 2; + case 'c': + return 3; + // ... + case '-': + return HandleDash(value); + default: + return 1000; + } + } - public class TooManyCase + private int HandleDash(int value) { - Dictionary matching = new Dictionary() + if (value > 10) + { + return 42; + } + else if (value < 5 && value > 1) + { + return 21; + } + return 99; + } + +For this example, a `switch` expression is more concise and clear: + + public int MapChar(char ch, int value) => + ch switch // Compliant { - { 'a', 1 }, - { 'b', 2 }, - { 'c', 2 }, - { 'd', 3 }, - { 'e', 4 }, - { 'f', 5 }, - { 'g', 5 }, - { 'h', 5 } + 'a' => 1, + 'b' => 2, + 'c' => 3, + // ... + '-' => HandleDash(value), + _ => 1000, }; - public int mapValues(char ch) + private int HandleDash(int value) + { + if (value > 10) { - int value; - if (this.matching.TryGetValue(ch, out value)) { - return value; - } else { - return 6; - } + return 42; } + else if (value < 5 && value > 1) + { + return 21; + } + return 99; } ## Resources - + ### Documentation - -- [Dictionary<TKey,TValue> Class](https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.dictionary-2) -- [Dictionary<TKey,TValue>.TryGetValue(TKey, TValue) Method](https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.dictionary-2.trygetvalue) -- [The - `switch` statement](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/selection-statements#the-switch-statement) \ No newline at end of file + +- Sonar - [Cognitive Complexity](https://www.sonarsource.com/docs/CognitiveComplexity.pdf) +- Microsoft Learn - [The + `switch` statement](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/selection-statements#the-switch-statement) +- Microsoft Learn - [C#: Switch + Expression](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/switch-expression) \ No newline at end of file diff --git a/docs/description/S1481.md b/docs/description/S1481.md index 43328e9..9b1d2ea 100644 --- a/docs/description/S1481.md +++ b/docs/description/S1481.md @@ -1,11 +1,13 @@ ## Why is this an issue? - -An unused local variable is a variable that has been declared but is not used anywhere in the block of code where it is defined. It is dead code, contributing to unnecessary complexity and leading to confusion when reading the code. Therefore, it should be removed from your code to maintain clarity and efficiency. - + +An unused local variable is a variable that has been declared but is not used anywhere in the block of code where it is defined. It is dead code, +contributing to unnecessary complexity and leading to confusion when reading the code. Therefore, it should be removed from your code to maintain +clarity and efficiency. + ### What is the potential impact? - + Having unused local variables in your code can lead to several issues: - + - **Decreased Readability**: Unused variables can make your code more difficult to read. They add extra lines and complexity, which can distract from the main logic of the code. - **Misunderstanding**: When other developers read your code, they may wonder why a variable is declared but not used. This can lead @@ -17,10 +19,11 @@ Having unused local variables in your code can lead to several issues: - **Memory Usage**: Although modern compilers are smart enough to ignore unused variables, not all compilers do this. In such cases, unused variables take up memory space, leading to inefficient use of resources. -In summary, unused local variables can make your code less readable, more confusing, and harder to maintain, and they can potentially lead to bugs or inefficient memory use. Therefore, it is best to remove them. - +In summary, unused local variables can make your code less readable, more confusing, and harder to maintain, and they can potentially lead to bugs +or inefficient memory use. Therefore, it is best to remove them. + ### Exceptions - + Unused locally created resources in a `using` statement are not reported. using(var t = new TestTimer()) // t never used, but compliant. @@ -29,11 +32,12 @@ Unused locally created resources in a `using` statement are not reported. } ## How to fix it - -The fix for this issue is straightforward. Once you ensure the unused variable is not part of an incomplete implementation leading to bugs, you just need to remove it. - + +The fix for this issue is straightforward. Once you ensure the unused variable is not part of an incomplete implementation leading to bugs, you +just need to remove it. + ### Code examples - + #### Noncompliant code example public int NumberOfMinutes(int hours) diff --git a/docs/description/S1541.md b/docs/description/S1541.md index d402494..5a822de 100644 --- a/docs/description/S1541.md +++ b/docs/description/S1541.md @@ -1,3 +1,4 @@ ## Why is this an issue? - -The cyclomatic complexity of methods and properties should not exceed a defined threshold. Complex code can perform poorly and will in any case be difficult to understand and therefore to maintain. \ No newline at end of file + +The cyclomatic complexity of methods and properties should not exceed a defined threshold. Complex code can perform poorly and will in any case be +difficult to understand and therefore to maintain. \ No newline at end of file diff --git a/docs/description/S1607.md b/docs/description/S1607.md index 6940808..47b78c1 100644 --- a/docs/description/S1607.md +++ b/docs/description/S1607.md @@ -1,9 +1,12 @@ ## Why is this an issue? - -When a test fails due, for example, to infrastructure issues, you might want to ignore it temporarily. But without some kind of notation about why the test is being ignored, it may never be reactivated. Such tests are difficult to address without comprehensive knowledge of the project, and end up polluting their projects. - -This rule raises an issue for each ignored test that does not have a `WorkItem` attribute nor a comment about why it is being skipped on the right side of the `Ignore` attribute. - + +When a test fails due, for example, to infrastructure issues, you might want to ignore it temporarily. But without some kind of notation about why +the test is being ignored, it may never be reactivated. Such tests are difficult to address without comprehensive knowledge of the project, and end up +polluting their projects. + +This rule raises an issue for each ignored test that does not have a `WorkItem` attribute nor a comment about why it is being skipped on +the right side of the `Ignore` attribute. + ### Noncompliant code example [TestMethod] @@ -33,8 +36,8 @@ or } ### Exceptions - + The rule doesn’t raise an issue if: - + - the test method is also marked with `WorkItem` attribute - there is a comment on the right side of the `Ignore` attribute \ No newline at end of file diff --git a/docs/description/S1643.md b/docs/description/S1643.md index 101e23e..a0fa902 100644 --- a/docs/description/S1643.md +++ b/docs/description/S1643.md @@ -1,7 +1,7 @@ ## Why is this an issue? - + `StringBuilder` is more efficient than string concatenation, especially when the operator is repeated over and over as in loops. - + ### Noncompliant code example string str = ""; diff --git a/docs/description/S1656.md b/docs/description/S1656.md index 7d27f2c..5f0360c 100644 --- a/docs/description/S1656.md +++ b/docs/description/S1656.md @@ -1,12 +1,12 @@ ## Why is this an issue? - + Re-assigning a variable to itself is a defect as it has no actual effect and indicates meaning to do something else. It usually means that: - + - The statement is redundant and should be removed - The re-assignment is a mistake, and another value or variable was intended for the assignment instead ### Code examples - + #### Noncompliant code example public class Choice { @@ -30,7 +30,7 @@ Re-assigning a variable to itself is a defect as it has no actual effect and ind } ## Resources - + ### Documentation - Microsoft Learn - [Compiler Warning (level 3) CS1717](https://learn.microsoft.com/en-us/dotnet/csharp/misc/cs1717) \ No newline at end of file diff --git a/docs/description/S1659.md b/docs/description/S1659.md index 69a3e56..1fa19c3 100644 --- a/docs/description/S1659.md +++ b/docs/description/S1659.md @@ -1,7 +1,7 @@ ## Why is this an issue? - + Declaring multiple variable on one line is difficult to read. - + ### Noncompliant code example class MyClass diff --git a/docs/description/S1694.md b/docs/description/S1694.md index 32a2ceb..71522a3 100644 --- a/docs/description/S1694.md +++ b/docs/description/S1694.md @@ -1,55 +1,34 @@ +A `class` with only `abstract` methods and no inheritable behavior should be converted to an [`interface`](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/interfaces/). + ## Why is this an issue? - -The purpose of an abstract class is to provide some heritable behaviors while also defining methods which must be implemented by sub-classes. - -A `class` with no abstract methods that was made `abstract` purely to prevent instantiation should be converted to a concrete `class` (i.e. remove the `abstract` keyword) with a `protected` constructor. - -A `class` with only `abstract` methods and no inheritable behavior should be converted to an `interface`. - -### Noncompliant code example - - public abstract class Animal //Noncompliant; should be an interface - { - abstract void Move(); - abstract void Feed(); - } - - public abstract class Color //Noncompliant; should be concrete with a protected constructor - { - private int red = 0; - private int green = 0; - private int blue = 0; - - public int GetRed() - { - return red; - } - } -### Compliant solution +The purpose of an [`abstract` +class](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/abstract-and-sealed-classes-and-class-members) is to provide some overridable behaviors while also defining methods that are required to be implemented by sub-classes. - public interface Animal - { - void Move(); - void Feed(); - } - - public class Color - { - private int red = 0; - private int green = 0; - private int blue = 0; - - protected Color() - {} - - public int GetRed() - { - return red; - } - } - - public abstract class Lamp +A class that contains only `abstract` methods, often called pure abstract class, is effectively an interface, but with the disadvantage +of not being able to be implemented by multiple classes. + +Using interfaces over pure abstract classes presents multiple advantages: + +- [**Multiple Inheritance**](https://en.wikipedia.org/wiki/Multiple_inheritance): Unlike classes, an interface doesn’t + count towards the single inheritance limit in C#. This means a class can implement multiple interfaces, which can be useful when you need to define + behavior that can be shared across multiple classes. +- [**Loose Coupling**](https://en.wikipedia.org/wiki/Loose_coupling#In_programming): Interfaces provide a way to achieve + loose coupling between classes. This is because an interface only specifies what methods a class must have, but not how they are implemented. This + makes it easier to swap out implementations without changing the code that uses them. +- [**Polymorphism**](https://en.wikipedia.org/wiki/Polymorphism_%28computer_science%29): Interfaces allow you to use + polymorphism, which means you can use an interface type to refer to any object that implements that interface. This can be useful when you want to + write code that can work with any class that implements a certain interface, *without knowing what the actual class is*. +- [**Design by contract**](https://en.wikipedia.org/wiki/Design_by_contract): Interfaces provide a clear contract of what + a class should do, without specifying how it should do it. This makes it easier to understand the intended behavior of a class, and to ensure that + different implementations of an interface are consistent with each other. + +### Exceptions + +`abstract` classes that contain non-abstract methods, in addition to `abstract` ones, cannot easily be converted to +interfaces, and are not the subject of this rule: + + public abstract class Lamp // Compliant: Glow is abstract, but FlipSwitch is not { private bool switchLamp = false; @@ -63,4 +42,52 @@ A `class` with only `abstract` methods and no inheritable behavior should be con Glow(); } } - } \ No newline at end of file + } + +Notice that, since C# 8.0, you can also define [default implementations for +interface methods](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-8.0/default-interface-methods), which is yet another reason to prefer interfaces over abstract classes when you don’t need to provide any inheritable +behavior. + +However, interfaces cannot have fields (such as `switchLamp` in the example above), and that remains true even in C# 8.0 and upwards. +This can be a valid reason to still prefer an abstract class over an interface. + +## How to fix it + +Convert the `abstract` class to an `interface` with the same methods. + +### Code examples + +#### Noncompliant code example + + public abstract class Animal // Noncompliant: should be an interface + { + public abstract void Move(); + public abstract void Feed(); + } + +### Compliant solution + + public interface Animal + { + void Move(); + void Feed(); + } + +## Resources + +### Documentation + +- Microsoft Learn - [Abstract + and Sealed Classes and Class Members (C# Programming Guide)](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/abstract-and-sealed-classes-and-class-members) +- Microsoft Learn - [Interfaces - define behavior for + multiple types](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/interfaces/) +- Microsoft Learn - [Default Interface + Methods](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-8.0/default-interface-methods) +- Microsoft Learn - [Tutorial: Update + interfaces with default interface methods](https://learn.microsoft.com/en-us/dotnet/csharp/advanced-topics/interface-implementation/default-interface-methods-versions) +- Microsoft Learn - [Inheritance - derive types + to create more specialized behavior](https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/object-oriented/inheritance) +- Wikipedia - [Multiple Inheritance](https://en.wikipedia.org/wiki/Multiple_inheritance) +- Wikipedia - [Loose Coupling - In programming](https://en.wikipedia.org/wiki/Loose_coupling#In_programming) +- Wikipedia - [Polymorphism (computer science)](https://en.wikipedia.org/wiki/Polymorphism_%28computer_science%29) +- Wikipedia - [Design by contract](https://en.wikipedia.org/wiki/Design_by_contract) \ No newline at end of file diff --git a/docs/description/S1696.md b/docs/description/S1696.md index 0864a65..f641155 100644 --- a/docs/description/S1696.md +++ b/docs/description/S1696.md @@ -1,13 +1,17 @@ ## Why is this an issue? - -Catching `NullReferenceException` is generally considered a bad practice because it can hide bugs in your code. Instead of catching this exception, you should aim to prevent it. This makes your code more robust and easier to understand. In addition, constantly catching and handling `NullReferenceException` can lead to performance issues. Exceptions are expensive in terms of system resources, so they should be used cautiously and only for exceptional conditions, not for regular control flow. - + +Catching `NullReferenceException` is generally considered a bad practice because it can hide bugs in your code. Instead of catching this +exception, you should aim to prevent it. This makes your code more robust and easier to understand. In addition, constantly catching and handling +`NullReferenceException` can lead to performance issues. Exceptions are expensive in terms of system resources, so they should be used +cautiously and only for exceptional conditions, not for regular control flow. + ## How to fix it - -Instead of catching NullReferenceException, it’s better to prevent it from happening in the first place. You can do this by using null checks or null conditional operators (`?.`) before accessing members of an object. - + +Instead of catching NullReferenceException, it’s better to prevent it from happening in the first place. You can do this by using null checks or +null conditional operators (`?.`) before accessing members of an object. + ### Code examples - + #### Noncompliant code example public int GetLengthPlusTwo(string str) @@ -34,9 +38,9 @@ Instead of catching NullReferenceException, it’s better to prevent it from hap } ## Resources - + ### Documentation - + - CWE - [CWE-395 - Use of NullPointerException Catch to Detect NULL Pointer Dereference](https://cwe.mitre.org/data/definitions/395) - Microsoft Learn - [NullReferenceException class](https://learn.microsoft.com/en-us/dotnet/api/system.nullreferenceexception) - Microsoft Learn - [Null-conditional operators ?. and ?\[\]](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/member-access-operators#null-conditional-operators--and-) \ No newline at end of file diff --git a/docs/description/S1698.md b/docs/description/S1698.md index 19f3e7b..ac3f29d 100644 --- a/docs/description/S1698.md +++ b/docs/description/S1698.md @@ -1,7 +1,11 @@ ## Why is this an issue? - -Using the equality `==` and inequality `!=` operators to compare two objects generally works. The operators can be overloaded, and therefore the comparison can resolve to the appropriate method. However, when the operators are used on interface instances, then `==` resolves to reference equality, which may result in unexpected behavior if implementing classes override `Equals`. Similarly, when a class overrides `Equals`, but instances are compared with non-overloaded `==`, there is a high chance that value comparison was meant instead of the reference one. - + +Using the equality `==` and inequality `!=` operators to compare two objects generally works. The operators can be +overloaded, and therefore the comparison can resolve to the appropriate method. However, when the operators are used on interface instances, then +`==` resolves to reference equality, which may result in unexpected behavior if implementing classes override `Equals`. +Similarly, when a class overrides `Equals`, but instances are compared with non-overloaded `==`, there is a high chance that +value comparison was meant instead of the reference one. + ### Noncompliant code example public interface IMyInterface @@ -53,12 +57,13 @@ Using the equality `==` and inequality `!=` operators to compare two objects gen } ### Exceptions - + The rule does not report on comparisons of `System.Type` instances and on comparisons inside `Equals` overrides. - -It also does not raise an issue when one of the operands is `null` nor when one of the operand is cast to `object` (because in this case we want to ensure reference equality even if some `==` overload is present). - + +It also does not raise an issue when one of the operands is `null` nor when one of the operand is cast to `object` (because +in this case we want to ensure reference equality even if some `==` overload is present). + ## Resources - + - CWE - [CWE-595 - Comparison of Object References Instead of Object Contents](https://cwe.mitre.org/data/definitions/595) - CWE - [CWE-597 - Use of Wrong Operator in String Comparison](https://cwe.mitre.org/data/definitions/597) \ No newline at end of file diff --git a/docs/description/S1699.md b/docs/description/S1699.md index d1d84a9..a1b0f25 100644 --- a/docs/description/S1699.md +++ b/docs/description/S1699.md @@ -1,11 +1,17 @@ ## Why is this an issue? - -Calling an overridable method from a constructor could result in failures or strange behaviors when instantiating a subclass which overrides the method. - -When constructing an object of a derived class, the constructor of the parent class is invoked first, and only then the constructor of the derived class is called. This sequential construction process applies to multiple levels of inheritance as well, starting from the base class and progressing to the most derived class. - -If an overridable method is called within the constructor of the parent class, it may inadvertently invoke an overridden implementation in the derived class. This can lead to unexpected failures or strange behaviors because the object’s construction is still in progress and may not have reached a fully initialized state. Consequently, the overridden method may rely on uninitialized members or have assumptions about the object’s state that are not yet valid. - + +Calling an overridable method from a constructor could result in failures or strange behaviors when instantiating a subclass which overrides the +method. + +When constructing an object of a derived class, the constructor of the parent class is invoked first, and only then the constructor of the derived +class is called. This sequential construction process applies to multiple levels of inheritance as well, starting from the base class and progressing +to the most derived class. + +If an overridable method is called within the constructor of the parent class, it may inadvertently invoke an overridden implementation in the +derived class. This can lead to unexpected failures or strange behaviors because the object’s construction is still in progress and may not have +reached a fully initialized state. Consequently, the overridden method may rely on uninitialized members or have assumptions about the object’s state +that are not yet valid. + For example: public class Parent @@ -43,7 +49,7 @@ For example: initialized yet. ## Resources - + ### Documentation - [Constructors](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/constructors) diff --git a/docs/description/S1751.md b/docs/description/S1751.md index d05ab6e..f8d3934 100644 --- a/docs/description/S1751.md +++ b/docs/description/S1751.md @@ -1,23 +1,25 @@ ## Why is this an issue? - -A [loop statement](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/iteration-statements) with at most one iteration is equivalent to an `if` statement; the following block is executed only once. - -If the initial intention was to conditionally execute the block only once, an `if` statement should be used instead. If that was not the initial intention, the block of the loop should be fixed so the block is executed multiple times. - + +A [loop statement](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/iteration-statements) with at most one +iteration is equivalent to an `if` statement; the following block is executed only once. + +If the initial intention was to conditionally execute the block only once, an `if` statement should be used instead. If that was not the +initial intention, the block of the loop should be fixed so the block is executed multiple times. + A loop statement with at most one iteration can happen when a statement unconditionally transfers control, such as a [jump statement](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/jump-statements) or a [throw statement](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/exception-handling-statements#the-throw-statement), is misplaced inside the loop block. - + This rule raises when the following statements are misplaced: - + - [`break`](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/jump-statements#the-break-statement) - [`continue`](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/jump-statements#the-continue-statement) - [`return`](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/jump-statements#the-return-statement) - [`throw`](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/exception-handling-statements#the-throw-statement) ## How to fix it - + ### Code examples - + #### Noncompliant code example public object Method(IEnumerable items) @@ -53,7 +55,7 @@ This rule raises when the following statements are misplaced: } ## Resources - + ### Documentation - Microsoft Learn - [Iteration diff --git a/docs/description/S1764.md b/docs/description/S1764.md index c799549..6b39117 100644 --- a/docs/description/S1764.md +++ b/docs/description/S1764.md @@ -1,9 +1,11 @@ ## Why is this an issue? - -Using the same value on both sides of certain operators is a code defect. In the case of logical operators, it is either a copy/paste error and, therefore, a bug, or it is simply duplicated code and should be simplified. For bitwise operators and most binary mathematical operators, having the same value on both sides of an operator yields predictable results and should be simplified as well to avoid further code defects. - + +Using the same value on both sides of certain operators is a code defect. In the case of logical operators, it is either a copy/paste error and, +therefore, a bug, or it is simply duplicated code and should be simplified. For bitwise operators and most binary mathematical operators, having the +same value on both sides of an operator yields predictable results and should be simplified as well to avoid further code defects. + This rule raises for the following operators. - + - [Equality operators](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/equality-operators) (`==` and `!=`) - [Comparison operators](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/comparison-operators) @@ -24,7 +26,7 @@ This rule raises for the following operators. - Divide assignment operator (`\=`) ### Exceptions - + This rule ignores the following operators: - Multiplication (\*) @@ -36,7 +38,7 @@ This rule ignores the following operators: (>>)](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-and-shift-operators#right-shift-operator-) ### Code examples - + #### Noncompliant code example if ( a == a ) // always true @@ -63,7 +65,7 @@ This rule ignores the following operators: Object.Equals(c, c); // always true ## Resources - + ### Documentation - [Arithmetic Operators](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/arithmetic-operators) diff --git a/docs/description/S1821.md b/docs/description/S1821.md index 22d0faa..f65a85b 100644 --- a/docs/description/S1821.md +++ b/docs/description/S1821.md @@ -1,5 +1,7 @@ ## Why is this an issue? - -Nested `switch` structures are difficult to understand because you can easily confuse the cases of an inner `switch` as belonging to an outer statement. Therefore nested `switch` statements should be avoided. - -Specifically, you should structure your code to avoid the need for nested `switch` statements, but if you cannot, then consider moving the inner `switch` to another function. \ No newline at end of file + +Nested `switch` structures are difficult to understand because you can easily confuse the cases of an inner `switch` as +belonging to an outer statement. Therefore nested `switch` statements should be avoided. + +Specifically, you should structure your code to avoid the need for nested `switch` statements, but if you cannot, then consider moving +the inner `switch` to another function. \ No newline at end of file diff --git a/docs/description/S1848.md b/docs/description/S1848.md index 53bd10c..c15befe 100644 --- a/docs/description/S1848.md +++ b/docs/description/S1848.md @@ -1,13 +1,13 @@ ## Why is this an issue? - + Creating objects that are not used is a vulnerability that can lead to unexpected behavior. - + If this was done intentionally due to side effects in the object’s constructor, the code should be moved to a dedicated method. - + ## How to fix it - + ### Code examples - + #### Noncompliant code example public void Method(MyObject myObject) diff --git a/docs/description/S1854.md b/docs/description/S1854.md index 05eecbe..078c5af 100644 --- a/docs/description/S1854.md +++ b/docs/description/S1854.md @@ -1,11 +1,14 @@ ## Why is this an issue? - -Dead stores refer to assignments made to local variables that are subsequently never used or immediately overwritten. Such assignments are unnecessary and don’t contribute to the functionality or clarity of the code. They may even negatively impact performance. Removing them enhances code cleanliness and readability. Even if the unnecessary operations do not do any harm in terms of the program’s correctness, they are - at best - a waste of computing resources. - + +Dead stores refer to assignments made to local variables that are subsequently never used or immediately overwritten. Such assignments are +unnecessary and don’t contribute to the functionality or clarity of the code. They may even negatively impact performance. Removing them enhances code +cleanliness and readability. Even if the unnecessary operations do not do any harm in terms of the program’s correctness, they are - at best - a waste +of computing resources. + ### Exceptions - + No issue is reported when - + - the analyzed method body contains `try` blocks - a lambda expression captures the local variable - the variable is unused (case covered by Rule {rule:csharpsquid:S1481}) @@ -13,13 +16,15 @@ No issue is reported when `""` or `string.Empty` ## How to fix it - -Remove the unnecesarry assignment, then test the code to make sure that the right-hand side of a given assignment had no side effects (e.g. a method that writes certain data to a file and returns the number of written bytes). - -You can also use [discards](https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/functional/discards) (rather than a variable) to express that result of a method call is ignored on purpose. - + +Remove the unnecesarry assignment, then test the code to make sure that the right-hand side of a given assignment had no side effects (e.g. a +method that writes certain data to a file and returns the number of written bytes). + +You can also use [discards](https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/functional/discards) (rather than a variable) +to express that result of a method call is ignored on purpose. + ### Code examples - + #### Noncompliant code example int Foo(int y) @@ -39,7 +44,7 @@ You can also use [discards](https://learn.microsoft.com/en-us/dotnet/csharp/fund } ## Resources - + ### Standards - CWE - [CWE-563 - Assignment to Variable without Use ('Unused Variable')](https://cwe.mitre.org/data/definitions/563) diff --git a/docs/description/S1858.md b/docs/description/S1858.md index bb3fcb2..af8b39a 100644 --- a/docs/description/S1858.md +++ b/docs/description/S1858.md @@ -1,9 +1,10 @@ ## Why is this an issue? - -Invoking a method designed to return a string representation of an object which is already a string is a waste of keystrokes. Similarly, explicitly invoking `ToString()` when the compiler would do it implicitly is also needless code-bloat. - + +Invoking a method designed to return a string representation of an object which is already a string is a waste of keystrokes. Similarly, explicitly +invoking `ToString()` when the compiler would do it implicitly is also needless code-bloat. + This rule raises an issue when `ToString()` is invoked: - + - on a `string` - on a non-`string` operand to concatenation - on an argument to `string.Format` @@ -25,7 +26,7 @@ This rule raises an issue when `ToString()` is invoked: var v = string.Format("{0}", someObject); ### Exceptions - + The rule does not report on value types, where leaving off the `ToString()` call would result in automatic boxing. var v = string.Format("{0}", 1.ToString()); \ No newline at end of file diff --git a/docs/description/S1862.md b/docs/description/S1862.md index 2d23fde..aac6108 100644 --- a/docs/description/S1862.md +++ b/docs/description/S1862.md @@ -1,14 +1,16 @@ ## Why is this an issue? - + A chain of [if/else -if](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/selection-statements#the-if-statement) statements is evaluated from top to bottom. At most, only one branch will be executed: the first statement with a condition that evaluates to `true`. Therefore, duplicating a condition leads to unreachable code inside the duplicated condition block. Usually, this is due to a copy/paste error. - +if](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/selection-statements#the-if-statement) statements is evaluated from top to bottom. At most, only one branch will be executed: the first statement with a condition that evaluates to +`true`. Therefore, duplicating a condition leads to unreachable code inside the duplicated condition block. Usually, this is due to a +copy/paste error. + The result of such duplication can lead to unreachable code or even to unexpected behavior. - + ## How to fix it - + ### Code examples - + #### Noncompliant code example if (param == 1) @@ -40,8 +42,8 @@ The result of such duplication can lead to unreachable code or even to unexpecte } ## Resources - + ### Documentation - + - [The if statement](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/selection-statements#the-if-statement) \ No newline at end of file diff --git a/docs/description/S1871.md b/docs/description/S1871.md index 3c0859d..32ad048 100644 --- a/docs/description/S1871.md +++ b/docs/description/S1871.md @@ -1,8 +1,10 @@ ## Why is this an issue? - -When the same code is duplicated in two or more separate branches of a conditional, it can make the code harder to understand, maintain, and can potentially introduce bugs if one instance of the code is changed but others are not. - -Having two `cases` in a `switch` statement or two branches in an `if` chain with the same implementation is at best duplicate code, and at worst a coding error. + +When the same code is duplicated in two or more separate branches of a conditional, it can make the code harder to understand, maintain, and can +potentially introduce bugs if one instance of the code is changed but others are not. + +Having two `cases` in a `switch` statement or two branches in an `if` chain with the same implementation is at +best duplicate code, and at worst a coding error. if (a >= 0 && a < 10) { @@ -37,7 +39,7 @@ Having two `cases` in a `switch` statement or two branches in an `if` chain with } If the same logic is truly needed for both instances, then: - + - in an `if` chain they should be combined if ((a >= 0 && a < 10) || (a >= 20 && a < 50)) @@ -67,8 +69,9 @@ If the same logic is truly needed for both instances, then: } ### Exceptions - -Blocks in an `if` chain that contain a single line of code are ignored, as are blocks in a `switch` statement that contain a single line of code with or without a following `break`. + +The rule does not raise an issue for blocks in an `if` chain that contain a single line of code. The same applies to blocks in a +`switch` statement that contain a single line of code with or without a following `break`. if (a >= 0 && a < 10) { @@ -83,19 +86,20 @@ Blocks in an `if` chain that contain a single line of code are ignored, as are b DoTheThing(); } -But this exception does not apply to `if` chains without `else`-s, or to `switch`-es without default clauses when all branches have the same single line of code. In the case of `if` chains with `else`-s, or of `switch`-es with default clauses, rule {rule:csharpsquid:S3923} raises a bug. +However, this exception does not apply to `if` chains without an `else` statement or to a `switch` statement +without a `default` clause. - if(a == 1) + if (a == 1) { - doSomething(); //Noncompliant, this might have been done on purpose but probably not + DoSomething(); // Noncompliant, this might have been done on purpose but probably not } else if (a == 2) { - doSomething(); + DoSomething(); } ## Resources - + ### Related rules - {rule:csharpsquid:S3923} - All branches in a conditional structure should not have exactly the same implementation \ No newline at end of file diff --git a/docs/description/S1905.md b/docs/description/S1905.md index b87577b..7689c2d 100644 --- a/docs/description/S1905.md +++ b/docs/description/S1905.md @@ -1,27 +1,30 @@ ## Why is this an issue? - -Casting expressions are utilized to convert one data type to another, such as transforming an integer into a string. This is especially crucial in strongly typed languages like C, C++, C#, Java, Python, and others. - + +Casting expressions are utilized to convert one data type to another, such as transforming an integer into a string. This is especially crucial in +strongly typed languages like C, C++, C#, Java, Python, and others. + However, there are instances where casting expressions are not needed. These include situations like: - + - casting a variable to its own type - casting a subclass to a parent class (in the case of polymorphism) - the programming language is capable of automatically converting the given type to another -These scenarios are considered unnecessary casting expressions. They can complicate the code and make it more difficult to understand, without offering any advantages. - -As a result, it’s generally advised to avoid unnecessary casting expressions. Instead, rely on the language’s type system to ensure type safety and code clarity. - +These scenarios are considered unnecessary casting expressions. They can complicate the code and make it more difficult to understand, without +offering any advantages. + +As a result, it’s generally advised to avoid unnecessary casting expressions. Instead, rely on the language’s type system to ensure type safety and +code clarity. + ### Exceptions - + Issues are not raised against the [default literal](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/types/casting-and-type-conversions). - + ## How to fix it - + To fix your code remove the unnecessary casting expression. - + ### Code examples - + #### Noncompliant code example public int Example(int i) @@ -49,7 +52,7 @@ To fix your code remove the unnecessary casting expression. bool b = (bool)default; // Doesn't raise an issue ## Resources - + ### Documentation - Microsoft - [Casting and type diff --git a/docs/description/S1939.md b/docs/description/S1939.md index 664e884..9785c04 100644 --- a/docs/description/S1939.md +++ b/docs/description/S1939.md @@ -1,13 +1,13 @@ ## Why is this an issue? - + An inheritance list entry is redundant if: - + - It is `Object` - all classes extend `Object` implicitly. - It is `int` for an `enum` - It is a base class of another listed inheritance. Such redundant declarations should be removed because they needlessly clutter the code and can be confusing. - + ### Noncompliant code example public class MyClass : Object // Noncompliant diff --git a/docs/description/S1940.md b/docs/description/S1940.md index 3740ab8..f6364fb 100644 --- a/docs/description/S1940.md +++ b/docs/description/S1940.md @@ -1,7 +1,7 @@ ## Why is this an issue? - + It is needlessly complex to invert the result of a boolean comparison. The opposite comparison should be made instead. - + ### Noncompliant code example if ( !(a == 2)) { ...} // Noncompliant diff --git a/docs/description/S1944.md b/docs/description/S1944.md index b579e2f..e38dc6c 100644 --- a/docs/description/S1944.md +++ b/docs/description/S1944.md @@ -1,5 +1,5 @@ ## Why is this an issue? - + A cast is an [explicit conversion](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/types/casting-and-type-conversions#explicit-conversions), which is a way to tell the compiler the intent to convert from one type to another. @@ -10,23 +10,24 @@ conversion](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/ty } In most cases, the compiler will be able to catch invalid casts between incompatible value types or reference types. - + However, the compiler will not be able to detect invalid casts to [interfaces](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/interface). - + ### What is the potential impact? - + Invalid casts will lead to unexpected behaviors or runtime errors such as [InvalidCastException](https://learn.microsoft.com/en-us/dotnet/api/system.invalidcastexception). - + ### Exceptions - + No issue is reported if the interface has no implementing class in the assembly. - + ## How to fix it - -To prevent an `InvalidCastException` from raising during an explicit conversion, it is recommended to use the [`as` operator](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast#as-operator). When the conversion is not possible, the `as` operator returns `null` and will never raise an exception. - + +To prevent an `InvalidCastException` from raising during an explicit conversion, it is recommended to use the [`as` operator](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast#as-operator). +When the conversion is not possible, the `as` operator returns `null` and will never raise an exception. + ### Code examples - + #### Noncompliant code example public interface IMyInterface @@ -68,9 +69,9 @@ To prevent an `InvalidCastException` from raising during an explicit conversion, } ## Resources - + ### Documentation - + - [Casting and type conversions - Explicit conversion](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/types/casting-and-type-conversions#explicit-conversions) - [Type-testing operators and cast diff --git a/docs/description/S1994.md b/docs/description/S1994.md index 0de9818..51d4ef5 100644 --- a/docs/description/S1994.md +++ b/docs/description/S1994.md @@ -1,15 +1,18 @@ ## Why is this an issue? - -The `for` loop is designed to iterate over a range using a counter variable, with the counter being updated in the loop’s increment section. Misusing this structure can lead to issues such as infinite loops if the counter is not updated correctly. If this is intentional, use a `while` or `do while` loop instead of a `for` loop. - -Using a for loop for purposes other than its intended use can lead to confusion and potential bugs. If the `for` loop structure does not fit your needs, consider using an alternative [iteration statement](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/iteration-statements). - + +The `for` loop is designed to iterate over a range using a counter variable, with the counter being updated in the loop’s increment +section. Misusing this structure can lead to issues such as infinite loops if the counter is not updated correctly. If this is intentional, use a +`while` or `do while` loop instead of a `for` loop. + +Using a for loop for purposes other than its intended use can lead to confusion and potential bugs. If the `for` loop structure does not +fit your needs, consider using an alternative [iteration statement](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/iteration-statements). + ## How to fix it - + Move the counter variable update to the loop’s increment section. If this is impossible, consider using another iteration statement instead. - + ### Code examples - + #### Noncompliant code example int sum = 0; @@ -41,9 +44,9 @@ Move the counter variable update to the loop’s increment section. If this is i } ## Resources - + ### Documentation - + - Microsoft Learn - [The `for` statement](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/iteration-statements#the-for-statement) - Microsoft Learn - [Iteration diff --git a/docs/description/S2053.md b/docs/description/S2053.md index 2a8f538..096766d 100644 --- a/docs/description/S2053.md +++ b/docs/description/S2053.md @@ -1,42 +1,56 @@ This vulnerability increases the likelihood that attackers are able to compute the cleartext of password hashes. - + ## Why is this an issue? - -During the process of password hashing, an additional component, known as a "salt," is often integrated to bolster the overall security. This salt, acting as a defensive measure, primarily wards off certain types of attacks that leverage pre-computed tables to crack passwords. - -However, potential risks emerge when the salt is deemed insecure. This can occur when the salt is consistently the same across all users or when it is too short or predictable. In scenarios where users share the same password and salt, their password hashes will inevitably mirror each other. Similarly, a short salt heightens the probability of multiple users unintentionally having identical salts, which can potentially lead to identical password hashes. These identical hashes streamline the process for potential attackers to recover clear-text passwords. Thus, the emphasis on implementing secure, unique, and sufficiently lengthy salts in password-hashing functions is vital. - + +During the process of password hashing, an additional component, known as a "salt," is often integrated to bolster the overall security. This salt, +acting as a defensive measure, primarily wards off certain types of attacks that leverage pre-computed tables to crack passwords. + +However, potential risks emerge when the salt is deemed insecure. This can occur when the salt is consistently the same across all users or when it +is too short or predictable. In scenarios where users share the same password and salt, their password hashes will inevitably mirror each other. +Similarly, a short salt heightens the probability of multiple users unintentionally having identical salts, which can potentially lead to identical +password hashes. These identical hashes streamline the process for potential attackers to recover clear-text passwords. Thus, the emphasis on +implementing secure, unique, and sufficiently lengthy salts in password-hashing functions is vital. + ### What is the potential impact? - -Despite best efforts, even well-guarded systems might have vulnerabilities that could allow an attacker to gain access to the hashed passwords. This could be due to software vulnerabilities, insider threats, or even successful phishing attempts that give attackers the access they need. - -Once the attacker has these hashes, they will likely attempt to crack them using a couple of methods. One is brute force, which entails trying every possible combination until the correct password is found. While this can be time-consuming, having the same salt for all users or a short salt can make the task significantly easier and faster. - -If multiple users have the same password and the same salt, their password hashes would be identical. This means that if an attacker successfully cracks one hash, they have effectively cracked all identical ones, granting them access to multiple accounts at once. - -A short salt, while less critical than a shared one, still increases the odds of different users having the same salt. This might create clusters of password hashes with identical salt that can then be attacked as explained before. - -With short salts, the probability of a collision between two users' passwords and salts couple might be low depending on the salt size. The shorter the salt, the higher the collision probability. In any case, using longer, cryptographically secure salt should be preferred. - + +Despite best efforts, even well-guarded systems might have vulnerabilities that could allow an attacker to gain access to the hashed passwords. +This could be due to software vulnerabilities, insider threats, or even successful phishing attempts that give attackers the access they need. + +Once the attacker has these hashes, they will likely attempt to crack them using a couple of methods. One is brute force, which entails trying +every possible combination until the correct password is found. While this can be time-consuming, having the same salt for all users or a short salt +can make the task significantly easier and faster. + +If multiple users have the same password and the same salt, their password hashes would be identical. This means that if an attacker successfully +cracks one hash, they have effectively cracked all identical ones, granting them access to multiple accounts at once. + +A short salt, while less critical than a shared one, still increases the odds of different users having the same salt. This might create clusters +of password hashes with identical salt that can then be attacked as explained before. + +With short salts, the probability of a collision between two users' passwords and salts couple might be low depending on the salt size. The shorter +the salt, the higher the collision probability. In any case, using longer, cryptographically secure salt should be preferred. + ### Exceptions - -To securely store password hashes, it is a recommended to rely on key derivation functions that are computationally intensive. Examples of such functions are: - + +To securely store password hashes, it is a recommended to rely on key derivation functions that are computationally intensive. Examples of such +functions are: + - Argon2 - PBKDF2 - Scrypt - Bcrypt When they are used for password storage, using a secure, random salt is required. - -However, those functions can also be used for other purposes such as master key derivation or password-based pre-shared key generation. In those cases, the implemented cryptographic protocol might require using a fixed salt to derive keys in a deterministic way. In such cases, using a fixed salt is safe and accepted. - + +However, those functions can also be used for other purposes such as master key derivation or password-based pre-shared key generation. In those +cases, the implemented cryptographic protocol might require using a fixed salt to derive keys in a deterministic way. In such cases, using a fixed +salt is safe and accepted. + ## How to fix it in .NET - + ### Code examples - + The following code contains examples of hard-coded salts. - + #### Noncompliant code example using System.Security.Cryptography; @@ -57,17 +71,20 @@ The following code contains examples of hard-coded salts. } ### How does this work? - -This code ensures that each user’s password has a unique salt value associated with it. It generates a salt randomly and with a length that provides the required security level. It uses a salt length of at least 32 bytes (256 bits), as recommended by industry standards. - + +This code ensures that each user’s password has a unique salt value associated with it. It generates a salt randomly and with a length that +provides the required security level. It uses a salt length of at least 32 bytes (256 bits), as recommended by industry standards. + In the case of the code sample, the class automatically takes care of generating a secure salt if none is specified. - + ## Resources - + ### Standards - OWASP - [Top 10 2021 Category A2 - Cryptographic Failures](https://owasp.org/Top10/A02_2021-Cryptographic_Failures/) - OWASP - [Top 10 2017 Category A3 - Sensitive Data Exposure](https://www.owasp.org/www-project-top-ten/2017/A3_2017-Sensitive_Data_Exposure) - CWE - [CWE-759 - Use of a One-Way Hash without a Salt](https://cwe.mitre.org/data/definitions/759) -- CWE - [CWE-760 - Use of a One-Way Hash with a Predictable Salt](https://cwe.mitre.org/data/definitions/760) \ No newline at end of file +- CWE - [CWE-760 - Use of a One-Way Hash with a Predictable Salt](https://cwe.mitre.org/data/definitions/760) +- STIG Viewer - [Application Security and + Development: V-222542](https://stigviewer.com/stig/application_security_and_development/2023-06-08/finding/V-222542) - The application must only store cryptographic representations of passwords. \ No newline at end of file diff --git a/docs/description/S2068.md b/docs/description/S2068.md index bc30ea1..277fb73 100644 --- a/docs/description/S2068.md +++ b/docs/description/S2068.md @@ -1,16 +1,18 @@ -Because it is easy to extract strings from an application source code or binary, credentials should not be hard-coded. This is particularly true for applications that are distributed or that are open-source. - +Because it is easy to extract strings from an application source code or binary, credentials should not be hard-coded. This is particularly true +for applications that are distributed or that are open-source. + In the past, it has led to the following vulnerabilities: - + - [CVE-2019-13466](http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-13466) - [CVE-2018-15389](http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-15389) Credentials should be stored outside of the code in a configuration file, a database, or a management service for secrets. - -This rule flags instances of hard-coded credentials used in database and LDAP connections. It looks for hard-coded credentials in connection strings, and for variable names that match any of the patterns from the provided list. - + +This rule flags instances of hard-coded credentials used in database and LDAP connections. It looks for hard-coded credentials in connection +strings, and for variable names that match any of the patterns from the provided list. + It’s recommended to customize the configuration of this rule with additional credential words such as "oauthToken", "secret", …​ - + ## Ask Yourself Whether - Credentials allow access to a sensitive component like a database, a file storage, an API or a service. @@ -18,7 +20,7 @@ It’s recommended to customize the configuration of this rule with additional c - Application re-distribution is required before updating the credentials. There is a risk if you answered yes to any of those questions. - + ## Recommended Secure Coding Practices - Store the credentials in a configuration file that is not pushed to the code repository. diff --git a/docs/description/S2092.md b/docs/description/S2092.md index 82ba95a..eee6f37 100644 --- a/docs/description/S2092.md +++ b/docs/description/S2092.md @@ -1,13 +1,14 @@ -When a cookie is protected with the `secure` attribute set to *true* it will not be send by the browser over an unencrypted HTTP request and thus cannot be observed by an unauthorized person during a man-in-the-middle attack. - +When a cookie is protected with the `secure` attribute set to *true* it will not be send by the browser over an unencrypted HTTP +request and thus cannot be observed by an unauthorized person during a man-in-the-middle attack. + ## Ask Yourself Whether - + - the cookie is for instance a *session-cookie* not designed to be sent over non-HTTPS communication. - it’s not sure that the website contains [mixed content](https://developer.mozilla.org/en-US/docs/Web/Security/Mixed_content) or not (ie HTTPS everywhere or not) There is a risk if you answered yes to any of those questions. - + ## Recommended Secure Coding Practices - It is recommended to use `HTTPs` everywhere so setting the `secure` flag to *true* should be the default behaviour @@ -15,19 +16,20 @@ There is a risk if you answered yes to any of those questions. - Set the `secure` flag to *true* for session-cookies. ## Sensitive Code Example - + When the `HttpCookie.Secure` property is set to `false` then the cookie will be send during an unencrypted HTTP request: HttpCookie myCookie = new HttpCookie("Sensitive cookie"); myCookie.Secure = false; // Sensitive: a security-sensitive cookie is created with the secure flag set to false -The [default value](https://docs.microsoft.com/en-us/dotnet/api/system.web.httpcookie.secure?view=netframework-4.8) of `Secure` flag is `false`, unless overwritten by an application’s configuration file: +The [default value](https://docs.microsoft.com/en-us/dotnet/api/system.web.httpcookie.secure?view=netframework-4.8) of +`Secure` flag is `false`, unless overwritten by an application’s configuration file: HttpCookie myCookie = new HttpCookie("Sensitive cookie"); // Sensitive: a security-sensitive cookie is created with the secure flag not defined (by default set to false) ## Compliant Solution - + Set the `HttpCookie.Secure` property to `true`: HttpCookie myCookie = new HttpCookie("Sensitive cookie"); @@ -48,4 +50,6 @@ Or change the default flag values for the whole application by editing the [Web. Exposure](https://owasp.org/www-project-top-ten/2017/A3_2017-Sensitive_Data_Exposure) - CWE - [CWE-311 - Missing Encryption of Sensitive Data](https://cwe.mitre.org/data/definitions/311) - CWE - [CWE-315 - Cleartext Storage of Sensitive Information in a Cookie](https://cwe.mitre.org/data/definitions/315) -- CWE - [CWE-614 - Sensitive Cookie in HTTPS Session Without 'Secure' Attribute](https://cwe.mitre.org/data/definitions/614) \ No newline at end of file +- CWE - [CWE-614 - Sensitive Cookie in HTTPS Session Without 'Secure' Attribute](https://cwe.mitre.org/data/definitions/614) +- STIG Viewer - [Application Security and + Development: V-222576](https://stigviewer.com/stig/application_security_and_development/2023-06-08/finding/V-222576) - The application must set the secure flag on session cookies. \ No newline at end of file diff --git a/docs/description/S2094.md b/docs/description/S2094.md index 9856fb8..cb33dae 100644 --- a/docs/description/S2094.md +++ b/docs/description/S2094.md @@ -1,7 +1,9 @@ ## Why is this an issue? - -There is no good excuse for an empty class. If it’s being used simply as a common extension point, it should be replaced with an `interface`. If it was stubbed in as a placeholder for future development it should be fleshed-out. In any other case, it should be eliminated. - + +There is no good excuse for an empty class. If it’s being used simply as a common extension point, it should be replaced with an +`interface`. If it was stubbed in as a placeholder for future development it should be fleshed-out. In any other case, it should be +eliminated. + ### Noncompliant code example public class Empty // Noncompliant @@ -15,8 +17,15 @@ There is no good excuse for an empty class. If it’s being used simply as a com } ### Exceptions - -Partial classes are ignored entirely, as they are often used with Source Generators. Subclasses of System.Exception are ignored, as even an empty Exception class can provide useful information by its type name alone. Subclasses of System.Attribute are ignored, as well as classes which are annotated with attributes. Subclasses of generic classes are ignored, as even when empty they can be used for type specialization. Subclasses of certain framework types - like the PageModel class used in ASP.NET Core Razor Pages - are also ignored. + +- Partial classes are ignored entirely, as source generators often use them. +- Classes with names ending in `Command`, `Message`, `Event`, or `Query` are ignored as messaging + libraries often use them. +- Subclasses of `System.Exception` are ignored; even an empty Exception class can provide helpful information by its type name alone. +- Subclasses of `System.Attribute` and classes annotated with attributes are ignored. +- Subclasses of generic classes are ignored, as they can be used for type specialization even when empty. +- Subclasses of certain framework types — like the `PageModel` class used in ASP.NET Core Razor Pages — are ignored. +- Subclass of a class with non-public default constructors are ignored, as they widen the constructor accessibility. using Microsoft.AspNetCore.Mvc.RazorPages; diff --git a/docs/description/S2114.md b/docs/description/S2114.md index 6220e5d..4135d12 100644 --- a/docs/description/S2114.md +++ b/docs/description/S2114.md @@ -1,8 +1,11 @@ ## Why is this an issue? - -Passing a collection as an argument to the collection’s own method is a code defect. Doing so might either have unexpected side effects or always have the same result. - -Another case is using set-like operations. For example, using [Union](https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.union) between a list and itself will always return the same list. Conversely, using [Except](https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.except) between a list and itself will always return an empty list. + +Passing a collection as an argument to the collection’s own method is a code defect. Doing so might either have unexpected side effects or always +have the same result. + +Another case is using set-like operations. For example, using [Union](https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.union) between a list and itself will always return the same list. +Conversely, using [Except](https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.except) between a list and itself will +always return an empty list. var list = new List(); @@ -27,7 +30,7 @@ Another case is using set-like operations. For example, using [Union](https://le set.SetEquals(set); // Noncompliant: always returns true ## Resources - + ### Documentation - + - [Collections](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/collections) \ No newline at end of file diff --git a/docs/description/S2115.md b/docs/description/S2115.md index aeae5ef..47f8980 100644 --- a/docs/description/S2115.md +++ b/docs/description/S2115.md @@ -1,35 +1,50 @@ When accessing a database, an empty password should be avoided as it introduces a weakness. - + ## Why is this an issue? - -When a database does not require a password for authentication, it allows anyone to access and manipulate the data stored within it. Exploiting this vulnerability typically involves identifying the target database and establishing a connection to it without the need for any authentication credentials. - + +When a database does not require a password for authentication, it allows anyone to access and manipulate the data stored within it. Exploiting +this vulnerability typically involves identifying the target database and establishing a connection to it without the need for any authentication +credentials. + ### What is the potential impact? - -Once connected, an attacker can perform various malicious actions, such as viewing, modifying, or deleting sensitive information, potentially leading to data breaches or unauthorized access to critical systems. It is crucial to address this vulnerability promptly to ensure the security and integrity of the database and the data it contains. - + +Once connected, an attacker can perform various malicious actions, such as viewing, modifying, or deleting sensitive information, potentially +leading to data breaches or unauthorized access to critical systems. It is crucial to address this vulnerability promptly to ensure the security and +integrity of the database and the data it contains. + #### Unauthorized Access to Sensitive Data - -When a database lacks a password for authentication, it opens the door for unauthorized individuals to gain access to sensitive data. This can include personally identifiable information (PII), financial records, intellectual property, or any other confidential information stored in the database. Without proper access controls in place, malicious actors can exploit this vulnerability to retrieve sensitive data, potentially leading to identity theft, financial loss, or reputational damage. - + +When a database lacks a password for authentication, it opens the door for unauthorized individuals to gain access to sensitive data. This can +include personally identifiable information (PII), financial records, intellectual property, or any other confidential information stored in the +database. Without proper access controls in place, malicious actors can exploit this vulnerability to retrieve sensitive data, potentially leading to +identity theft, financial loss, or reputational damage. + #### Compromise of System Integrity - -Without a password requirement, unauthorized individuals can gain unrestricted access to a database, potentially compromising the integrity of the entire system. Attackers can inject malicious code, alter configurations, or manipulate data within the database, leading to system malfunctions, unauthorized system access, or even complete system compromise. This can disrupt business operations, cause financial losses, and expose the organization to further security risks. - + +Without a password requirement, unauthorized individuals can gain unrestricted access to a database, potentially compromising the integrity of the +entire system. Attackers can inject malicious code, alter configurations, or manipulate data within the database, leading to system malfunctions, +unauthorized system access, or even complete system compromise. This can disrupt business operations, cause financial losses, and expose the +organization to further security risks. + #### Unwanted Modifications or Deletions - -The absence of a password for database access allows anyone to make modifications or deletions to the data stored within it. This poses a significant risk, as unauthorized changes can lead to data corruption, loss of critical information, or the introduction of malicious content. For example, an attacker could modify financial records, tamper with customer orders, or delete important files, causing severe disruptions to business processes and potentially leading to financial and legal consequences. - -Overall, the lack of a password configured to access a database poses a serious security risk, enabling unauthorized access, data breaches, system compromise, and unwanted modifications or deletions. It is essential to address this vulnerability promptly to safeguard sensitive data, maintain system integrity, and protect the organization from potential harm. - + +The absence of a password for database access allows anyone to make modifications or deletions to the data stored within it. This poses a +significant risk, as unauthorized changes can lead to data corruption, loss of critical information, or the introduction of malicious content. For +example, an attacker could modify financial records, tamper with customer orders, or delete important files, causing severe disruptions to business +processes and potentially leading to financial and legal consequences. + +Overall, the lack of a password configured to access a database poses a serious security risk, enabling unauthorized access, data breaches, system +compromise, and unwanted modifications or deletions. It is essential to address this vulnerability promptly to safeguard sensitive data, maintain +system integrity, and protect the organization from potential harm. + ## How to fix it in Entity Framework Core - + ### Code examples - + The following code uses an empty password to connect to a SQL Server database. - + The vulnerability can be fixed by using Windows authentication (sometimes referred to as integrated security). - + #### Noncompliant code example protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) @@ -45,13 +60,17 @@ The vulnerability can be fixed by using Windows authentication (sometimes referr } ### How does this work? - + #### Windows authentication (integrated security) - -When the connection string includes the `Integrated Security=true` parameter, it enables Windows authentication (sometimes called integrated security) for the database connection. With integrated security, the user’s Windows credentials are used to authenticate and authorize access to the database. It eliminates the need for a separate username and password for the database connection. Integrated security simplifies authentication and leverages the existing Windows authentication infrastructure for secure database access in your C# application. - -It’s important to note that when using integrated security, the user running the application must have the necessary permissions to access the database. Ensure that the user account running the application has the appropriate privileges and is granted access to the database. - + +When the connection string includes the `Integrated Security=true` parameter, it enables Windows authentication (sometimes called +integrated security) for the database connection. With integrated security, the user’s Windows credentials are used to authenticate and authorize +access to the database. It eliminates the need for a separate username and password for the database connection. Integrated security simplifies +authentication and leverages the existing Windows authentication infrastructure for secure database access in your C# application. + +It’s important to note that when using integrated security, the user running the application must have the necessary permissions to access the +database. Ensure that the user account running the application has the appropriate privileges and is granted access to the database. + The syntax employed in connection strings varies by provider: | Syntax | Supported by | @@ -63,13 +82,14 @@ The syntax employed in connection strings varies by provider: | `Trusted_Connection=yes;` | ODBC | Note: Some providers such as MySQL do not support Windows authentication with .NET Core. - + ### Pitfalls - + #### Hard-coded passwords - -It could be tempting to replace the empty password with a hard-coded one. Hard-coding passwords in the code can pose significant security risks. Here are a few reasons why it is not recommended: - + +It could be tempting to replace the empty password with a hard-coded one. Hard-coding passwords in the code can pose significant security risks. +Here are a few reasons why it is not recommended: + 1. Security Vulnerability: Hard-coded passwords can be easily discovered by anyone who has access to the code, such as other developers or attackers. This can lead to unauthorized access to the database and potential data breaches. 2. Lack of Flexibility: Hard-coded passwords make it difficult to change the password without modifying the code. If the password needs to be @@ -77,16 +97,18 @@ It could be tempting to replace the empty password with a hard-coded one. Hard-c 3. Version Control Issues: Storing passwords in code can lead to version control issues. If the code is shared or stored in a version control system, the password will be visible to anyone with access to the repository, which is a security risk. -To mitigate these risks, it is recommended to use secure methods for storing and retrieving passwords, such as using environment variables, configuration files, or secure key management systems. These methods allow for better security, flexibility, and separation of sensitive information from the codebase. - +To mitigate these risks, it is recommended to use secure methods for storing and retrieving passwords, such as using environment variables, +configuration files, or secure key management systems. These methods allow for better security, flexibility, and separation of sensitive information +from the codebase. + ## How to fix it in ASP.NET - + ### Code examples - + The following configuration file uses an empty password to connect to a database. - + The vulnerability can be fixed by using Windows authentication (sometimes referred to as integrated security) - + #### Noncompliant code example @@ -106,13 +128,17 @@ The vulnerability can be fixed by using Windows authentication (sometimes referr ### How does this work? - + #### Windows authentication (integrated security) - -When the connection string includes the `Integrated Security=true` parameter, it enables Windows authentication (sometimes called integrated security) for the database connection. With integrated security, the user’s Windows credentials are used to authenticate and authorize access to the database. It eliminates the need for a separate username and password for the database connection. Integrated security simplifies authentication and leverages the existing Windows authentication infrastructure for secure database access in your C# application. - -It’s important to note that when using integrated security, the user running the application must have the necessary permissions to access the database. Ensure that the user account running the application has the appropriate privileges and is granted access to the database. - + +When the connection string includes the `Integrated Security=true` parameter, it enables Windows authentication (sometimes called +integrated security) for the database connection. With integrated security, the user’s Windows credentials are used to authenticate and authorize +access to the database. It eliminates the need for a separate username and password for the database connection. Integrated security simplifies +authentication and leverages the existing Windows authentication infrastructure for secure database access in your C# application. + +It’s important to note that when using integrated security, the user running the application must have the necessary permissions to access the +database. Ensure that the user account running the application has the appropriate privileges and is granted access to the database. + The syntax employed in connection strings varies by provider: | Syntax | Supported by | @@ -124,12 +150,13 @@ The syntax employed in connection strings varies by provider: | `Trusted_Connection=yes;` | ODBC | Note: Some providers such as MySQL do not support Windows authentication with .NET Core. - + ### Pitfalls - + #### Hard-coded passwords - -It could be tempting to replace the empty password with a hard-coded one. Hard-coding passwords in the code can pose significant security risks. Here are a few reasons why it is not recommended: + +It could be tempting to replace the empty password with a hard-coded one. Hard-coding passwords in the code can pose significant security risks. +Here are a few reasons why it is not recommended: 1. Security Vulnerability: Hard-coded passwords can be easily discovered by anyone who has access to the code, such as other developers or attackers. This can lead to unauthorized access to the database and potential data breaches. @@ -138,8 +165,10 @@ It could be tempting to replace the empty password with a hard-coded one. Hard-c 3. Version Control Issues: Storing passwords in code can lead to version control issues. If the code is shared or stored in a version control system, the password will be visible to anyone with access to the repository, which is a security risk. -To mitigate these risks, it is recommended to use secure methods for storing and retrieving passwords, such as using environment variables, configuration files, or secure key management systems. These methods allow for better security, flexibility, and separation of sensitive information from the codebase. - +To mitigate these risks, it is recommended to use secure methods for storing and retrieving passwords, such as using environment variables, +configuration files, or secure key management systems. These methods allow for better security, flexibility, and separation of sensitive information +from the codebase. + ## Resources - [Create the Web.config file for an ASP.NET application](https://docs.microsoft.com/en-us/troubleshoot/aspnet/create-web-config) diff --git a/docs/description/S2123.md b/docs/description/S2123.md index 6d31356..1463b55 100644 --- a/docs/description/S2123.md +++ b/docs/description/S2123.md @@ -1,27 +1,31 @@ ## Why is this an issue? - + When using the [postfix -increment](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/arithmetic-operators#postfix-increment-operator) operator, it is important to know that the result of the expression `x++` is the value **before** the operation `x`. - +increment](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/arithmetic-operators#postfix-increment-operator) operator, it is important to know that the result of the expression `x++` is the value **before** the operation +`x`. + This means that in some cases, the result might not be what you expect: - + - When assigning `x++` to `x`, it’s the same as assigning `x` to itself, since the value is assigned before the increment takes place - When returning `x++`, the returning value is `x`, not `x+1` -The same applies to the postfix and prefix [decrement](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/arithmetic-operators#decrement-operator---) operators. - +The same applies to the postfix and prefix [decrement](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/arithmetic-operators#decrement-operator---) +operators. + ## How to fix it - + To solve the issue in assignments, eliminate the assignment, since `x\++` mutates `x` anyways. - + To solve the issue in return statements, consider using the [prefix -increment](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/arithmetic-operators#prefix-increment-operator) operator, since it works in reverse: the result of the expression `++x` is the value **after** the operation, which is `x+1`, as one might expect. - -The same applies to the postfix and prefix [decrement](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/arithmetic-operators#decrement-operator---) operators. - +increment](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/arithmetic-operators#prefix-increment-operator) operator, since it works in reverse: the result of the expression `++x` is the value **after** the operation, +which is `x+1`, as one might expect. + +The same applies to the postfix and prefix [decrement](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/arithmetic-operators#decrement-operator---) +operators. + ### Code examples - + #### Noncompliant code example int PickNumber() @@ -45,7 +49,7 @@ The same applies to the postfix and prefix [decrement](https://learn.microsoft.c } ## Resources - + ### Documentation - Microsoft Learn - [Arithmetic diff --git a/docs/description/S2139.md b/docs/description/S2139.md index 5764311..a13838e 100644 --- a/docs/description/S2139.md +++ b/docs/description/S2139.md @@ -1,20 +1,23 @@ ## Why is this an issue? - -When an exception is logged and rethrown, the upstream code may not be aware that the exception has already been logged. As a result, the same exception gets logged multiple times, making it difficult to identify the root cause of the issue. This can be particularly problematic in multi-threaded applications where messages from other threads can be interwoven with the repeated log entries. - + +When an exception is logged and rethrown, the upstream code may not be aware that the exception has already been logged. As a result, the same +exception gets logged multiple times, making it difficult to identify the root cause of the issue. This can be particularly problematic in +multi-threaded applications where messages from other threads can be interwoven with the repeated log entries. + ### Exceptions - + This rule will not generate issues if, within the catch block, one of the following conditions are met: - + - The logs generated within the catch block do not contain any references to the exception being caught. - The exception being thrown from the catch block is not the same exception that is being caught. ## How to fix it - -To address this issue, it is recommended to modify the code to log exceptions only when they are handled locally. In all other cases, simply rethrow the exception and allow the higher-level layers of the application to handle the logging and appropriate actions. - + +To address this issue, it is recommended to modify the code to log exceptions only when they are handled locally. In all other cases, simply +rethrow the exception and allow the higher-level layers of the application to handle the logging and appropriate actions. + ### Code examples - + #### Noncompliant code example try {} @@ -43,7 +46,7 @@ or } ## Resources - + ### Documentation - Microsoft Learn - [Exception-handling statements](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/exception-handling-statements) diff --git a/docs/description/S2148.md b/docs/description/S2148.md index c9e1fe6..b2863a9 100644 --- a/docs/description/S2148.md +++ b/docs/description/S2148.md @@ -1,7 +1,8 @@ ## Why is this an issue? - -Beginning with C# 7, it is possible to add underscores ('\_') to numeric literals to enhance readability. The addition of underscores in this manner has no semantic meaning, but makes it easier for maintainers to understand the code. - + +Beginning with C# 7, it is possible to add underscores ('\_') to numeric literals to enhance readability. The addition of underscores in this manner +has no semantic meaning, but makes it easier for maintainers to understand the code. + The number of digits to the left of a decimal point needed to trigger this rule varies by base. | Base | Minimum digits | @@ -11,9 +12,9 @@ The number of digits to the left of a decimal point needed to trigger this rule | hexadecimal | 9 | It is only the presence of underscores, not their spacing that is scrutinized by this rule. - + **Note** that this rule is automatically disabled when the project’s `C# version` is lower than `7`. - + ### Noncompliant code example int i = 10000000; // Noncompliant; is this 10 million or 100 million? diff --git a/docs/description/S2156.md b/docs/description/S2156.md index 06c97ef..25d8aeb 100644 --- a/docs/description/S2156.md +++ b/docs/description/S2156.md @@ -1,7 +1,9 @@ ## Why is this an issue? - -The difference between `private` and `protected` visibility is that child classes can see and use `protected` members, but they cannot see `private` ones. Since a `sealed` class cannot have children, marking its members `protected` is confusingly pointless. - + +The difference between `private` and `protected` visibility is that child classes can see and use `protected` +members, but they cannot see `private` ones. Since a `sealed` class cannot have children, marking its members +`protected` is confusingly pointless. + ### Noncompliant code example public sealed class MySealedClass diff --git a/docs/description/S2166.md b/docs/description/S2166.md index 40cf8d0..dcddec9 100644 --- a/docs/description/S2166.md +++ b/docs/description/S2166.md @@ -1,7 +1,9 @@ ## Why is this an issue? - -Clear, communicative naming is important in code. It helps maintainers and API users understand the intentions for and uses of a unit of code. Using "exception" in the name of a class that does not extend `Exception` or one of its subclasses is a clear violation of the expectation that a class' name will indicate what it is and/or does. - + +Clear, communicative naming is important in code. It helps maintainers and API users understand the intentions for and uses of a unit of code. +Using "exception" in the name of a class that does not extend `Exception` or one of its subclasses is a clear violation of the expectation +that a class' name will indicate what it is and/or does. + ### Noncompliant code example public class FruitException // Noncompliant - this has nothing to do with Exception diff --git a/docs/description/S2178.md b/docs/description/S2178.md index 35df323..58e7bef 100644 --- a/docs/description/S2178.md +++ b/docs/description/S2178.md @@ -1,19 +1,26 @@ ## Why is this an issue? - -[Short-circuit evaluation](https://en.wikipedia.org/wiki/Short-circuit_evaluation) is an evaluation strategy for [Boolean operators](https://en.wikipedia.org/wiki/Logical_connective), that doesn’t evaluates the second argument of the operator if it is not needed to determine the result of the operation. - -C# provides logical operators that implement short-circuit evaluation: `&&` and `||`, as well as non-short-circuit versions: `&` and `|`. Unlike short-circuit operators, non-short-circuit ones evaluate both operands and afterwards perform the logical operation. - -For example `false && FunctionCall()` always results in `false`, even when `FunctionCall` invocation would raise an exception. Instead, `false & FunctionCall()` also evaluates `FunctionCall()`, and results in an exception if `FunctionCall()` invocation raises an exception. - -Similarly, `true || FunctionCall()` always results in `true`, no matter what the return value of `FunctionCall()` would be. - -The use of non-short-circuit logic in a boolean context is likely a mistake - one that could cause serious program errors as conditions are evaluated under the wrong circumstances. - + +[Short-circuit evaluation](https://en.wikipedia.org/wiki/Short-circuit_evaluation) is an evaluation strategy for [Boolean operators](https://en.wikipedia.org/wiki/Logical_connective), that doesn’t evaluates the second argument of the operator if it is not +needed to determine the result of the operation. + +C# provides logical operators that implement short-circuit evaluation: `&&` and `||`, as well as non-short-circuit +versions: `&` and `|`. Unlike short-circuit operators, non-short-circuit ones evaluate both operands and afterwards perform +the logical operation. + +For example `false && FunctionCall()` always results in `false`, even when `FunctionCall` invocation would +raise an exception. Instead, `false & FunctionCall()` also evaluates `FunctionCall()`, and results in an exception if +`FunctionCall()` invocation raises an exception. + +Similarly, `true || FunctionCall()` always results in `true`, no matter what the return value of `FunctionCall()` +would be. + +The use of non-short-circuit logic in a boolean context is likely a mistake - one that could cause serious program errors as conditions are +evaluated under the wrong circumstances. + ## How to fix it - + ### Code examples - + #### Noncompliant code example if (GetTrue() | GetFalse()) // Noncompliant: both sides evaluated @@ -27,9 +34,9 @@ The use of non-short-circuit logic in a boolean context is likely a mistake - on } ## Resources - + ### Documentation - + - [Boolean logical operators - AND, OR, NOT, XOR](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/boolean-logical-operators) - [Short-circuit evaluation](https://en.wikipedia.org/wiki/Short-circuit_evaluation) diff --git a/docs/description/S2183.md b/docs/description/S2183.md index 261f998..2108fd3 100644 --- a/docs/description/S2183.md +++ b/docs/description/S2183.md @@ -1,16 +1,21 @@ ## Why is this an issue? - -The [shifting](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-and-shift-operators#left-shift-operator-) operators are used to do an [arithmetic shift](https://en.wikipedia.org/wiki/Arithmetic_shift) to the bits of an [integral numeric](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/integral-numeric-types) value, either to the left or the right. + +The [shifting](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-and-shift-operators#left-shift-operator-) +operators are used to do an [arithmetic shift](https://en.wikipedia.org/wiki/Arithmetic_shift) to the bits of an [integral numeric](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/integral-numeric-types) value, either to +the left or the right. var number = 14; // ...01110 (14) var left = number << 1; // ...11100 (28) var right = number >> 1; // ...00111 (7) Therefore, shifting an integral number by 0 is equivalent to doing nothing, since the bits do not move any positions to the left or the right. - -On the other hand, shifting an integral number by a value greater than their count of bits minus one (`n_bits-1`) is equivalent to shifting by the value [modulo](https://en.wikipedia.org/wiki/Modulo) the bit count of the number (`value % n_bits`). - -In the case of `int` and `uint`, which take 32 bits in the memory, the shift count is given by the five low-order bits of the second operand, which can represent numbers from 0 to 31. This means that numbers having the same five low-order bits are treated the same by the shift operators. + +On the other hand, shifting an integral number by a value greater than their count of bits minus one (`n_bits-1`) is equivalent to +shifting by the value [modulo](https://en.wikipedia.org/wiki/Modulo) the bit count of the number (`value % n_bits`). + +In the case of `int` and `uint`, which take 32 bits in the memory, the shift count is given by the five low-order bits of the +second operand, which can represent numbers from 0 to 31. This means that numbers having the same five low-order bits are treated the same by the +shift operators. var one = 0b0_00001; var thirtyThree = 0b1_00001; // Same five low-order bits, 33 % 32 = 1 @@ -18,14 +23,16 @@ In the case of `int` and `uint`, which take 32 bits in the memory, the shift cou var shifted1 = 42 << one; // Results in 84 var shifted2 = 42 << thirtyThree; // Results in 84 -Note that integral number with a less than 32-bit quantity (e.g. `short`, `ushort`) are implicitly converted to `int` before the shifting operation and so the rule for `int`/`uint` applies. - -If the first operand is a `long` or `ulong` (64-bit quantity), the shift count is given by the six low-order bits of the second operand. That is, the actual shift count is 0 to 63 bits. - +Note that integral number with a less than 32-bit quantity (e.g. `short`, `ushort`) are implicitly converted to +`int` before the shifting operation and so the rule for `int`/`uint` applies. + +If the first operand is a `long` or `ulong` (64-bit quantity), the shift count is given by the six low-order bits of the +second operand. That is, the actual shift count is 0 to 63 bits. + ### Exceptions - + This rule doesn’t raise an issue when the shift by zero is obviously for cosmetic reasons: - + - When the value shifted is a literal. - When there is a similar shift at the same position on line before or after. E.g.: @@ -33,9 +40,9 @@ This rule doesn’t raise an issue when the shift by zero is obviously for cosme bytes[loc+1] = (byte)(value >> 0); ## How to fix it - + ### Code examples - + #### Noncompliant code example short s = 1; @@ -63,7 +70,7 @@ This rule doesn’t raise an issue when the shift by zero is obviously for cosme var longShift2 = lg << 1; ## Resources - + ### Documentation - Microsoft Learn - [Bitwise and diff --git a/docs/description/S2184.md b/docs/description/S2184.md index 37edbef..b640856 100644 --- a/docs/description/S2184.md +++ b/docs/description/S2184.md @@ -1,7 +1,10 @@ ## Why is this an issue? - -When division is performed on `int`s, the result will always be an `int`. You can assign that result to a `double`, `float` or `decimal` with automatic type conversion, but having started as an `int`, the result will likely not be what you expect. If the result of `int` division is assigned to a floating-point variable, precision will have been lost before the assignment. Instead, at least one operand should be cast or promoted to the final type before the operation takes place. - + +When division is performed on `int`s, the result will always be an `int`. You can assign that result to a +`double`, `float` or `decimal` with automatic type conversion, but having started as an `int`, the result +will likely not be what you expect. If the result of `int` division is assigned to a floating-point variable, precision will have been lost +before the assignment. Instead, at least one operand should be cast or promoted to the final type before the operation takes place. + ### Noncompliant code example static void Main() @@ -23,5 +26,9 @@ When division is performed on `int`s, the result will always be an `int`. You ca static void Method(float f) { } ## Resources - -- CWE - [CWE-190 - Integer Overflow or Wraparound](https://cwe.mitre.org/data/definitions/190) \ No newline at end of file + +### Standards + +- CWE - [CWE-190 - Integer Overflow or Wraparound](https://cwe.mitre.org/data/definitions/190) +- STIG Viewer - [Application Security and + Development: V-222612](https://stigviewer.com/stig/application_security_and_development/2023-06-08/finding/V-222612) - The application must not be vulnerable to overflow attacks. \ No newline at end of file diff --git a/docs/description/S2187.md b/docs/description/S2187.md index ed572f2..777622f 100644 --- a/docs/description/S2187.md +++ b/docs/description/S2187.md @@ -1,9 +1,10 @@ ## Why is this an issue? - -To ensure proper testing, it is important to include test cases in a test class. If a test class does not have any test cases, it can give the wrong impression that the class being tested has been thoroughly tested, when in reality, it has not. - + +To ensure proper testing, it is important to include test cases in a test class. If a test class does not have any test cases, it can give the +wrong impression that the class being tested has been thoroughly tested, when in reality, it has not. + This rule will raise an issue when any of these conditions are met: - + - For `NUnit`, a class is marked with `TestFixture` but does not contain any method marked with `Test`, `TestCase`, `TestCaseSource`, or `Theory`. - For `MSTest`, a class is marked with `TestClass` but does not contain any method marked with `TestMethod` or @@ -11,19 +12,20 @@ This rule will raise an issue when any of these conditions are met: It does not apply to `xUnit` since `xUnit` does not require a [test class attribute](https://xunit.net/docs/comparisons#attributes). - + ### Exceptions - + There are scenarios where not having any test cases within a test class is perfectly acceptable and not seen as a problem. - + #### Abstract classes - + To facilitate the creation of common test cases, test logic, or test infrastructure, it is advisable to use a base class. - -Additionally, in both `NUnit` and `MSTest`, abstract classes that are annotated with their respective attributes (`TestFixture` in NUnit and `TestClass` in MSTest) are automatically ignored. - + +Additionally, in both `NUnit` and `MSTest`, abstract classes that are annotated with their respective attributes +(`TestFixture` in NUnit and `TestClass` in MSTest) are automatically ignored. + Therefore, there is no need to raise an issue in this particular scenario. - + More information here: - [`TestFixture` documentation in @@ -31,19 +33,21 @@ More information here: - [`TypeValidator` class in `MSTest` (GitHub)](https://github.com/microsoft/testfx/blob/0f19160cc319338ef6e23acb320da1562b40decd/src/Adapter/MSTest.TestAdapter/Discovery/TypeValidator.cs#L86-L97) #### Derived classes that inherit test cases from a base class - + A base class containing one or more test cases to provide generic test cases is also considered a compliant scenario. - + #### Classes that contain `AssemblyInitialize` or `AssemblyCleanup` methods - + **This particular exception scenario only applies to the MSTest test framework.** - -The `AssemblyInitialize` and `AssemblyCleanup` attributes are used to annotate methods that are executed only once at the beginning and at the end of a test run. These attributes can only be applied once per assembly. - + +The `AssemblyInitialize` and `AssemblyCleanup` attributes are used to annotate methods that are executed only once at the +beginning and at the end of a test run. These attributes can only be applied once per assembly. + It is logical to have a dedicated class for these methods, and this scenario is also considered compliant. - -Furthermore, it is important to note that the test engine will execute a method annotated with either the `AssemblyInitialize` or `AssemblyCleanup` attribute only if that method is part of a class annotated with the `TestClass` attribute. - + +Furthermore, it is important to note that the test engine will execute a method annotated with either the `AssemblyInitialize` or +`AssemblyCleanup` attribute only if that method is part of a class annotated with the `TestClass` attribute. + More information here: - [`AssemblyInitialize` @@ -52,16 +56,17 @@ More information here: attribute](https://learn.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2008/ms245265%28v=vs.90%29) ## How to fix it in MSTest - -To fix this issue in `MSTest`, it is important that all test classes annotated with the `[TestClass]` attribute contain at least one test case. - + +To fix this issue in `MSTest`, it is important that all test classes annotated with the `[TestClass]` attribute contain at +least one test case. + To achieve this, at least one method needs to be annotated with one of the following method attributes: - `TestMethod` - `DataTestMethod` ### Code examples - + #### Noncompliant code example [TestClass] @@ -77,9 +82,10 @@ To achieve this, at least one method needs to be annotated with one of the follo } ## How to fix it in NUnit - -To fix this issue in `NUnit`, it is important that all test classes annotated with the `[TestFixture]` attribute contain at least one test case. - + +To fix this issue in `NUnit`, it is important that all test classes annotated with the `[TestFixture]` attribute contain at +least one test case. + To achieve this, at least one method needs to be annotated with one of the following method attributes: - `Test` @@ -88,7 +94,7 @@ To achieve this, at least one method needs to be annotated with one of the follo - `Theory` ### Code examples - + #### Noncompliant code example [TestFixture] @@ -104,7 +110,7 @@ To achieve this, at least one method needs to be annotated with one of the follo } ## Resources - + ### Documentation - [`NUnit` documentation](https://docs.nunit.org/articles/nunit/intro.html) diff --git a/docs/description/S2190.md b/docs/description/S2190.md index e872a3b..30d9c25 100644 --- a/docs/description/S2190.md +++ b/docs/description/S2190.md @@ -1,5 +1,5 @@ ## Why is this an issue? - + Having an infinite loop or recursion will lead to a program failure or a program never finishing the execution. public int Sum() @@ -15,17 +15,18 @@ Having an infinite loop or recursion will lead to a program failure or a program } This can happen in multiple scenarios. - + ### Loop statements - -`while` and `for` loops with no `break` or `return` statements that have exit conditions which are always `false` will be indefinitely executed. - + +`while` and `for` loops with no `break` or `return` statements that have exit conditions which are +always `false` will be indefinitely executed. + ### "goto" statements - + `goto` statement with nothing that stops it from being executed over and over again will prevent the program from the completion. - + ### Recursion - + When a [recursive](https://en.wikipedia.org/wiki/Recursion_%28computer_science%29) method call chain lacks an exit condition, the [call stack](https://en.wikipedia.org/wiki/Call_stack) will reach its limit and the program will crash due to a [StackOverflowException](https://learn.microsoft.com/en-us/dotnet/api/system.stackoverflowexception). int Pow(int num, int exponent) @@ -33,10 +34,11 @@ When a [recursive](https://en.wikipedia.org/wiki/Recursion_%28computer_science%2 return num * Pow(num, exponent - 1); // Noncompliant: no condition under which Pow isn't re-called } -In this example, `Pow` will keep calling `Pow` with `exponent - 1` forever, until the program crashes with a StackOverflowException. - +In this example, `Pow` will keep calling `Pow` with `exponent - 1` forever, until the program crashes with a +StackOverflowException. + Recursion provides some benefits. - + - **Simplified code**: recursion can often lead to more concise and elegant code by breaking down complex problems into smaller, more manageable parts. - **Improved code readability**: compared to iterative solutions, recursive solutions can be easier to understand and reason about. @@ -55,9 +57,9 @@ However, it has disadvantages as well. terminated, making it crucial to have proper base cases and exit conditions. ## How to fix it - + The program’s logic should incorporate a mechanism to break out of the control flow loop. Here are some examples. - + ### Code examples - Use a loop condition which eventually evaluates to `false` @@ -142,7 +144,7 @@ The program’s logic should incorporate a mechanism to break out of the control } ## Resources - + ### Documentation - Microsoft Learn - [The "for" statement](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/iteration-statements#the-for-statement) diff --git a/docs/description/S2197.md b/docs/description/S2197.md index 41d1a90..1adbdfe 100644 --- a/docs/description/S2197.md +++ b/docs/description/S2197.md @@ -1,7 +1,8 @@ ## Why is this an issue? - -When the modulus of a negative number is calculated, the result will either be negative or zero. Thus, comparing the modulus of a variable for equality with a positive number (or a negative one) could result in unexpected results. - + +When the modulus of a negative number is calculated, the result will either be negative or zero. Thus, comparing the modulus of a variable for +equality with a positive number (or a negative one) could result in unexpected results. + ### Noncompliant code example public bool IsOdd(int x) diff --git a/docs/description/S2198.md b/docs/description/S2198.md index 1ae1498..fb7767b 100644 --- a/docs/description/S2198.md +++ b/docs/description/S2198.md @@ -1,9 +1,11 @@ ## Why is this an issue? - -Certain [mathematical comparisons](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/comparison-operators) will always return the same value, and should not be performed. - -Specifically, the following comparisons will return either always `true` or always `false` depending on the kind of comparison: - + +Certain [mathematical comparisons](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/comparison-operators) +will always return the same value, and should not be performed. + +Specifically, the following comparisons will return either always `true` or always `false` depending on the kind of +comparison: + - comparing a `char` with a numeric constant that is outside of the range of `char` - comparing a `float` with a numeric constant that is outside of the range of `float` - comparing a `long` with a numeric constant that is outside of the range of `long` @@ -17,7 +19,7 @@ Specifically, the following comparisons will return either always `true` or alwa if (f > double.MaxValue) { } // Noncompliant: always false ## Resources - + ### Documentation - Microsoft Learn: [Comparison diff --git a/docs/description/S2201.md b/docs/description/S2201.md index db28f50..66e2072 100644 --- a/docs/description/S2201.md +++ b/docs/description/S2201.md @@ -1,9 +1,12 @@ ## Why is this an issue? - -When you do not use the return value of a method with no side effects, it indicates that something is wrong. Either this method is unnecessary, or the source code does not behave as expected and could lead to code defects. For example, there are methods, such as [DateTime.AddYears](https://learn.microsoft.com/en-us/dotnet/api/system.datetime.addyears), that don’t change the value of the input object, but instead, they return a new object whose value is the result of this operation, and as a result that you will have unexpected effects if you do not use the return value. - + +When you do not use the return value of a method with no side effects, it indicates that something is wrong. Either this method is unnecessary, or +the source code does not behave as expected and could lead to code defects. For example, there are methods, such as [DateTime.AddYears](https://learn.microsoft.com/en-us/dotnet/api/system.datetime.addyears), that don’t change the value of the input object, +but instead, they return a new object whose value is the result of this operation, and as a result that you will have unexpected effects if you do not +use the return value. + This rule raises an issue when the results of the following methods are ignored: - + - [LINQ](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/linq/) - [`Pure` methods](https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.contracts.pureattribute) - Any method on [build-in types](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/built-in-types) @@ -22,16 +25,17 @@ Special cases: return true; }); -Such code should be rewritten as a loop because [`Enumerable.All`](https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.all) method should be used to determine if all elements satisfy a condition and not to change their state. - +Such code should be rewritten as a loop because [`Enumerable.All`](https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.all) method should be used to +determine if all elements satisfy a condition and not to change their state. + ### Exceptions - + This rule doesn’t report issues on invocations with [`out`](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/out-parameter-modifier) or [`ref`](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/ref) arguments. - + ## How to fix it - + ### Code examples - + #### Noncompliant code example data.Where(x => x > 5).Select(x => x * x); // Noncompliant @@ -54,7 +58,7 @@ This rule doesn’t report issues on invocations with [`out`](https://learn.micr } ## Resources - + ### Documentation - Microsoft Learn - [`PureAttribute` diff --git a/docs/description/S2219.md b/docs/description/S2219.md index 73e8e3d..21e58ae 100644 --- a/docs/description/S2219.md +++ b/docs/description/S2219.md @@ -1,7 +1,7 @@ ## Why is this an issue? - + To check the type of an object there are several options: - + - `expr is SomeType` or `expr.GetType() == typeof(SomeType)` if the type is known at compile time, - `typeInstance.IsInstanceOfType(expr)` if the type is calculated during runtime. @@ -9,8 +9,11 @@ If runtime calculated `Type`s need to be compared: - `typeInstance1.IsAssignableFrom(typeInstance2)`. -Depending on whether the type is returned by a `GetType()` or `typeof()` call, the `IsAssignableFrom()` and `IsInstanceOfType()` might be simplified. Similarly, if the type is `sealed`, the type comparison with `==` can be converted to an `is` call. Simplifying the calls also make `null` checking unnecessary because both `is` and `IsInstanceOfType` performs it already. - +Depending on whether the type is returned by a `GetType()` or `typeof()` call, the `IsAssignableFrom()` and +`IsInstanceOfType()` might be simplified. Similarly, if the type is `sealed`, the type comparison with `==` can be +converted to an `is` call. Simplifying the calls also make `null` checking unnecessary because both `is` and +`IsInstanceOfType` performs it already. + Finally, utilizing the most concise language constructs for type checking makes the code more readable, so - `expr as T != null` checks should be simplified to `expr is T`, and @@ -75,8 +78,10 @@ Finally, utilizing the most concise language constructs for type checking makes } ### Exceptions - -Calling `GetType` on an object of `Nullable` type returns the underlying generic type parameter `T`, thus a comparison with `typeof(Nullable)` can’t be simplified to use the `is` operator, which doesn’t make difference between `T` and `T?`. + +Calling `GetType` on an object of `Nullable` type returns the underlying generic type parameter `T`, thus +a comparison with `typeof(Nullable)` can’t be simplified to use the `is` operator, which doesn’t make difference +between `T` and `T?`. int? i = 42; bool condition = i.GetType() == typeof(int?); // false; diff --git a/docs/description/S2221.md b/docs/description/S2221.md index d6e22e1..c0f03c7 100644 --- a/docs/description/S2221.md +++ b/docs/description/S2221.md @@ -1,7 +1,9 @@ ## Why is this an issue? - -Catching `System.Exception` seems like an efficient way to handle multiple possible exceptions. Unfortunately, it traps all exception types, including the ones that were not intended to be caught. To prevent any misunderstandings, the exception filters should be used. Alternatively each exception type should be in a separate `catch` block. - + +Catching `System.Exception` seems like an efficient way to handle multiple possible exceptions. Unfortunately, it traps all exception +types, including the ones that were not intended to be caught. To prevent any misunderstandings, exception filters should be used. Alternatively, each +exception type should be in a separate `catch` block. + ### Noncompliant code example try @@ -19,14 +21,15 @@ Catching `System.Exception` seems like an efficient way to handle multiple possi { // do something } - catch (Exception e) when (e is FileNotFoundException || e is IOException) + catch (Exception e) when (e is FileNotFoundException or IOException) { // do something } ### Exceptions - -The final option is to catch `System.Exception` and `throw` it in the last statement in the `catch` block. This is the least-preferred option, as it is an old-style code, which also suffers from performance penalty compared to exception filters. + +The final option is to catch `System.Exception` and `throw` it in the last statement in the `catch` block. This is +the least-preferred option, as it is an old-style code, which also suffers from performance penalties compared to exception filters. try { @@ -34,7 +37,7 @@ The final option is to catch `System.Exception` and `throw` it in the last state } catch (Exception e) { - if (e is FileNotFoundException || e is IOException) + if (e is FileNotFoundException or IOException) { // do something } @@ -45,5 +48,5 @@ The final option is to catch `System.Exception` and `throw` it in the last state } ## Resources - + - CWE - [CWE-396 - Declaration of Catch for Generic Exception](https://cwe.mitre.org/data/definitions/396) \ No newline at end of file diff --git a/docs/description/S2222.md b/docs/description/S2222.md index 497ef2b..b98c244 100644 --- a/docs/description/S2222.md +++ b/docs/description/S2222.md @@ -1,11 +1,12 @@ ## Why is this an issue? - -To prevent potential [deadlocks](https://en.wikipedia.org/wiki/Deadlock) in an application, it is crucial to release any locks that are acquired within a method along all possible execution paths. - + +To prevent potential [deadlocks](https://en.wikipedia.org/wiki/Deadlock) in an application, it is crucial to release any locks that are +acquired within a method along all possible execution paths. + Failing to release locks properly can lead to potential deadlocks, where the lock might not be released, causing issues in the application. - + This rule specifically focuses on tracking the following types from the `System.Threading` namespace: - + - [`Monitor`](https://learn.microsoft.com/en-us/dotnet/api/system.threading.monitor) - [`Mutex`](https://learn.microsoft.com/en-us/dotnet/api/system.threading.mutex) - [`ReaderWriterLock`](https://learn.microsoft.com/en-us/dotnet/api/system.threading.readerwriterlock) @@ -13,13 +14,13 @@ This rule specifically focuses on tracking the following types from the `System. - [`SpinLock`](https://learn.microsoft.com/en-us/dotnet/api/system.threading.spinlock) An issue is reported when a lock is acquired within a method but not released on all paths. - + ### Exceptions - + If the lock is never released within the method, no issue is raised, assuming that the callers will handle the release. - + ## How to fix it - + To make sure that a lock is always released correctly, you can follow one of these two methods: - Use a [`lock`](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/lock) statement with your @@ -27,7 +28,7 @@ To make sure that a lock is always released correctly, you can follow one of the - Use a [`try-finally`](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/exception-handling-statements#the-try-finally-statement) statement and put the release of your lock object within the finally block. ### Code examples - + #### Noncompliant code example class MyClass diff --git a/docs/description/S2223.md b/docs/description/S2223.md index b5e305e..cff4607 100644 --- a/docs/description/S2223.md +++ b/docs/description/S2223.md @@ -1,6 +1,7 @@ ## Why is this an issue? - -Unlike instance fields, which can only be accessed by code having a hold on the instance, `static` fields can be accessed by any code having visibility of the field and its type. + +Unlike instance fields, which can only be accessed by code having a hold on the instance, `static` fields can be accessed by any code +having visibility of the field and its type. public class Math { @@ -22,10 +23,11 @@ Another typical scenario of the use of a non-private mutable `static` field is t } } -Non-private `static` fields that are neither `const` nor `readonly`, like the ones in the examples above, can lead to errors and unpredictable behavior. - +Non-private `static` fields that are neither `const` nor `readonly`, like the ones in the examples above, can lead +to errors and unpredictable behavior. + This can happen because: - + - Any object can modify these fields and alter the global state. This makes the code more difficult to read, debug and test. class Counters @@ -76,7 +78,8 @@ This can happen because: } } -Publicly visible `static` fields should only be used to store shared data that does not change. To enforce this intent, these fields should be marked `readonly` or converted to `const`. +Publicly visible `static` fields should only be used to store shared data that does not change. To enforce this intent, these fields +should be marked `readonly` or converted to `const`. public class Math { @@ -93,7 +96,7 @@ Publicly visible `static` fields should only be used to store shared data that d } ## Resources - + ### Documentation - [static (C# Reference)](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/static) diff --git a/docs/description/S2225.md b/docs/description/S2225.md index f7b833a..6bbcd0e 100644 --- a/docs/description/S2225.md +++ b/docs/description/S2225.md @@ -1,7 +1,9 @@ ## Why is this an issue? - -Calling [ToString()](https://learn.microsoft.com/en-us/dotnet/api/system.object.tostring) on an object should always return a `string`. Thus, [overriding the -ToString method](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/how-to-override-the-tostring-method) should never return `null`, as it breaks the method’s implicit contract, and as a result the consumer’s expectations. + +Calling [ToString()](https://learn.microsoft.com/en-us/dotnet/api/system.object.tostring) on an object should always return a +`string`. Thus, [overriding the +ToString method](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/how-to-override-the-tostring-method) should never return `null`, as it breaks the method’s implicit contract, and as a result the consumer’s +expectations. public override string ToString () { @@ -30,9 +32,9 @@ A better alternative is to use the [String.Empty](https://learn.microsoft.com/en } ## Resources - + ### Documentation - + - CWE - [CWE-476 - NULL Pointer Dereference](https://cwe.mitre.org/data/definitions/476) - [Object.ToString Method](https://learn.microsoft.com/en-us/dotnet/api/system.object.tostring) - [How to diff --git a/docs/description/S2234.md b/docs/description/S2234.md index c171a35..2d288b2 100644 --- a/docs/description/S2234.md +++ b/docs/description/S2234.md @@ -1,6 +1,7 @@ ## Why is this an issue? - -Calling a method with argument variables whose names match the method parameter names but in a different order can cause confusion. It could indicate a mistake in the arguments' order, leading to unexpected results. + +Calling a method with argument variables whose names match the method parameter names but in a different order can cause confusion. It could +indicate a mistake in the arguments' order, leading to unexpected results. public double Divide(int divisor, int dividend) { diff --git a/docs/description/S2245.md b/docs/description/S2245.md index f3c2abf..28d4d3b 100644 --- a/docs/description/S2245.md +++ b/docs/description/S2245.md @@ -1,13 +1,16 @@ Using pseudorandom number generators (PRNGs) is security-sensitive. For example, it has led in the past to the following vulnerabilities: - + - [CVE-2013-6386](http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2013-6386) - [CVE-2006-3419](http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2006-3419) - [CVE-2008-4102](http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2008-4102) -When software generates predictable values in a context requiring unpredictability, it may be possible for an attacker to guess the next value that will be generated, and use this guess to impersonate another user or access sensitive information. - -As the `System.Random` class relies on a pseudorandom number generator, it should not be used for security-critical applications or for protecting sensitive data. In such context, the `System.Cryptography.RandomNumberGenerator` class which relies on a cryptographically strong random number generator (RNG) should be used in place. - +When software generates predictable values in a context requiring unpredictability, it may be possible for an attacker to guess the next value that +will be generated, and use this guess to impersonate another user or access sensitive information. + +As the `System.Random` class relies on a pseudorandom number generator, it should not be used for security-critical applications or for +protecting sensitive data. In such context, the `System.Cryptography.RandomNumberGenerator` class which relies on a cryptographically +strong random number generator (RNG) should be used in place. + ## Ask Yourself Whether - the code using the generated value requires it to be unpredictable. It is the case for all encryption mechanisms or when a secret value, such @@ -17,7 +20,7 @@ As the `System.Random` class relies on a pseudorandom number generator, it shoul - an attacker can access the generated value. There is a risk if you answered yes to any of those questions. - + ## Recommended Secure Coding Practices - Only use random number generators which are [recommended by diff --git a/docs/description/S2251.md b/docs/description/S2251.md index 85e73a8..47f668d 100644 --- a/docs/description/S2251.md +++ b/docs/description/S2251.md @@ -1,14 +1,18 @@ ## Why is this an issue? - -A `for` loop with a counter that moves in the wrong direction, away from the stop condition, is not an infinite loop. Because of [wraparound](https://en.wikipedia.org/wiki/Integer_overflow#:~:text=The%20most%20common%20result%20of%20an%20overflow%20is%20that%20the%20least%20significant%20representable%20digits%20of%20the%20result%20are%20stored%3B%20the%20result%20is%20said%20to%20wrap%20around%20the%20maximum), the loop will eventually reach its stop condition, but in doing so, it will probably run more times than anticipated, potentially causing unexpected behavior. - + +A `for` loop with a counter that moves in the wrong direction, away from the stop condition, is not an infinite loop. Because of [wraparound](https://en.wikipedia.org/wiki/Integer_overflow#:~:text=The%20most%20common%20result%20of%20an%20overflow%20is%20that%20the%20least%20significant%20representable%20digits%20of%20the%20result%20are%20stored%3B%20the%20result%20is%20said%20to%20wrap%20around%20the%20maximum), +the loop will eventually reach its stop condition, but in doing so, it will probably run more times than anticipated, potentially causing unexpected +behavior. + ## How to fix it - + If your [stop -condition](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/iteration-statements#the-for-statement:~:text=The%20condition%20section%20that%20determines%20if%20the%20next%20iteration%20in%20the%20loop%20should%20be%20executed) indicates a **maximum** value, the [iterator](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/iteration-statements#the-for-statement:~:text=The%20iterator%20section%20that%20defines%20what%20happens%20after%20each%20execution%20of%20the%20body%20of%20the%20loop) should **increase** towards it. Conversely, if your stop condition indicates a **minimum** value, the iterator should **decrease** towards it. - +condition](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/iteration-statements#the-for-statement:~:text=The%20condition%20section%20that%20determines%20if%20the%20next%20iteration%20in%20the%20loop%20should%20be%20executed) indicates a **maximum** value, the [iterator](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/iteration-statements#the-for-statement:~:text=The%20iterator%20section%20that%20defines%20what%20happens%20after%20each%20execution%20of%20the%20body%20of%20the%20loop) +should **increase** towards it. Conversely, if your stop condition indicates a **minimum** value, the iterator should +**decrease** towards it. + ### Code examples - + #### Noncompliant code example for (int i = 0; i < maximum; i--) // Noncompliant: runs until it underflows to int.MaxValue @@ -33,9 +37,9 @@ condition](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/st } ## Resources - + ### Documentation - + - [Integer overflow](https://en.wikipedia.org/wiki/Integer_overflow) - [The `for` statement](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/iteration-statements#the-for-statement) \ No newline at end of file diff --git a/docs/description/S2252.md b/docs/description/S2252.md index 39c859d..019c432 100644 --- a/docs/description/S2252.md +++ b/docs/description/S2252.md @@ -1,6 +1,8 @@ ## Why is this an issue? - -A [`for`](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/iteration-statements#the-for-statement) loop is a fundamental programming construct used to execute a block of code repeatedly. However, if the loop’s condition is false before the first iteration, the loop will never execute. + +A [`for`](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/iteration-statements#the-for-statement) loop +is a fundamental programming construct used to execute a block of code repeatedly. However, if the loop’s condition is false before the first +iteration, the loop will never execute. for (int i = 0; i < 0; i++) // Noncompliant: the condition is always false, the loop will never execute { @@ -15,10 +17,10 @@ Rewrite the loop to ensure the condition evaluates to `true` at least once. } This bug has the potential to cause unexpected outcomes as the loop might contain critical code that needs to be executed. - + ## Resources - + ### Documentation - + - Microsoft Learn - [The `for` statement](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/iteration-statements#the-for-statement) \ No newline at end of file diff --git a/docs/description/S2257.md b/docs/description/S2257.md index 26016c9..b59f2c6 100644 --- a/docs/description/S2257.md +++ b/docs/description/S2257.md @@ -1,7 +1,8 @@ -The use of a non-standard algorithm is dangerous because a determined attacker may be able to break the algorithm and compromise whatever data has been protected. Standard algorithms like `AES`, `RSA`, `SHA`, …​ should be used instead. - +The use of a non-standard algorithm is dangerous because a determined attacker may be able to break the algorithm and compromise whatever data has +been protected. Standard algorithms like `AES`, `RSA`, `SHA`, …​ should be used instead. + This rule tracks custom implementation of these types from `System.Security.Cryptography` namespace: - + - `AsymmetricAlgorithm` - `AsymmetricKeyExchangeDeformatter` - `AsymmetricKeyExchangeFormatter` diff --git a/docs/description/S2259.md b/docs/description/S2259.md index fd1dc8f..668b02c 100644 --- a/docs/description/S2259.md +++ b/docs/description/S2259.md @@ -1,15 +1,16 @@ ## Why is this an issue? - -Accessing a [null](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/null) value will always throw a [NullReferenceException](https://learn.microsoft.com/en-us/dotnet/api/system.nullreferenceexception) most likely causing an abrupt program termination. - + +Accessing a [null](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/null) value will always throw a [NullReferenceException](https://learn.microsoft.com/en-us/dotnet/api/system.nullreferenceexception) most likely causing an abrupt program +termination. + Such termination might expose sensitive information that a malicious third party could exploit to, for instance, bypass security measures. - + ### Exceptions - + In the following cases, the rule does not raise: - + #### Extensions Methods - + Calls to extension methods can still operate on `null` values. using System; @@ -33,7 +34,7 @@ Calls to extension methods can still operate on `null` values. } #### Unreachable code - + Unreachable code is not executed, thus `null` values will never be accessed. public void Method() @@ -46,15 +47,18 @@ Unreachable code is not executed, thus `null` values will never be accessed. } #### Validated value by analysis attributes - -[Nullable analysis attributes](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/nullable-analysis) enable the developer to annotate methods with information about the null-state of its arguments. Thus, potential `null` values validated by one of the following attributes will not raise: - + +[Nullable analysis attributes](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/nullable-analysis) enable +the developer to annotate methods with information about the null-state of its arguments. Thus, potential `null` values validated by one of +the following attributes will not raise: + - [NotNullAttribute](https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.codeanalysis.notnullattribute) - [NotNullWhenAttribute](https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.codeanalysis.notnullwhenattribute) - [DoesNotReturnAttribute](https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.codeanalysis.doesnotreturnattribute) - [DoesNotReturnIfAttribute](https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.codeanalysis.doesnotreturnifattribute) -It is important to note those attributes are only available starting .NET Core 3. As a workaround, it is possible to define those attributes manually in a custom class: +It is important to note those attributes are only available starting .NET Core 3. As a workaround, it is possible to define those attributes +manually in a custom class: using System; @@ -81,8 +85,9 @@ It is important to note those attributes are only available starting .NET Core 3 } #### Validated value by Debug.Assert - -A value validated with [Debug.Assert](https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.debug.assert) to not be `null` is safe to access. + +A value validated with [Debug.Assert](https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.debug.assert) to not be +`null` is safe to access. using System.Diagnostics; @@ -93,9 +98,9 @@ A value validated with [Debug.Assert](https://learn.microsoft.com/en-us/dotnet/a } #### Validated value by IDE-specific attributes - + Like with null-analysis-attribute, potential `null` values validated by one of the following IDE-specific attributes will not raise - + ##### Visual Studio - [ValidatedNotNullAttribute](https://learn.microsoft.com/en-us/dotnet/api/microsoft.validatednotnullattribute) (The attribute is @@ -126,7 +131,7 @@ Like with null-analysis-attribute, potential `null` values validated by one of t } #### Null forgiving operator - + Expression marked with the [null forgiving operator](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/null-forgiving) @@ -137,16 +142,16 @@ operator](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/ope } ## How to fix it - + To fix the issue, the access of the `null` value needs to be prevented by either: - ensuring the variable has a value, or - by checking if the value is not `null` ### Code examples - + #### Noncompliant code example - + The variable `myObject` is equal to `null`, meaning it has no value: public void Method() @@ -167,7 +172,7 @@ The parameter `input` might be `null` as suggested by the `if` condition: } #### Compliant solution - + Ensuring the variable `myObject` has a value resolves the issue: public void Method() @@ -188,7 +193,7 @@ Preventing the non-compliant code to be executed by returning early: } ## Resources - + ### Documentation - CVE - [CWE-476 - NULL Pointer Dereference](https://cwe.mitre.org/data/definitions/476) diff --git a/docs/description/S2275.md b/docs/description/S2275.md index 8b2a3cb..4f31751 100644 --- a/docs/description/S2275.md +++ b/docs/description/S2275.md @@ -1,7 +1,10 @@ ## Why is this an issue? - -Composite format strings in C# are evaluated at runtime, which means they are not verified by the compiler. Introducing an ill-formed format item, or indexing mismatch can lead to unexpected behaviors or runtime errors. The purpose of this rule is to perform static validation on composite format strings used in various string formatting functions to ensure their correct usage. This rule validates the proper behavior of composite formats when invoking the following methods: - + +Composite format strings in C# are evaluated at runtime, which means they are not verified by the compiler. Introducing an ill-formed format item, +or indexing mismatch can lead to unexpected behaviors or runtime errors. The purpose of this rule is to perform static validation on composite format +strings used in various string formatting functions to ensure their correct usage. This rule validates the proper behavior of composite formats when +invoking the following methods: + - `String.Format` - `StringBuilder.AppendFormat` - `Console.Write` @@ -32,8 +35,9 @@ Composite format strings in C# are evaluated at runtime, which means they are no s = string.Format("no format"); // Compliant ### Exceptions - -The rule does not perform any checks on the format specifier, if present (defined after the `:`). Moreover, no issues are raised in the following cases: + +The rule does not perform any checks on the format specifier, if present (defined after the `:`). Moreover, no issues are raised in the +following cases: - the format string is not a `const`. @@ -45,7 +49,7 @@ The rule does not perform any checks on the format specifier, if present (define var res = string.Format("{0} {1}", array); // Compliant the rule does not check the size of the array ## Resources - + ### Documentation - [Composite formatting](https://learn.microsoft.com/en-us/dotnet/standard/base-types/composite-formatting) diff --git a/docs/description/S2290.md b/docs/description/S2290.md index 043d6da..47221e8 100644 --- a/docs/description/S2290.md +++ b/docs/description/S2290.md @@ -1,13 +1,17 @@ ## Why is this an issue? - -[Field-like](https://learn.microsoft.com/en-us/dotnet/csharp/event-pattern#define-and-raise-field-like-events) events are events that do not have explicit [`add`](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/add) and [`remove`](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/remove) accessors. + +[Field-like](https://learn.microsoft.com/en-us/dotnet/csharp/event-pattern#define-and-raise-field-like-events) events are events that do +not have explicit [`add`](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/add) and [`remove`](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/remove) accessors. public event EventHandler MyEvent; // No add and remove accessors -The compiler generates a `private` `delegate` field to back the event, as well as generating the implicit `add` and `remove` accessors. - -When a `virtual` field-like `event` is overridden by another field-like `event`, the behavior of the C# compiler is to generate a new `private` `delegate` field in the derived class, separate from the parent’s field. This results in multiple and separate events being created, which is rarely what’s actually intended. - +The compiler generates a `private` `delegate` field to back the event, as well as generating the implicit `add` +and `remove` accessors. + +When a `virtual` field-like `event` is overridden by another field-like `event`, the behavior of the C# compiler +is to generate a new `private` `delegate` field in the derived class, separate from the parent’s field. This results in multiple +and separate events being created, which is rarely what’s actually intended. + ### Noncompliant code example abstract class Car @@ -43,7 +47,7 @@ When a `virtual` field-like `event` is overridden by another field-like `event`, } ### Compliant solution - + To prevent this, remove the `virtual` designation from the parent class event. abstract class Car @@ -78,9 +82,9 @@ To prevent this, remove the `virtual` designation from the parent class event. } ## Resources - + ### Documentation - + - [Add keyword](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/add) - [Remove keyword](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/remove) - [Delegates](https://learn.microsoft.com/en-us/dotnet/csharp/delegate-class) diff --git a/docs/description/S2291.md b/docs/description/S2291.md index e01a771..f34df7a 100644 --- a/docs/description/S2291.md +++ b/docs/description/S2291.md @@ -1,12 +1,16 @@ ## Why is this an issue? - -[Enumerable.Sum()](https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.sum) always executes addition in a `checked` context, so an [OverflowException](https://learn.microsoft.com/en-us/dotnet/api/system.overflowexception) will be thrown if the value exceeds `MaxValue`, even if an `unchecked` context was specified. Therefore, using this method inside an `unchecked` context will only make the code more confusing, since the behavior will still be `checked`. - + +[Enumerable.Sum()](https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.sum) always executes addition in a +`checked` context, so an [OverflowException](https://learn.microsoft.com/en-us/dotnet/api/system.overflowexception) will be +thrown if the value exceeds `MaxValue`, even if an `unchecked` context was specified. Therefore, using this method inside an +`unchecked` context will only make the code more confusing, since the behavior will still be `checked`. + This rule raises an issue when an `unchecked` context is specified for a `Sum` on integer types. - + ### Exceptions - -When the `Sum` call is inside a [try-catch block](https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/exceptions/), no issues are reported, since the exception is properly handled. + +When the `Sum` call is inside a [try-catch block](https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/exceptions/), +no issues are reported, since the exception is properly handled. void Add(List list) { @@ -24,11 +28,11 @@ When the `Sum` call is inside a [try-catch block](https://learn.microsoft.com/en } ## How to fix it - + Remove the `unchecked` operator/statement, and optionally add some exception handling for the `OverflowException`. - + ### Code examples - + #### Noncompliant code example void Add(List list) @@ -58,9 +62,9 @@ Remove the `unchecked` operator/statement, and optionally add some exception han } ## Resources - + ### Documentation - + - [`Enumerable.Sum` Method](https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.sum) - [`Enumerable.Sum` implementation](https://github.com/microsoft/referencesource/blob/51cf7850defa8a17d815b4700b67116e3fa283c2/System.Core/System/Linq/Enumerable.cs#L1408-L1415) - [`checked` and diff --git a/docs/description/S2292.md b/docs/description/S2292.md index c3d1158..ea5dccd 100644 --- a/docs/description/S2292.md +++ b/docs/description/S2292.md @@ -1,7 +1,8 @@ ## Why is this an issue? - -Trivial properties, which include no logic but setting and getting a backing field should be converted to auto-implemented properties, yielding cleaner and more readable code. - + +Trivial properties, which include no logic but setting and getting a backing field should be converted to auto-implemented properties, yielding +cleaner and more readable code. + ### Noncompliant code example public class Car diff --git a/docs/description/S2302.md b/docs/description/S2302.md index 167b753..5d7c804 100644 --- a/docs/description/S2302.md +++ b/docs/description/S2302.md @@ -1,9 +1,10 @@ ## Why is this an issue? - -Because parameter names could be changed during refactoring, they should not be spelled out literally in strings. Instead, use `nameof()`, and the string that’s output will always be correct. - + +Because parameter names could be changed during refactoring, they should not be spelled out literally in strings. Instead, use +`nameof()`, and the string that’s output will always be correct. + This rule raises an issue when a string in the `throw` statement contains the name of one of the method parameters. - + ### Noncompliant code example void DoSomething(int someParameter, string anotherParam) @@ -33,7 +34,7 @@ This rule raises an issue when a string in the `throw` statement contains the na } ### Exceptions - + - The rule doesn’t raise any issue when using C# < 6.0. - When the parameter name is contained in a sentence inside the `throw` statement string, the rule will raise an issue only if the parameter name is at least 5 characters long. This is to avoid false positives. \ No newline at end of file diff --git a/docs/description/S2306.md b/docs/description/S2306.md index 6d35e13..49d18fb 100644 --- a/docs/description/S2306.md +++ b/docs/description/S2306.md @@ -1,11 +1,13 @@ ## Why is this an issue? - -Since C# 5.0, `async` and `await` are [contextual keywords](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/#contextual-keywords). Contextual keywords do have a particular meaning in some contexts, but are not reserved and therefore can be used as variable names. + +Since C# 5.0, `async` and `await` are [contextual keywords](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/#contextual-keywords). Contextual keywords +do have a particular meaning in some contexts, but are not reserved and therefore can be used as variable names. int await = 42; // Noncompliant, but compiles int async = 42; // Noncompliant, but compiles -[Keywords](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords), on the other hand, are always reserved and therefore are not valid variable names. +[Keywords](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords), on the other hand, are always reserved and +therefore are not valid variable names. int abstract = 42; // Error CS1585: Member modifier 'abstract' must precede the member type and name int foreach = 42; // Error CS1519: Invalid token 'foreach' in class, struct, or interface member declaration @@ -16,8 +18,8 @@ To avoid any confusion, it is best to not use `async` and `await` as identifiers int someOtherVariableName = 42; ## Resources - + ### Documentation - + - [Contextual Keywords - MSDN](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/#contextual-keywords) - [Asynchronous programming - MSDN](https://learn.microsoft.com/en-us/dotnet/csharp/asynchronous-programming/) \ No newline at end of file diff --git a/docs/description/S2326.md b/docs/description/S2326.md index b27b596..6451c62 100644 --- a/docs/description/S2326.md +++ b/docs/description/S2326.md @@ -1,7 +1,8 @@ ## Why is this an issue? - -Type parameters that aren’t used are dead code, which can only distract and possibly confuse developers during maintenance. Therefore, unused type parameters should be removed. - + +Type parameters that aren’t used are dead code, which can only distract and possibly confuse developers during maintenance. Therefore, unused type +parameters should be removed. + ### Noncompliant code example public class MoreMath // Noncompliant; is ignored diff --git a/docs/description/S2327.md b/docs/description/S2327.md index 1271c61..2d59ecb 100644 --- a/docs/description/S2327.md +++ b/docs/description/S2327.md @@ -1,7 +1,9 @@ ## Why is this an issue? - -When multiple, adjacent `try` statements have duplicate `catch` and/or `finally` blocks, they should be merged to consolidate the `catch/finally` logic for cleaner, more readable code. Note that this applies even when there is intervening code outside any `try` block. - + +When multiple, adjacent `try` statements have duplicate `catch` and/or `finally` blocks, they should be merged to +consolidate the `catch/finally` logic for cleaner, more readable code. Note that this applies even when there is intervening code outside +any `try` block. + ### Noncompliant code example try diff --git a/docs/description/S2328.md b/docs/description/S2328.md index 2c7699f..e7daaee 100644 --- a/docs/description/S2328.md +++ b/docs/description/S2328.md @@ -1,16 +1,19 @@ ## Why is this an issue? - -`GetHashCode` is used to file an object in a `Dictionary` or `Hashtable`. If `GetHashCode` uses non-`readonly` fields and those fields change after the object is stored, the object immediately becomes mis-filed in the `Hashtable`. Any subsequent test to see if the object is in the `Hashtable` will return a false negative. - + +`GetHashCode` is used to file an object in a `Dictionary` or `Hashtable`. If `GetHashCode` uses +non-`readonly` fields and those fields change after the object is stored, the object immediately becomes mis-filed in the +`Hashtable`. Any subsequent test to see if the object is in the `Hashtable` will return a false negative. + ### Exceptions - + This rule does not raise if the type implementing `GetHashCode` is a value type, for example a `struct` or a `record -struct`, since when a value type is stored in a `Dictionary` or `Hashtable`, a copy of the value is stored, not a reference to the value. - +struct`, since when a value type is stored in a `Dictionary` or `Hashtable`, a copy of the value is stored, not a +reference to the value. + ## How to fix it - + ### Code examples - + #### Noncompliant code example public class Person diff --git a/docs/description/S2330.md b/docs/description/S2330.md index edcb17f..b11f514 100644 --- a/docs/description/S2330.md +++ b/docs/description/S2330.md @@ -1,9 +1,12 @@ ## Why is this an issue? - -Array covariance is the principle that if an implicit or explicit reference conversion exits from type `A` to `B`, then the same conversion exists from the array type `A[]` to `B[]`. - -While this array conversion can be useful in readonly situations to pass instances of `A[]` where `B[]` is expected, it must be used with care, since assigning an instance of `B` into an array of `A` will cause an `ArrayTypeMismatchException` to be thrown at runtime. - + +Array covariance is the principle that if an implicit or explicit reference conversion exits from type `A` to `B`, then the +same conversion exists from the array type `A[]` to `B[]`. + +While this array conversion can be useful in readonly situations to pass instances of `A[]` where `B[]` is expected, it must +be used with care, since assigning an instance of `B` into an array of `A` will cause an `ArrayTypeMismatchException` +to be thrown at runtime. + ### Noncompliant code example abstract class Fruit { } diff --git a/docs/description/S2333.md b/docs/description/S2333.md index 06e4ce8..9027723 100644 --- a/docs/description/S2333.md +++ b/docs/description/S2333.md @@ -1,7 +1,7 @@ ## Why is this an issue? - + Unnecessary keywords simply clutter the code and should be removed. Specifically: - + - `partial` on type declarations that are completely defined in one place - `sealed` on members of `sealed` classes - `unsafe` method or block inside construct already marked with `unsafe`, or when there are no `unsafe` diff --git a/docs/description/S2339.md b/docs/description/S2339.md index c8222e2..d380d38 100644 --- a/docs/description/S2339.md +++ b/docs/description/S2339.md @@ -1,13 +1,17 @@ ## Why is this an issue? - + Constant members are copied at compile time to the call sites, instead of being fetched at runtime. - -As an example, say you have a library with a constant `Version` member set to `1.0`, and a client application linked to it. This library is then updated and `Version` is set to `2.0`. Unfortunately, even after the old DLL is replaced by the new one, `Version` will still be `1.0` for the client application. In order to see `2.0`, the client application would need to be rebuilt against the new version of the library. - -This means that you should use constants to hold values that by definition will never change, such as `Zero`. In practice, those cases are uncommon, and therefore it is generally better to avoid constant members. - + +As an example, say you have a library with a constant `Version` member set to `1.0`, and a client application linked to it. +This library is then updated and `Version` is set to `2.0`. Unfortunately, even after the old DLL is replaced by the new one, +`Version` will still be `1.0` for the client application. In order to see `2.0`, the client application would need to +be rebuilt against the new version of the library. + +This means that you should use constants to hold values that by definition will never change, such as `Zero`. In practice, those cases +are uncommon, and therefore it is generally better to avoid constant members. + This rule only reports issues on public constant fields, which can be reached from outside the defining assembly. - + ### Noncompliant code example public class Foo diff --git a/docs/description/S2342.md b/docs/description/S2342.md index 091e217..d80167d 100644 --- a/docs/description/S2342.md +++ b/docs/description/S2342.md @@ -1,16 +1,17 @@ ## Why is this an issue? - -Shared naming conventions allow teams to collaborate efficiently. This rule checks that all `enum` names match a provided regular expression. - + +Shared naming conventions allow teams to collaborate efficiently. This rule checks that all `enum` names match a provided regular +expression. + The default configuration is the one recommended by Microsoft: - + - Pascal casing, starting with an upper case character, e.g. BackColor - Short abbreviations of 2 letters can be capitalized, e.g. GetID - Longer abbreviations need to be lower case, e.g. GetHtml - If the enum is marked as [Flags] then its name should be plural (e.g. MyOptions), otherwise, names should be singular (e.g. MyOption) ### Noncompliant code example - + With the default regular expression for non-flags enums: `^([A-Z]{1,3}[a-z0-9]+)*([A-Z]{2})?$` public enum foo // Noncompliant diff --git a/docs/description/S2344.md b/docs/description/S2344.md index a52c6d4..77755ef 100644 --- a/docs/description/S2344.md +++ b/docs/description/S2344.md @@ -1,7 +1,7 @@ ## Why is this an issue? - + The information that an enumeration type is actually an enumeration or a set of flags should not be duplicated in its name. - + ### Noncompliant code example enum FooFlags // Noncompliant diff --git a/docs/description/S2345.md b/docs/description/S2345.md index f005701..7b4aebd 100644 --- a/docs/description/S2345.md +++ b/docs/description/S2345.md @@ -1,17 +1,21 @@ ## Why is this an issue? - -When you annotate an [Enum](https://learn.microsoft.com/en-us/dotnet/api/system.enum) with the [Flags attribute](https://learn.microsoft.com/en-us/dotnet/api/system.flagsattribute), you must not rely on the values that are automatically set by the language to the `Enum` members, but you should define the enumeration constants in powers of two (1, 2, 4, 8, and so on). Automatic value initialization will set the first member to zero and increment the value by one for each subsequent member. As a result, you won’t be able to use the enum members with bitwise operators. - + +When you annotate an [Enum](https://learn.microsoft.com/en-us/dotnet/api/system.enum) with the [Flags attribute](https://learn.microsoft.com/en-us/dotnet/api/system.flagsattribute), you must not rely on the values that are automatically +set by the language to the `Enum` members, but you should define the enumeration constants in powers of two (1, 2, 4, 8, and so on). +Automatic value initialization will set the first member to zero and increment the value by one for each subsequent member. As a result, you won’t be +able to use the enum members with bitwise operators. + ### Exceptions - -The default initialization of `0, 1, 2, 3, 4, …​` matches `0, 1, 2, 4, 8 …​` in the first three values, so no issue is reported if the first three members of the enumeration are not initialized. - + +The default initialization of `0, 1, 2, 3, 4, …​` matches `0, 1, 2, 4, 8 …​` in the first three values, so no issue is +reported if the first three members of the enumeration are not initialized. + ## How to fix it - + Define enumeration constants in powers of two, that is, 1, 2, 4, 8, and so on. - + ### Code examples - + #### Noncompliant code example var bananaAndStrawberry = FruitType.Banana | FruitType.Strawberry; @@ -41,8 +45,8 @@ Define enumeration constants in powers of two, that is, 1, 2, 4, 8, and so on. } ## Resources - + ### Documentation - + - [Enum Class](https://learn.microsoft.com/en-us/dotnet/api/system.enum) - [FlagsAttribute Class](https://learn.microsoft.com/en-us/dotnet/api/system.flagsattribute) \ No newline at end of file diff --git a/docs/description/S2346.md b/docs/description/S2346.md index fa7fec9..305d6e5 100644 --- a/docs/description/S2346.md +++ b/docs/description/S2346.md @@ -1,7 +1,9 @@ ## Why is this an issue? - -An enumeration can be decorated with the [FlagsAttribute](https://learn.microsoft.com/en-us/dotnet/api/system.flagsattribute) to indicate that it can be used as a [bit field](https://en.wikipedia.org/wiki/Bit_field): a set of flags, that can be independently set and reset. - + +An enumeration can be decorated with the [FlagsAttribute](https://learn.microsoft.com/en-us/dotnet/api/system.flagsattribute) to +indicate that it can be used as a [bit field](https://en.wikipedia.org/wiki/Bit_field): a set of flags, that can be independently set and +reset. + For example, the following definition of the day of the week: [Flags] @@ -39,7 +41,8 @@ These can be used to write more expressive conditions, taking advantage of [bitw someDays & Days.Weekend != Days.None; // someDays overlaps with the weekend someDays & Days.Weekdays == Days.Weekdays; // someDays is only made of weekdays -Consistent use of `None` in flag enumerations indicates that all flag values are cleared. The value 0 should not be used to indicate any other state since there is no way to check that the bit `0` is set. +Consistent use of `None` in flag enumerations indicates that all flag values are cleared. The value 0 should not be used to indicate any +other state since there is no way to check that the bit `0` is set. [Flags] enum Days @@ -62,9 +65,9 @@ Consistent use of `None` in flag enumerations indicates that all flag values are someDays.HasFlag(Days.Monday) // Same issue as above ## How to fix it - + ### Code examples - + #### Noncompliant code example [Flags] @@ -88,9 +91,9 @@ Consistent use of `None` in flag enumerations indicates that all flag values are } ## Resources - + ### Documentation - + - [FlagsAttribute](https://learn.microsoft.com/en-us/dotnet/api/system.flagsattribute) - [Bit field](https://en.wikipedia.org/wiki/Bit_field) - [Bitwise and shift operators diff --git a/docs/description/S2357.md b/docs/description/S2357.md index 37c78d1..4a447e7 100644 --- a/docs/description/S2357.md +++ b/docs/description/S2357.md @@ -1,7 +1,9 @@ ## Why is this an issue? - -Fields should not be part of an API, and therefore should always be private. Indeed, they cannot be added to an interface for instance, and validation cannot be added later on without breaking backward compatibility. Instead, developers should encapsulate their fields into properties. Explicit property getters and setters can be introduced for validation purposes or to smooth the transition to a newer system. - + +Fields should not be part of an API, and therefore should always be private. Indeed, they cannot be added to an interface for instance, and +validation cannot be added later on without breaking backward compatibility. Instead, developers should encapsulate their fields into properties. +Explicit property getters and setters can be introduced for validation purposes or to smooth the transition to a newer system. + ### Noncompliant code example public class Foo @@ -27,7 +29,7 @@ or } ### Exceptions - + `struct`s are ignored, as are `static` and `const` fields in classes. - + Further, an issue is only raised when the real accessibility is `public`, taking into account the class accessibility. \ No newline at end of file diff --git a/docs/description/S2360.md b/docs/description/S2360.md index 90b5284..f492a6f 100644 --- a/docs/description/S2360.md +++ b/docs/description/S2360.md @@ -1,7 +1,7 @@ ## Why is this an issue? - + The overloading mechanism should be used in place of optional parameters for several reasons: - + - Optional parameter values are baked into the method call site code, thus, if a default value has been changed, all referencing assemblies need to be rebuilt, otherwise the original values will be used. - The Common Language Specification (CLS) allows compilers to ignore default parameter values, and thus require the caller to explicitly specify @@ -27,5 +27,5 @@ The overloading mechanism should be used in place of optional parameters for sev } ### Exceptions - + The rule ignores non externally visible methods. \ No newline at end of file diff --git a/docs/description/S2365.md b/docs/description/S2365.md index 6782d57..92ada20 100644 --- a/docs/description/S2365.md +++ b/docs/description/S2365.md @@ -1,38 +1,39 @@ ## Why is this an issue? - -Most developers expect property access to be as efficient as field access. However, if a property returns a copy of an array or collection, it will be much slower than a simple field access, contrary to the caller’s likely expectations. Therefore, such properties should be refactored into methods so that callers are not surprised by the unexpectedly poor performance. - + +Most developers expect property access to be as efficient as field access. However, if a property returns a copy of an array or collection, it will +be much slower than a simple field access, contrary to the caller’s likely expectations. Therefore, such properties should be refactored into methods +so that callers are not surprised by the unexpectedly poor performance. + This rule tracks calls to the following methods inside properties: - + - [Enumerable.ToList](https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.tolist) - [Enumerable.ToArray](https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.toarray) - [Array.Clone](https://learn.microsoft.com/en-us/dotnet/api/system.array.clone) ## How to fix it - + ### Code examples - + #### Noncompliant code example - private List _foo = new List { "a", "b", "c" }; - public IEnumerable Foo // Noncompliant: expensive ToList call - { - get - { - return (string[])_foo.Clone(); - } - } + private List foo = new List { "a", "b", "c" }; + private string[] bar = new string[] { "a", "b", "c" }; + + public IEnumerable Foo => foo.ToList(); // Noncompliant: collection foo is copied + + public IEnumerable Bar => (string[])bar.Clone(); // Noncompliant: array bar is copied #### Compliant solution - private List _foo = new List { "a", "b", "c" }; - public IEnumerable GetFoo() - { - return (string[])_foo.Clone(); - } + private List foo = new List { "a", "b", "c" }; + private string[] bar = new string[] { "a", "b", "c" }; + + public IEnumerable GetFoo() => foo.ToList(); + + public IEnumerable GetBar() => (string[])bar.Clone(); ## Resources - + ### Documentation - [Properties (C# Programming diff --git a/docs/description/S2368.md b/docs/description/S2368.md index 8b43435..7823034 100644 --- a/docs/description/S2368.md +++ b/docs/description/S2368.md @@ -1,9 +1,10 @@ ## Why is this an issue? - -Using [multidimensional](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/multidimensional-arrays) and [jagged](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/jagged-arrays) arrays as method parameters in C# can be challenging for developers. - + +Using [multidimensional](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/multidimensional-arrays) and [jagged](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/jagged-arrays) arrays as method parameters in C# can be +challenging for developers. + When these methods are exposed to external users, it requires advanced language knowledge for effective usage. - + Determining the appropriate data to pass to these parameters may not be intuitive. public class Program @@ -15,8 +16,9 @@ Determining the appropriate data to pass to these parameters may not be intuitiv } In this example, it cannot be inferred easily what the matrix should look like. Is it a 2x2 Matrix or even a triangular Matrix? - -Using a collection, data structure, or class that provides a more suitable representation of the required data is recommended instead of a multidimensional array or jagged array to enhance code readability. + +Using a collection, data structure, or class that provides a more suitable representation of the required data is recommended instead of a +multidimensional array or jagged array to enhance code readability. public class Matrix2x2 { @@ -32,10 +34,11 @@ Using a collection, data structure, or class that provides a more suitable repre } As a result, avoiding exposing such methods to external users is recommended. - + ### Exceptions - -However, using multidimensional and jagged array method parameters internally, such as in `private` or `internal` methods or within `internal` classes, is compliant since they are not publicly exposed. + +However, using multidimensional and jagged array method parameters internally, such as in `private` or `internal` methods or +within `internal` classes, is compliant since they are not publicly exposed. public class FirstClass { @@ -54,9 +57,9 @@ However, using multidimensional and jagged array method parameters internally, s } ## Resources - + ### Documentation - + - [Collections and Data Structures](https://learn.microsoft.com/en-us/dotnet/standard/collections/) - [Jagged Arrays](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/jagged-arrays) - [Multidimensional Arrays](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/multidimensional-arrays) \ No newline at end of file diff --git a/docs/description/S2372.md b/docs/description/S2372.md index c77bdee..fc16c21 100644 --- a/docs/description/S2372.md +++ b/docs/description/S2372.md @@ -1,9 +1,10 @@ ## Why is this an issue? - -Property getters should be simple operations that are always safe to call. If exceptions need to be thrown, it is best to convert the property to a method. - + +Property getters should be simple operations that are always safe to call. If exceptions need to be thrown, it is best to convert the property to a +method. + It is valid to throw exceptions from indexed property getters and from property setters, which are not detected by this rule. - + ### Noncompliant code example public int Foo @@ -25,5 +26,6 @@ It is valid to throw exceptions from indexed property getters and from property } ### Exceptions - -No issue is raised when the thrown exception derives from or is of type `NotImplementedException`, `NotSupportedException` or `InvalidOperationException`. \ No newline at end of file + +No issue is raised when the thrown exception derives from or is of type `NotImplementedException`, `NotSupportedException` or +`InvalidOperationException`. \ No newline at end of file diff --git a/docs/description/S2376.md b/docs/description/S2376.md index 3a707b9..40c8997 100644 --- a/docs/description/S2376.md +++ b/docs/description/S2376.md @@ -1,7 +1,8 @@ ## Why is this an issue? - -Properties with only setters are confusing and counterintuitive. Instead, a property getter should be added if possible, or the property should be replaced with a setter method. - + +Properties with only setters are confusing and counterintuitive. Instead, a property getter should be added if possible, or the property should be +replaced with a setter method. + ### Noncompliant code example class Program diff --git a/docs/description/S2386.md b/docs/description/S2386.md index 65d1cb0..f01dd91 100644 --- a/docs/description/S2386.md +++ b/docs/description/S2386.md @@ -1,9 +1,11 @@ ## Why is this an issue? - -`public static` mutable fields of classes which are accessed directly should be protected to the degree possible. This can be done by reducing the accessibility of the field or by changing the return type to an immutable type. - -This rule raises issues for `public static` fields with a type inheriting/implementing `System.Array` or `System.Collections.Generic.ICollection`. - + +`public static` mutable fields of classes which are accessed directly should be protected to the degree possible. This can be done by +reducing the accessibility of the field or by changing the return type to an immutable type. + +This rule raises issues for `public static` fields with a type inheriting/implementing `System.Array` or +`System.Collections.Generic.ICollection`. + ### Noncompliant code example public class A @@ -21,9 +23,9 @@ This rule raises issues for `public static` fields with a type inheriting/implem } ### Exceptions - + No issue is reported: - + - If the type of the field inherits/implements one (at least) of the following types: - [`System.Collections.ObjectModel.ReadOnlyCollection`](https://learn.microsoft.com/en-us/dotnet/api/system.collections.objectmodel.readonlycollection-1) - [`System.Collections.ObjectModel.ReadOnlyDictionary`](https://learn.microsoft.com/en-us/dotnet/api/system.collections.objectmodel.readonlydictionary-2) diff --git a/docs/description/S2387.md b/docs/description/S2387.md index f18d1d0..0017a0e 100644 --- a/docs/description/S2387.md +++ b/docs/description/S2387.md @@ -1,7 +1,8 @@ ## Why is this an issue? - -Having a variable with the same name in two unrelated classes is fine, but do the same thing within a class hierarchy and you’ll get confusion at best, chaos at worst. - + +Having a variable with the same name in two unrelated classes is fine, but do the same thing within a class hierarchy and you’ll get confusion at +best, chaos at worst. + ### Noncompliant code example public class Fruit @@ -35,8 +36,9 @@ Having a variable with the same name in two unrelated classes is fine, but do th } ### Exceptions - -This rule ignores same-name fields that are `static` in both the parent and child classes. It also ignores `private` parent class fields, but in all other such cases, the child class field should be renamed. + +This rule ignores same-name fields that are `static` in both the parent and child classes. It also ignores `private` parent +class fields, but in all other such cases, the child class field should be renamed. public class Fruit { diff --git a/docs/description/S2436.md b/docs/description/S2436.md index 4ca57af..3f7bc69 100644 --- a/docs/description/S2436.md +++ b/docs/description/S2436.md @@ -1,9 +1,9 @@ ## Why is this an issue? - + A method or class with too many type parameters has likely aggregated too many responsibilities and should be split. - + ### Noncompliant code example - + With the default parameter value of 2: void foo() {} // Noncompliant; not really readable diff --git a/docs/description/S2437.md b/docs/description/S2437.md index 45dec0e..c63ade7 100644 --- a/docs/description/S2437.md +++ b/docs/description/S2437.md @@ -1,31 +1,39 @@ ## Why is this an issue? - -Certain [bitwise operations](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-and-shift-operators) are not needed and should not be performed because their results are predictable. - + +Certain [bitwise operations](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-and-shift-operators) +are not needed and should not be performed because their results are predictable. + Specifically, using `& -1` with any value always results in the original value. - -That is because the binary representation of `-1` on a [integral numeric type](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/integral-numeric-types) supporting negative numbers, such as `int` or `long`, is based on [two’s + +That is because the binary representation of `-1` on a [integral numeric type](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/integral-numeric-types) supporting +negative numbers, such as `int` or `long`, is based on [two’s complement](https://en.wikipedia.org/wiki/Two%27s_complement) and made of all 1s: `0b111…​111`. - -Performing `&` between a value and `0b111…​111` means applying the `&` operator to each bit of the value and the bit `1`, resulting in a value equal to the provided one, bit by bit. + +Performing `&` between a value and `0b111…​111` means applying the `&` operator to each bit of the value +and the bit `1`, resulting in a value equal to the provided one, bit by bit. anyValue & -1 // Noncompliant anyValue // Compliant -Similarly, `anyValue | 0` always results in `anyValue`, because the binary representation of `0` is always `0b000…​000` and the `|` operator returns its first input when the second is `0`. +Similarly, `anyValue | 0` always results in `anyValue`, because the binary representation of `0` is always +`0b000…​000` and the `|` operator returns its first input when the second is `0`. anyValue | 0 // Noncompliant anyValue // Compliant -The same applies to `anyValue ^ 0`: the `^` operator returns `1` when its two input bits are different (`1` and `0` or `0` and `1`) and returns `0` when its two input bits are the same (both `0` or both `1`). When `^` is applied with `0`, the result would be `1` if the other input is `1`, because the two input bits are different, and `0` if the other input bit is `0`, because the two input are the same. That results in returning `anyValue`. +The same applies to `anyValue ^ 0`: the `^` operator returns `1` when its two input bits are different +(`1` and `0` or `0` and `1`) and returns `0` when its two input bits are the same (both +`0` or both `1`). When `^` is applied with `0`, the result would be `1` if the other input is +`1`, because the two input bits are different, and `0` if the other input bit is `0`, because the two input are the +same. That results in returning `anyValue`. anyValue ^ 0 // Noncompliant anyValue // Compliant ## Resources - + ### Documentation - + - [Bitwise operations (C# reference)](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-and-shift-operators) - [And Operator (Visual Basic)](https://learn.microsoft.com/en-us/dotnet/visual-basic/language-reference/operators/and-operator) diff --git a/docs/description/S2445.md b/docs/description/S2445.md index 156b983..57118fa 100644 --- a/docs/description/S2445.md +++ b/docs/description/S2445.md @@ -1,7 +1,8 @@ ## Why is this an issue? - -[Locking](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/lock) on a class field synchronizes not on the field itself, but on the object assigned to it. Thus, there are some good practices to follow to avoid problems related to [thread](https://learn.microsoft.com/en-us/dotnet/standard/threading/threads-and-threading) synchronization. - + +[Locking](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/lock) on a class field synchronizes not on the +field itself, but on the object assigned to it. Thus, there are some good practices to follow to avoid problems related to [thread](https://learn.microsoft.com/en-us/dotnet/standard/threading/threads-and-threading) synchronization. + - Locking on a non-`readonly` field makes it possible for the field’s value to change while a thread is in the code block, locked on the old value. This allows another thread to lock on the new value and access the same block concurrently. private Color color = new Color("red"); @@ -36,9 +37,9 @@ } ## How to fix it - + ### Code examples - + #### Noncompliant code example private Color color = new Color("red"); diff --git a/docs/description/S2479.md b/docs/description/S2479.md index bb74706..fa5e4d5 100644 --- a/docs/description/S2479.md +++ b/docs/description/S2479.md @@ -1,7 +1,9 @@ ## Why is this an issue? - -Non-encoded [control characters](https://en.wikipedia.org/wiki/Control_character) and whitespace characters are often injected in the source code because of a bad manipulation. They are either invisible or difficult to recognize, which can result in bugs when the string is not what the developer expects. If you actually need to use a control character use their encoded version: - + +Non-encoded [control characters](https://en.wikipedia.org/wiki/Control_character) and whitespace characters are often injected in the +source code because of a bad manipulation. They are either invisible or difficult to recognize, which can result in bugs when the string is not what +the developer expects. If you actually need to use a control character use their encoded version: + - [ASCII](https://en.wikipedia.org/wiki/ASCII), for example `\n` and `\t` - [Unicode](https://en.wikipedia.org/wiki/Unicode), for example `U+000D` and `U+0009` @@ -20,9 +22,9 @@ This rule raises an issue when the following characters are seen in a [string li - The simple space character: Unicode `U+0020`, ASCII 32 ## How to fix it - + ### Code examples - + #### Noncompliant code example string tabInside = "A B"; // Noncompliant: contains a tabulation @@ -36,7 +38,7 @@ This rule raises an issue when the following characters are seen in a [string li Console.WriteLine(zeroWidthSpaceInside); // Prints "foo?bar" ## Resources - + ### Documentation - [Strings and string literals](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/strings/) diff --git a/docs/description/S2486.md b/docs/description/S2486.md index 79bb64f..739bbe8 100644 --- a/docs/description/S2486.md +++ b/docs/description/S2486.md @@ -1,9 +1,9 @@ ## Why is this an issue? - + When exceptions occur, it is usually a bad idea to simply ignore them. Instead, it is better to handle them properly, or at least to log them. - + This rule only reports on empty catch clauses that catch generic `Exception`s. - + ### Noncompliant code example string text = ""; @@ -28,11 +28,11 @@ This rule only reports on empty catch clauses that catch generic `Exception`s. } ### Exceptions - + When a block contains a comment, it is not considered to be empty. - + ## Resources - + - OWASP - [Top 10 2021 Category A9 - Security Logging and Monitoring Failures](https://owasp.org/Top10/A09_2021-Security_Logging_and_Monitoring_Failures/) - OWASP - [Top 10 2017 Category A10 - diff --git a/docs/description/S2551.md b/docs/description/S2551.md index 0a5d124..a5ccc3d 100644 --- a/docs/description/S2551.md +++ b/docs/description/S2551.md @@ -1,15 +1,20 @@ ## Why is this an issue? - -A shared resource refers to a resource or data that can be accessed or modified by multiple [threads](https://en.wikipedia.org/wiki/Thread_%28computing%29) or concurrent parts of a program. It could be any piece of data, object, file, database connection, or system resource that needs to be accessed or manipulated by multiple parts of a program at the same time. - -Shared resources should not be used for [locking](https://en.wikipedia.org/wiki/Lock_%28computer_science%29) because it increases the chance of [deadlocks](https://en.wikipedia.org/wiki/Deadlock). Any other thread could acquire (or attempt to acquire) the same lock while doing some operation, without knowing that the resource is meant to be used for locking purposes. - -For example, a `string` should never be used for locking. When a `string` is [interned](https://en.wikipedia.org/wiki/Interning_%28computer_science%29) by the runtime, it can be shared by multiple threads, breaking the locking mechanism. - -Instead, a dedicated private `object` instance should be used for each shared resource. This minimizes access to the lock instance, avoiding deadlocks and lock contention. - + +A shared resource refers to a resource or data that can be accessed or modified by multiple [threads](https://en.wikipedia.org/wiki/Thread_%28computing%29) or concurrent parts of a program. It could be any piece of data, object, file, +database connection, or system resource that needs to be accessed or manipulated by multiple parts of a program at the same time. + +Shared resources should not be used for [locking](https://en.wikipedia.org/wiki/Lock_%28computer_science%29) because it increases the chance +of [deadlocks](https://en.wikipedia.org/wiki/Deadlock). Any other thread could acquire (or attempt to acquire) the same lock while doing +some operation, without knowing that the resource is meant to be used for locking purposes. + +For example, a `string` should never be used for locking. When a `string` is [interned](https://en.wikipedia.org/wiki/Interning_%28computer_science%29) by the runtime, it can be shared by multiple threads, breaking the +locking mechanism. + +Instead, a dedicated private `object` instance should be used for each shared resource. This minimizes access to the lock instance, +avoiding deadlocks and lock contention. + The following objects are considered as shared resources: - + - a reference to [this](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/this): if the instance is publicly accessibly, the lock might be shared - a [Type](https://learn.microsoft.com/en-us/dotnet/api/system.type) object: if the type class is publicly accessibly, the lock might @@ -18,9 +23,9 @@ The following objects are considered as shared resources: program uses the same string, the lock is shared because of interning ## How to fix it - + ### Code examples - + #### Noncompliant code example void MyLockingMethod() @@ -43,7 +48,7 @@ The following objects are considered as shared resources: } ## Resources - + ### Documentation - [Thread](https://en.wikipedia.org/wiki/Thread_%28computing%29) diff --git a/docs/description/S2583.md b/docs/description/S2583.md index 3ed8acb..eb53b4e 100644 --- a/docs/description/S2583.md +++ b/docs/description/S2583.md @@ -1,7 +1,7 @@ ## Why is this an issue? - + Conditional expressions which are always `true` or `false` can lead to [unreachable code](https://en.wikipedia.org/wiki/Unreachable_code). - + In the case below, the call of `Dispose()` never happens. var a = false; @@ -11,9 +11,9 @@ In the case below, the call of `Dispose()` never happens. } ### Exceptions - + This rule will not raise an issue in either of these cases: - + - When the condition is a single `const bool` const bool debug = false; @@ -25,16 +25,16 @@ This rule will not raise an issue in either of these cases: - When the condition is the literal `true` or `false`. In these cases, it is obvious the code is as intended. - + ## How to fix it - + The conditions should be reviewed to decide whether: - to update the condition or - to remove the condition. ### Code examples - + #### Noncompliant code example public void Sample(bool b) diff --git a/docs/description/S2589.md b/docs/description/S2589.md index a3bda07..330867a 100644 --- a/docs/description/S2589.md +++ b/docs/description/S2589.md @@ -1,24 +1,31 @@ -Gratuitous boolean expressions are conditions that do not change the evaluation of a program. This issue can indicate logical errors and affect the correctness of an application, as well as its maintainability. - +Gratuitous boolean expressions are conditions that do not change the evaluation of a program. This issue can indicate logical errors and affect the +correctness of an application, as well as its maintainability. + ## Why is this an issue? - -Control flow constructs like `if`-statements allow the programmer to direct the flow of a program depending on a boolean expression. However, if the condition is always true or always false, only one of the branches will ever be executed. In that case, the control flow construct and the condition no longer serve a purpose; they become *gratuitous*. - + +Control flow constructs like `if`-statements allow the programmer to direct the flow of a program depending on a boolean expression. +However, if the condition is always true or always false, only one of the branches will ever be executed. In that case, the control flow construct and +the condition no longer serve a purpose; they become *gratuitous*. + ### What is the potential impact? - -The presence of gratuitous conditions can indicate a logical error. For example, the programmer *intended* to have the program branch into different paths but made a mistake when formulating the branching condition. In this case, this issue might result in a bug and thus affect the reliability of the application. For instance, it might lead to the computation of incorrect results. - -Additionally, gratuitous conditions and control flow constructs introduce unnecessary complexity. The source code becomes harder to understand, and thus, the application becomes more difficult to maintain. - -This rule looks for operands of a boolean expression never changing the result of the expression. It also applies to the [null coalescing operator](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/null-coalescing-operator) when one of the operands always evaluates to `null`. + +The presence of gratuitous conditions can indicate a logical error. For example, the programmer *intended* to have the program branch into +different paths but made a mistake when formulating the branching condition. In this case, this issue might result in a bug and thus affect the +reliability of the application. For instance, it might lead to the computation of incorrect results. + +Additionally, gratuitous conditions and control flow constructs introduce unnecessary complexity. The source code becomes harder to understand, and +thus, the application becomes more difficult to maintain. + +This rule looks for operands of a boolean expression never changing the result of the expression. It also applies to the [null coalescing operator](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/null-coalescing-operator) when one of +the operands always evaluates to `null`. string d = null; var v1 = d ?? "value"; // Noncompliant ### Exceptions - + This rule will not raise an issue in either of these cases: - + - When the condition is a single `const bool` const bool debug = false; @@ -30,17 +37,19 @@ This rule will not raise an issue in either of these cases: - When the condition is the literal `true` or `false`. In these cases, it is obvious the code is as intended. - + ## How to fix it - + Gratuitous boolean expressions are suspicious and should be carefully removed from the code. - -First, the boolean expression in question should be closely inspected for logical errors. If a mistake was made, it can be corrected so the condition is no longer gratuitous. - -If it becomes apparent that the condition is actually unnecessary, it can be removed. The associated control flow construct (e.g., the `if`-statement containing the condition) will be adapted or even removed, leaving only the necessary branches. - + +First, the boolean expression in question should be closely inspected for logical errors. If a mistake was made, it can be corrected so the +condition is no longer gratuitous. + +If it becomes apparent that the condition is actually unnecessary, it can be removed. The associated control flow construct (e.g., the +`if`-statement containing the condition) will be adapted or even removed, leaving only the necessary branches. + ### Code examples - + #### Noncompliant code example public void Sample(bool b, bool c) @@ -67,7 +76,7 @@ If it becomes apparent that the condition is actually unnecessary, it can be rem } #### Compliant solution - + The unnecessary operand is updated: public void Sample(bool b, bool c, string s) @@ -114,7 +123,7 @@ The unnecessary operand is removed: } ## Resources - + ### Documentation - CWE - [CWE-571 - Expression is Always True](https://cwe.mitre.org/data/definitions/571) diff --git a/docs/description/S2612.md b/docs/description/S2612.md index dbc80c2..6e16c5f 100644 --- a/docs/description/S2612.md +++ b/docs/description/S2612.md @@ -1,22 +1,23 @@ In Unix, "others" class refers to all users except the owner of the file and the members of the group assigned to this file. - -In Windows, "Everyone" group is similar and includes all members of the Authenticated Users group as well as the built-in Guest account, and several other built-in security accounts. - + +In Windows, "Everyone" group is similar and includes all members of the Authenticated Users group as well as the built-in Guest account, and +several other built-in security accounts. + Granting permissions to these groups can lead to unintended access to files. - + ## Ask Yourself Whether - + - The application is designed to be run on a multi-user environment. - Corresponding files and directories may contain confidential information. There is a risk if you answered yes to any of those questions. - + ## Recommended Secure Coding Practices - + The most restrictive possible permissions should be assigned to files and directories. - + ## Sensitive Code Example - + .Net Framework: var unsafeAccessRule = new FileSystemAccessRule("Everyone", FileSystemRights.FullControl, AccessControlType.Allow); @@ -40,7 +41,7 @@ The most restrictive possible permissions should be assigned to files and direct fileSystemEntry.FileAccessPermissions = FileAccessPermissions.OtherReadWriteExecute; // Sensitive ## Compliant Solution - + .Net Framework var safeAccessRule = new FileSystemAccessRule("Everyone", FileSystemRights.FullControl, AccessControlType.Deny); @@ -70,4 +71,6 @@ The most restrictive possible permissions should be assigned to files and direct - OWASP - [Top 10 2017 Category A5 - Broken Access Control](https://owasp.org/www-project-top-ten/2017/A5_2017-Broken_Access_Control) - [OWASP File Permission](https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/02-Configuration_and_Deployment_Management_Testing/09-Test_File_Permission) - CWE - [CWE-732 - Incorrect Permission Assignment for Critical Resource](https://cwe.mitre.org/data/definitions/732) -- CWE - [CWE-266 - Incorrect Privilege Assignment](https://cwe.mitre.org/data/definitions/266) \ No newline at end of file +- CWE - [CWE-266 - Incorrect Privilege Assignment](https://cwe.mitre.org/data/definitions/266) +- STIG Viewer - [Application Security and + Development: V-222430](https://stigviewer.com/stig/application_security_and_development/2023-06-08/finding/V-222430) - The application must execute without excessive account permissions. \ No newline at end of file diff --git a/docs/description/S2629.md b/docs/description/S2629.md index b8680c8..a0f9105 100644 --- a/docs/description/S2629.md +++ b/docs/description/S2629.md @@ -1,37 +1,39 @@ ## Why is this an issue? - -Logging arguments should not require evaluation in order to avoid unnecessary performance overhead. When passing concatenated strings or string interpolations directly into a logging method, the evaluation of these expressions occurs every time the logging method is called, regardless of the log level. This can lead to inefficient code execution and increased resource consumption. - -Instead, it is recommended to use the overload of the logger that accepts a log format and its arguments as separate parameters. By separating the log format from the arguments, the evaluation of expressions can be deferred until it is necessary, based on the log level. This approach improves performance by reducing unnecessary evaluations and ensures that logging statements are only evaluated when needed. - + +Logging arguments should not require evaluation in order to avoid unnecessary performance overhead. When passing concatenated strings or string +interpolations directly into a logging method, the evaluation of these expressions occurs every time the logging method is called, regardless of the +log level. This can lead to inefficient code execution and increased resource consumption. + +Instead, it is recommended to use the overload of the logger that accepts a log format and its arguments as separate parameters. By separating the +log format from the arguments, the evaluation of expressions can be deferred until it is necessary, based on the log level. This approach improves +performance by reducing unnecessary evaluations and ensures that logging statements are only evaluated when needed. + Furthermore, using a constant log format enhances observability and facilitates searchability in log aggregation and monitoring software. - + The rule covers the following logging frameworks: - + - [Microsoft.Extensions.Logging](https://www.nuget.org/packages/Microsoft.Extensions.Logging) - [Castle.Core](https://www.nuget.org/packages/Castle.Core) - [log4net](https://www.nuget.org/packages/log4net) - [Serilog](https://www.nuget.org/packages/Serilog) - [Nlog](https://www.nuget.org/packages/NLog) +## How to fix it + +Use an overload that takes the log format and the parameters as separate arguments. The log format should be a constant string. + ### Code examples - + #### Noncompliant code example - public void Method(ILogger logger, bool parameter) - { - logger.DebugFormat($"The value of the parameter is: {parameter}."); - } + logger.DebugFormat($"The value of the parameter is: {parameter}."); #### Compliant solution - public void Method(ILogger logger, bool parameter) - { - logger.DebugFormat("The value of the parameter is: {Parameter}.", parameter); - } + logger.DebugFormat("The value of the parameter is: {Parameter}.", parameter); ## Resources - + ### Documentation - Microsoft Learn - [InterpolatedStringHandlerArgumentAttribute](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.interpolatedstringhandlerattribute) \ No newline at end of file diff --git a/docs/description/S2674.md b/docs/description/S2674.md index 2d300f4..488ffbe 100644 --- a/docs/description/S2674.md +++ b/docs/description/S2674.md @@ -1,9 +1,12 @@ ## Why is this an issue? - -You cannot assume that any given stream reading call will fill the `byte[]` passed in to the method with the number of bytes requested. Instead, you must check the value returned by the read method to see how many bytes were read. Fail to do so, and you introduce a bug that is both harmful and difficult to reproduce. - -This rule raises an issue when a `Stream.Read` or a `Stream.ReadAsync` method is called, but the return value is not checked. - + +You cannot assume that any given stream reading call will fill the `byte[]` passed in to the method with the number of bytes requested. +Instead, you must check the value returned by the read method to see how many bytes were read. Fail to do so, and you introduce a bug that is both +harmful and difficult to reproduce. + +This rule raises an issue when a `Stream.Read` or a `Stream.ReadAsync` method is called, but the return value is not +checked. + ### Noncompliant code example public void DoSomething(string fileName) diff --git a/docs/description/S2681.md b/docs/description/S2681.md index e5bf753..e567e91 100644 --- a/docs/description/S2681.md +++ b/docs/description/S2681.md @@ -1,9 +1,11 @@ ## Why is this an issue? - -Having inconsistent indentation and omitting curly braces from a control structure, such as an `if` statement or `for` loop, is misleading and can induce bugs. - -This rule raises an issue when the indentation of the lines after a control structure indicates an intent to include those lines in the block, but the omission of curly braces means the lines will be unconditionally executed once. - + +Having inconsistent indentation and omitting curly braces from a control structure, such as an `if` statement or `for` loop, +is misleading and can induce bugs. + +This rule raises an issue when the indentation of the lines after a control structure indicates an intent to include those lines in the block, but +the omission of curly braces means the lines will be unconditionally executed once. + The following patterns are recognized: if (condition) @@ -21,8 +23,9 @@ The following patterns are recognized: str = array[i]; DoTheThing(str); // Noncompliant: executed only on the last element -Note that this rule considers tab characters to be equivalent to 1 space. When mixing spaces and tabs, a code may look fine in one editor but be confusing in another configured differently. - +Note that this rule considers tab characters to be equivalent to 1 space. When mixing spaces and tabs, a code may look fine in one editor but be +confusing in another configured differently. + ## Resources - + - CWE - [CWE-483 - Incorrect Block Delimitation](https://cwe.mitre.org/data/definitions/483) \ No newline at end of file diff --git a/docs/description/S2688.md b/docs/description/S2688.md index 9d7658d..6a1418a 100644 --- a/docs/description/S2688.md +++ b/docs/description/S2688.md @@ -1,15 +1,18 @@ ## Why is this an issue? - + [double.NaN](https://learn.microsoft.com/en-us/dotnet/api/system.double.nan) and [float.NaN](https://learn.microsoft.com/en-us/dotnet/api/system.single.nan) are not equal to anything, not even themselves. - -When anything is compared with `NaN` using one of the [comparison operators](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/comparison-operators) `>`, `>=`, `<`, `⇐` or the [equality operator](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/equality-operators#equality-operator-) `==`, the result will always be `false`. In contrast, when anything is compared with `NaN` using the [inequality operator](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/equality-operators#inequality-operator-) `!=`, the result will always be `true`. - + +When anything is compared with `NaN` using one of the [comparison operators](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/comparison-operators) `>`, +`>=`, `<`, `⇐` or the [equality operator](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/equality-operators#equality-operator-) +`==`, the result will always be `false`. In contrast, when anything is compared with `NaN` using the [inequality operator](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/equality-operators#inequality-operator-) +`!=`, the result will always be `true`. + Instead, the best way to see whether a variable is equal to `NaN` is to use the [float.IsNaN](https://learn.microsoft.com/en-us/dotnet/api/system.single.isnan) and [double.IsNaN](https://learn.microsoft.com/en-us/dotnet/api/system.double.isnan) methods, which work as expected. - + ## How to fix it - + ### Code examples - + #### Noncompliant code example var a = double.NaN; diff --git a/docs/description/S2692.md b/docs/description/S2692.md index 247eea6..755f0ed 100644 --- a/docs/description/S2692.md +++ b/docs/description/S2692.md @@ -1,17 +1,19 @@ ## Why is this an issue? - -Most checks against an [IndexOf](https://learn.microsoft.com/en-us/dotnet/api/system.string.indexof) value compare it with -1 because **0 is a valid index**. + +Most checks against an [IndexOf](https://learn.microsoft.com/en-us/dotnet/api/system.string.indexof) value compare it with -1 because +**0 is a valid index**. strings.IndexOf(someString) == -1 // Test for "index not found" strings.IndexOf(someString) < 0 // Test for "index not found" strings.IndexOf(someString) >= 0 // Test for "index found" -Any checks which look for values `> 0` ignore the first element, which is likely a bug. If the intent is merely to check the inclusion of a value in a `string`, `List`, or array, consider using the [Contains](https://learn.microsoft.com/en-us/dotnet/api/system.string.contains) method instead. +Any checks which look for values `> 0` ignore the first element, which is likely a bug. If the intent is merely to check the +inclusion of a value in a `string`, `List`, or array, consider using the [Contains](https://learn.microsoft.com/en-us/dotnet/api/system.string.contains) method instead. strings.Contains(someString) // bool result This rule raises an issue when the output value of any of the following methods is tested against `> 0`: - + - [IndexOf](https://learn.microsoft.com/en-us/dotnet/api/system.collections.ilist.indexof), applied to `string`, list or array - [IndexOfAny](https://learn.microsoft.com/en-us/dotnet/api/system.string.indexofany), applied to a `string` @@ -25,9 +27,9 @@ This rule raises an issue when the output value of any of the following methods someString.LastIndexOf(charsArray) > 0 // Noncompliant: index 0 missing ## How to fix it - + ### Code examples - + #### Noncompliant code example string color = "blue"; @@ -89,7 +91,7 @@ This rule raises an issue when the output value of any of the following methods } ## Resources - + ### Documentation - [String.Contains Method](https://learn.microsoft.com/en-us/dotnet/api/system.string.contains) diff --git a/docs/description/S2696.md b/docs/description/S2696.md index 6e06eba..2ed5300 100644 --- a/docs/description/S2696.md +++ b/docs/description/S2696.md @@ -1,8 +1,11 @@ This rule raises an issue each time a `static` field is updated from a non-static method or property. - + ## Why is this an issue? - -Updating a `static` field from a non-`static` method introduces significant challenges and potential bugs. Multiple class instances and threads can access and modify the `static` field concurrently, leading to unintended consequences for other instances or threads (unexpected behavior, [race conditions](https://www.c-sharpcorner.com/UploadFile/1d42da/race-conditions-in-threading-C-Sharp/) and synchronization problems). + +Updating a `static` field from a non-`static` method introduces significant challenges and potential bugs. Multiple class +instances and threads can access and modify the `static` field concurrently, leading to unintended consequences for other instances or +threads (unexpected behavior, [race conditions](https://www.c-sharpcorner.com/UploadFile/1d42da/race-conditions-in-threading-C-Sharp/) and +synchronization problems). class MyClass { @@ -27,13 +30,18 @@ Updating a `static` field from a non-`static` method introduces significant chal } ## Resources - + ### Documentation - + - [Static Classes and Static Class Members](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/static-classes-and-static-class-members) - [Using threads and threading](https://learn.microsoft.com/en-us/dotnet/standard/threading/using-threads-and-threading) ### Articles & blog posts -- [Race Conditions in C#](https://www.c-sharpcorner.com/UploadFile/1d42da/race-conditions-in-threading-C-Sharp/) \ No newline at end of file +- [Race Conditions in C#](https://www.c-sharpcorner.com/UploadFile/1d42da/race-conditions-in-threading-C-Sharp/) + +### Standards + +- STIG Viewer - [Application Security and + Development: V-222567](https://stigviewer.com/stig/application_security_and_development/2023-06-08/finding/V-222567) - The application must not be vulnerable to race conditions. \ No newline at end of file diff --git a/docs/description/S2699.md b/docs/description/S2699.md index ff5ae92..d1f7bb7 100644 --- a/docs/description/S2699.md +++ b/docs/description/S2699.md @@ -1,5 +1,5 @@ ## Why is this an issue? - + The rule targets test methods that lack an assertion and consist solely of an action and, optionally, a setup. [TestMethod] @@ -9,29 +9,36 @@ The rule targets test methods that lack an assertion and consist solely of an ac var actual = stringCalculator.Add("0"); } -Such tests only verify that the system under test does not throw any exceptions without providing any guarantees regarding the code’s behavior under test. Those tests increase the coverage without enforcing anything on the covered code, resulting in a false sense of security. - +Such tests only verify that the system under test does not throw any exceptions without providing any guarantees regarding the code’s behavior +under test. Those tests increase the coverage without enforcing anything on the covered code, resulting in a false sense of security. + The rule identifies a potential issue when no assertions are present in tests utilizing the following frameworks: - + - `MSTest` - `NUnit` - `xUnit` - `FluentAssertions` (4.x and 5.x) - `NFluent` - `NSubstitute` +- `Moq` - `Shoudly` -By enforcing the presence of assertions, this rule aims to enhance the reliability and comprehensiveness of tests by ensuring that they provide meaningful validation of the expected behavior. - +By enforcing the presence of assertions, this rule aims to enhance the reliability and comprehensiveness of tests by ensuring that they provide +meaningful validation of the expected behavior. + ### Exceptions - + Test methods that include a call to a custom assertion method will not raise any issues. - + ### How to fix it - -To address this issue, you should include assertions to validate the expected behavior. Choose an appropriate assertion method provided by your testing framework (such as MSTest, NUnit, xUnit) or select a suitable assertion library like FluentAssertions, NFluent, NSubstitute, or Shouldly. - -In addition to using built-in assertion methods, you also have the option to create custom assertion methods. To do this, declare an attribute named `[AssertionMethodAttribute]` and apply it to the respective method. This allows you to encapsulate specific validation logic within your custom assertion methods without raising the issue. Here’s an example: + +To address this issue, you should include assertions to validate the expected behavior. Choose an appropriate assertion method provided by your +testing framework (such as MSTest, NUnit, xUnit) or select a suitable assertion library like FluentAssertions, NFluent, NSubstitute, Moq, or +Shouldly. + +In addition to using built-in assertion methods, you also have the option to create custom assertion methods. To do this, declare an attribute +named `[AssertionMethodAttribute]` and apply it to the respective method. This allows you to encapsulate specific validation logic within +your custom assertion methods without raising the issue. Here’s an example: using System; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -60,9 +67,9 @@ In addition to using built-in assertion methods, you also have the option to cre public class AssertionMethodAttribute : Attribute { } ## How to fix it in MSTest - + ### Code examples - + #### Noncompliant code example [TestMethod] @@ -83,9 +90,9 @@ In addition to using built-in assertion methods, you also have the option to cre } ## How to fix it in NUnit - + ### Code examples - + #### Noncompliant code example [Test] @@ -106,9 +113,9 @@ In addition to using built-in assertion methods, you also have the option to cre } ## How to fix it in xUnit - + ### Code examples - + #### Noncompliant code example [Fact] @@ -129,7 +136,7 @@ In addition to using built-in assertion methods, you also have the option to cre } ## Resources - + ### Documentation - [Unit testing C# with MSTest](https://learn.microsoft.com/en-us/dotnet/core/testing/unit-testing-with-mstest) diff --git a/docs/description/S2701.md b/docs/description/S2701.md index de68153..91b2204 100644 --- a/docs/description/S2701.md +++ b/docs/description/S2701.md @@ -1,16 +1,19 @@ ## Why is this an issue? - -Using literal boolean values in assertions can lead to less readable and less informative unit tests. When a test fails, it’s important to have a clear understanding of what the test was checking and why it failed. Most of the testing frameworks provide more explicit assertion methods that will provide a more helpful error message if the test fails. - + +Using literal boolean values in assertions can lead to less readable and less informative unit tests. When a test fails, it’s important to have a +clear understanding of what the test was checking and why it failed. Most of the testing frameworks provide more explicit assertion methods that will +provide a more helpful error message if the test fails. + ### Exceptions - -In the context of xUnit, `Assert.True` and `Assert.False` are not flagged by this rule. This is because `Assert.Fail` was only introduced in 2020 with version `2.4.2`. Prior to this, developers used `Assert.True(false, + +In the context of xUnit, `Assert.True` and `Assert.False` are not flagged by this rule. This is because +`Assert.Fail` was only introduced in 2020 with version `2.4.2`. Prior to this, developers used `Assert.True(false, message)` and `Assert.False(true, message)` as workarounds to simulate the functionality of `Assert.Fail()`. - + ## How to fix it in MSTest - + ### Code examples - + #### Noncompliant code example bool someResult; @@ -36,9 +39,9 @@ message)` and `Assert.False(true, message)` as workarounds to simulate the funct // Removed ## How to fix it in NUnit - + ### Code examples - + #### Noncompliant code example bool someResult; @@ -64,9 +67,9 @@ message)` and `Assert.False(true, message)` as workarounds to simulate the funct // Removed ## How to fix it in xUnit - + ### Code examples - + #### Noncompliant code example bool someResult; @@ -86,9 +89,9 @@ message)` and `Assert.False(true, message)` as workarounds to simulate the funct Assert.False(someResult); ## Resources - + ### Documentation - + - [NUnit Documentation](https://docs.nunit.org/) - [xUnit Documentation](https://xunit.net/docs/getting-started/netcore/cmdline) - Microsoft Learn - [MSTest Documentation](https://learn.microsoft.com/en-us/dotnet/core/testing/unit-testing-with-mstest) diff --git a/docs/description/S2737.md b/docs/description/S2737.md index 408ad4b..aad7339 100644 --- a/docs/description/S2737.md +++ b/docs/description/S2737.md @@ -1,6 +1,7 @@ ## Why is this an issue? - -A `catch` clause that only rethrows the caught exception has the same effect as omitting the `catch` altogether and letting it bubble up automatically. + +A `catch` clause that only rethrows the caught exception has the same effect as omitting the `catch` altogether and letting +it bubble up automatically. string s = ""; try @@ -30,8 +31,9 @@ or } ### Exceptions - -This rule will not generate issues for `catch` blocks if they are followed by a `catch` block for a more general exception type that does more than just rethrowing the exception. + +This rule will not generate issues for `catch` blocks if they are followed by a `catch` block for a more general exception +type that does more than just rethrowing the exception. var s = "" try diff --git a/docs/description/S2743.md b/docs/description/S2743.md index cf53c2a..8a267e5 100644 --- a/docs/description/S2743.md +++ b/docs/description/S2743.md @@ -1,9 +1,13 @@ ## Why is this an issue? - -A static field in a generic type is not shared among instances of different closed constructed types, thus `LengthLimitedSingletonCollection.instances` and `LengthLimitedSingletonCollection.instances` will point to different objects, even though `instances` is seemingly shared among all `LengthLimitedSingletonCollection<>` generic classes. - -If you need to have a static field shared among instances with different generic arguments, define a non-generic base class to store your static members, then set your generic type to inherit from the base class. - + +A static field in a generic type is not shared among instances of different closed constructed types, thus +`LengthLimitedSingletonCollection.instances` and `LengthLimitedSingletonCollection.instances` will +point to different objects, even though `instances` is seemingly shared among all `LengthLimitedSingletonCollection<>` +generic classes. + +If you need to have a static field shared among instances with different generic arguments, define a non-generic base class to store your static +members, then set your generic type to inherit from the base class. + ### Noncompliant code example public class LengthLimitedSingletonCollection where T : new() @@ -57,8 +61,9 @@ If you need to have a static field shared among instances with different generic } ### Exceptions - -If the static field or property uses a type parameter, then the developer is assumed to understand that the static member is not shared among the closed constructed types. + +If the static field or property uses a type parameter, then the developer is assumed to understand that the static member is not shared among the +closed constructed types. public class Cache { diff --git a/docs/description/S2755.md b/docs/description/S2755.md index cbf01f2..f392111 100644 --- a/docs/description/S2755.md +++ b/docs/description/S2755.md @@ -1,29 +1,39 @@ This vulnerability allows the usage of external entities in XML. - + ## Why is this an issue? - -External Entity Processing allows for XML parsing with the involvement of external entities. However, when this functionality is enabled without proper precautions, it can lead to a vulnerability known as XML External Entity (XXE) attack. - + +External Entity Processing allows for XML parsing with the involvement of external entities. However, when this functionality is enabled without +proper precautions, it can lead to a vulnerability known as XML External Entity (XXE) attack. + ### What is the potential impact? - + #### Exposing sensitive data - -One significant danger of XXE vulnerabilities is the potential for sensitive data exposure. By crafting malicious XML payloads, attackers can reference external entities that contain sensitive information, such as system files, database credentials, or configuration files. When these entities are processed during XML parsing, the attacker can extract the contents and gain unauthorized access to sensitive data. This poses a severe threat to the confidentiality of critical information. - + +One significant danger of XXE vulnerabilities is the potential for sensitive data exposure. By crafting malicious XML payloads, attackers can +reference external entities that contain sensitive information, such as system files, database credentials, or configuration files. When these +entities are processed during XML parsing, the attacker can extract the contents and gain unauthorized access to sensitive data. This poses a severe +threat to the confidentiality of critical information. + #### Exhausting system resources - -Another consequence of XXE vulnerabilities is the potential for denial-of-service attacks. By exploiting the ability to include external entities, attackers can construct XML payloads that cause resource exhaustion. This can overwhelm the system’s memory, CPU, or other critical resources, leading to system unresponsiveness or crashes. A successful DoS attack can disrupt the availability of services and negatively impact the user experience. - + +Another consequence of XXE vulnerabilities is the potential for denial-of-service attacks. By exploiting the ability to include external entities, +attackers can construct XML payloads that cause resource exhaustion. This can overwhelm the system’s memory, CPU, or other critical resources, leading +to system unresponsiveness or crashes. A successful DoS attack can disrupt the availability of services and negatively impact the user experience. + #### Forging requests - -XXE vulnerabilities can also enable Server-Side Request Forgery (SSRF) attacks. By leveraging the ability to include external entities, an attacker can make the vulnerable application send arbitrary requests to other internal or external systems. This can result in unintended actions, such as retrieving data from internal resources, scanning internal networks, or attacking other systems. SSRF attacks can lead to severe consequences, including unauthorized data access, system compromise, or even further exploitation within the network infrastructure. - + +XXE vulnerabilities can also enable Server-Side Request Forgery (SSRF) attacks. By leveraging the ability to include external entities, an attacker +can make the vulnerable application send arbitrary requests to other internal or external systems. This can result in unintended actions, such as +retrieving data from internal resources, scanning internal networks, or attacking other systems. SSRF attacks can lead to severe consequences, +including unauthorized data access, system compromise, or even further exploitation within the network infrastructure. + ## How to fix it in .NET - + ### Code examples - -The following code contains examples of XML parsers that have external entity processing enabled. As a result, the parsers are vulnerable to XXE attacks if an attacker can control the XML file that is processed. - + +The following code contains examples of XML parsers that have external entity processing enabled. As a result, the parsers are vulnerable to XXE +attacks if an attacker can control the XML file that is processed. + #### Noncompliant code example using System.Xml; @@ -36,8 +46,9 @@ The following code contains examples of XML parsers that have external entity pr } #### Compliant solution - -`XmlDocument` is safe by default since .NET Framework 4.5.2. For older versions, set `XmlResolver` explicitly to `null`. + +`XmlDocument` is safe by default since .NET Framework 4.5.2. For older versions, set `XmlResolver` explicitly to +`null`. using System.Xml; @@ -49,20 +60,26 @@ The following code contains examples of XML parsers that have external entity pr } ### How does this work? - + #### Disable external entities - -The most effective approach to prevent XXE vulnerabilities is to disable external entity processing entirely, unless it is explicitly required for specific use cases. By default, XML parsers should be configured to reject the processing of external entities. This can be achieved by setting the appropriate properties or options in your XML parser library or framework. - -If external entity processing is necessary for certain scenarios, adopt a whitelisting approach to restrict the entities that can be resolved during XML parsing. Create a list of trusted external entities and disallow all others. This approach ensures that only known and safe entities are processed. + +The most effective approach to prevent XXE vulnerabilities is to disable external entity processing entirely, unless it is explicitly required for +specific use cases. By default, XML parsers should be configured to reject the processing of external entities. This can be achieved by setting the +appropriate properties or options in your XML parser library or framework. + +If external entity processing is necessary for certain scenarios, adopt a whitelisting approach to restrict the entities that can be resolved +during XML parsing. Create a list of trusted external entities and disallow all others. This approach ensures that only known and safe entities are +processed. You should rely on features provided by your XML parser to restrict the external entities. - + ## Resources - + ### Standards - + - OWASP - [Top 10 2021 Category A5 - Security Misconfiguration](https://owasp.org/Top10/A05_2021-Security_Misconfiguration/) - OWASP - [Top 10 2017 Category A4 - XML External Entities (XXE)](https://owasp.org/www-project-top-ten/2017/A4_2017-XML_External_Entities_%28XXE%29) - CWE - [CWE-611 - Information Exposure Through XML External Entity Reference](https://cwe.mitre.org/data/definitions/611) -- CWE - [CWE-827 - Improper Control of Document Type Definition](https://cwe.mitre.org/data/definitions/827) \ No newline at end of file +- CWE - [CWE-827 - Improper Control of Document Type Definition](https://cwe.mitre.org/data/definitions/827) +- STIG Viewer - [Application Security and + Development: V-222608](https://stigviewer.com/stig/application_security_and_development/2023-06-08/finding/V-222608) - The application must not be vulnerable to XML-oriented attacks. \ No newline at end of file diff --git a/docs/description/S2757.md b/docs/description/S2757.md index edbf544..2925a57 100644 --- a/docs/description/S2757.md +++ b/docs/description/S2757.md @@ -1,6 +1,7 @@ ## Why is this an issue? - -Using operator pairs (`=+`, `=-`, or `=!`) that look like reversed single operators (`+=`, `-=` or `!=`) is confusing. They compile and run but do not produce the same result as their mirrored counterpart. + +Using operator pairs (`=+`, `=-`, or `=!`) that look like reversed single operators (`+=`, +`-=` or `!=`) is confusing. They compile and run but do not produce the same result as their mirrored counterpart. int target = -5; int num = 3; @@ -8,8 +9,9 @@ Using operator pairs (`=+`, `=-`, or `=!`) that look like reversed single operat target =- num; // Noncompliant: target = -3. Is that the intended behavior? target =+ num; // Noncompliant: target = 3 -This rule raises an issue when `=+`, `=-`, or `=!` are used without any space between the operators and when there is at least one whitespace after. - +This rule raises an issue when `=+`, `=-`, or `=!` are used without any space between the operators and when there +is at least one whitespace after. + Replace the operators with a single one if that is the intention int target = -5; diff --git a/docs/description/S2760.md b/docs/description/S2760.md index 081b29a..574ad71 100644 --- a/docs/description/S2760.md +++ b/docs/description/S2760.md @@ -1,7 +1,8 @@ ## Why is this an issue? - -When the same condition is checked twice in a row, it is either confusing - why have separate checks? - or an error - some other condition should have been checked in the second test. - + +When the same condition is checked twice in a row, it is either confusing - why have separate checks? - or an error - some other condition should +have been checked in the second test. + ### Noncompliant code example if (a == b) @@ -33,5 +34,5 @@ or } ### Exceptions - + Since it is a common pattern to test a variable, reassign it if it fails the test, then re-test it, that pattern is ignored. \ No newline at end of file diff --git a/docs/description/S2761.md b/docs/description/S2761.md index 792a0a7..8a5328a 100644 --- a/docs/description/S2761.md +++ b/docs/description/S2761.md @@ -1,5 +1,5 @@ ## Why is this an issue? - + The repetition of a prefix operator (`!`, or `~`) is usually a typo. The second operator invalidates the first one. int v1 = 0; diff --git a/docs/description/S2857.md b/docs/description/S2857.md index 5ec2c54..2f8a716 100644 --- a/docs/description/S2857.md +++ b/docs/description/S2857.md @@ -1,14 +1,15 @@ ## Why is this an issue? - + When concatenating strings, it is very easy to forget a whitespace. - + In some scenarios this might cause runtime errors, one of which is while creating an SQL query via concatenation: string select = "SELECT p.FirstName, p.LastName, p.PhoneNumber" + "FROM Person as p" + // Noncompliant: concatenation results in "p.PhoneNumberFROM" "WHERE p.Id = @Id"; // Noncompliant: concatenation results in "pWHERE" -This rule raises an issue when the spacing around SQL keywords appears to be missing, making the concatenated string invalid SQL syntax. It would require the user to add the appropriate whitespaces: +This rule raises an issue when the spacing around SQL keywords appears to be missing, making the concatenated string invalid SQL syntax. It would +require the user to add the appropriate whitespaces: string select = "SELECT p.FirstName, p.LastName, p.PhoneNumber" + " FROM Person as p" + diff --git a/docs/description/S2925.md b/docs/description/S2925.md index e669804..f53e50b 100644 --- a/docs/description/S2925.md +++ b/docs/description/S2925.md @@ -1,6 +1,7 @@ ## Why is this an issue? - -Using `Thread.Sleep` in a test might introduce unpredictable and inconsistent results depending on the environment. Furthermore, it will block the [thread](https://en.wikipedia.org/wiki/Thread_%28computing%29), which means the system resources are not being fully used. + +Using `Thread.Sleep` in a test might introduce unpredictable and inconsistent results depending on the environment. Furthermore, it will +block the [thread](https://en.wikipedia.org/wiki/Thread_%28computing%29), which means the system resources are not being fully used. [TestMethod] public void SomeTest() @@ -10,9 +11,10 @@ Using `Thread.Sleep` in a test might introduce unpredictable and inconsistent re } An alternative is a task-based asynchronous approach, using [async and await](https://learn.microsoft.com/en-us/dotnet/csharp/asynchronous-programming/). - -More specifically the [Task.Delay](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.delay) method should be used, because of the following advantages: - + +More specifically the [Task.Delay](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.delay) method should be +used, because of the following advantages: + - It is **asynchronous**: The thread will not be blocked, but instead will be reused by other operations - It is more **precise** in timing the delay than `Thread.Sleep` - It can be **canceled and continued**, which gives more flexibility and control in the timing of your code @@ -24,7 +26,8 @@ More specifically the [Task.Delay](https://learn.microsoft.com/en-us/dotnet/api/ // assertions... } -Another scenario is when some data might need to be mocked using [Moq](https://github.com/moq/moq4), and a delay needs to be introduced: +Another scenario is when some data might need to be mocked using [Moq](https://github.com/moq/moq4), and a delay needs to be +introduced: [TestMethod] public void UserService_Test() @@ -43,7 +46,8 @@ Another scenario is when some data might need to be mocked using [Moq](https://g // assertions... } -An alternative to `Thread.Sleep` while mocking with `Moq` is to use `ReturnsAsync` and pass the amount of time to delay there: +An alternative to `Thread.Sleep` while mocking with `Moq` is to use `ReturnsAsync` and pass the amount of time to +delay there: [TestMethod] public void UserService_Test() @@ -59,7 +63,7 @@ An alternative to `Thread.Sleep` while mocking with `Moq` is to use `ReturnsAsyn } ## Resources - + ### Documentation - [Thread.Sleep method](https://learn.microsoft.com/en-us/dotnet/api/system.threading.thread.sleep) diff --git a/docs/description/S2930.md b/docs/description/S2930.md index 85ca868..06b0d51 100644 --- a/docs/description/S2930.md +++ b/docs/description/S2930.md @@ -1,22 +1,32 @@ ## Why is this an issue? - -When writing [managed code](https://learn.microsoft.com/en-us/dotnet/standard/managed-code), there is no need to worry about memory allocation or deallocation as it is taken care of by the [garbage -collector](https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection). However, certain objects, such as `Bitmap`, utilize unmanaged memory for specific purposes like [pointer arithmetic](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/unsafe-code). These objects may have substantial unmanaged memory footprints while having minimal managed footprints. Unfortunately, the garbage collector only recognizes the small managed footprint and does not promptly reclaim the corresponding unmanaged memory (by invoking the finalizer method of `Bitmap`) for efficiency reasons. - -In addition, it’s essential to manage other system resources besides memory. The operating system has limits on the number of [file descriptors](https://en.wikipedia.org/wiki/File_descriptor) (e.g., `FileStream`) or [sockets](https://en.wikipedia.org/wiki/Network_socket) (e.g., `WebClient`) that can remain open simultaneously. Therefore, it’s crucial to `Dispose` of these resources promptly when they are no longer required, instead of relying on the garbage collector to invoke the finalizers of these objects at an unpredictable time in the future. - -This rule keeps track of `private` fields and local variables of specific types that implement `IDisposable` or `IAsyncDisposable`. It identifies instances of these types that are not properly disposed, closed, aliased, returned, or passed to other methods. This applies to instances that are either directly created using the `new` operator or instantiated through a predefined list of factory methods. - + +When writing [managed code](https://learn.microsoft.com/en-us/dotnet/standard/managed-code), there is no need to worry about memory +allocation or deallocation as it is taken care of by the [garbage +collector](https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection). However, certain objects, such as `Bitmap`, utilize unmanaged memory for specific purposes like [pointer arithmetic](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/unsafe-code). These objects may have substantial +unmanaged memory footprints while having minimal managed footprints. Unfortunately, the garbage collector only recognizes the small managed footprint +and does not promptly reclaim the corresponding unmanaged memory (by invoking the finalizer method of `Bitmap`) for efficiency reasons. + +In addition, it’s essential to manage other system resources besides memory. The operating system has limits on the number of [file descriptors](https://en.wikipedia.org/wiki/File_descriptor) (e.g., `FileStream`) or [sockets](https://en.wikipedia.org/wiki/Network_socket) (e.g., `WebClient`) that can remain open simultaneously. Therefore, it’s +crucial to `Dispose` of these resources promptly when they are no longer required, instead of relying on the garbage collector to invoke +the finalizers of these objects at an unpredictable time in the future. + +This rule keeps track of `private` fields and local variables of specific types that implement `IDisposable` or +`IAsyncDisposable`. It identifies instances of these types that are not properly disposed, closed, aliased, returned, or passed to other +methods. This applies to instances that are either directly created using the `new` operator or instantiated through a predefined list of +factory methods. + Here is the list of predefined factory methods tracked by this rule: - + - `System.IO.File.Create()` - `System.IO.File.Open()` - `System.Drawing.Image.FromFile()` - `System.Drawing.Image.FromStream()` ### Exceptions - -`IDisposable` / `IAsyncDisposable` variables returned from a method or passed to other methods are ignored, as are local `IDisposable` / `IAsyncDisposable` objects that are initialized with other `IDisposable` / `IAsyncDisposable` objects. + +`IDisposable` / `IAsyncDisposable` variables returned from a method or passed to other methods are ignored, as are local +`IDisposable` / `IAsyncDisposable` objects that are initialized with other `IDisposable` / +`IAsyncDisposable` objects. public Stream WriteToFile(string path, string text) { @@ -33,16 +43,18 @@ Here is the list of predefined factory methods tracked by this rule: } ## How to fix it - + It is essential to identify what kind of disposable resource variable is used to know how to fix this issue. - -In the case of a disposable resource store as a member (either as field or property), it should be disposed at the same time as the class. The best way to achieve this is to follow the [dispose + +In the case of a disposable resource store as a member (either as field or property), it should be disposed at the same time as the class. The best +way to achieve this is to follow the [dispose pattern](https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/dispose-pattern). - -When creating the disposable resource for a one-time use (cases not covered by the exceptions), it should be disposed at the end of its creation scope. The easiest to ensure your resource is disposed when reaching the end of a scope is to either use [the using statement or the using declaration](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/using) - + +When creating the disposable resource for a one-time use (cases not covered by the exceptions), it should be disposed at the end of its creation +scope. The easiest to ensure your resource is disposed when reaching the end of a scope is to either use [the using statement or the using declaration](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/using) + ### Code examples - + #### Noncompliant code example public class ResourceHolder @@ -94,7 +106,7 @@ When creating the disposable resource for a one-time use (cases not covered by t } ## Resources - + ### Documentation - [What is "managed code"?](https://learn.microsoft.com/en-us/dotnet/standard/managed-code) diff --git a/docs/description/S2931.md b/docs/description/S2931.md index 0674ee5..4110cda 100644 --- a/docs/description/S2931.md +++ b/docs/description/S2931.md @@ -1,12 +1,15 @@ ## Why is this an issue? - -An `IDisposable` object should be disposed (there are some rare exceptions where not disposing is fine, most notably `Task`). If a class has an `IDisposable` field, there can be two situations: - + +An `IDisposable` object should be disposed (there are some rare exceptions where not disposing is fine, most notably `Task`). +If a class has an `IDisposable` field, there can be two situations: + - The class observes a field that is under the responsibility of another class. - The class owns the field, and is therefore responsible for calling `Dispose` on it. -In the second case, the safest way for the class to ensure `Dispose` is called is to call it in its own `Dispose` function, and therefore to be itself `IDisposable`. A class is considered to own an `IDisposable` field resource if it created the object referenced by the field. - +In the second case, the safest way for the class to ensure `Dispose` is called is to call it in its own `Dispose` function, +and therefore to be itself `IDisposable`. A class is considered to own an `IDisposable` field resource if it created the object +referenced by the field. + ### Noncompliant code example public class ResourceHolder // Noncompliant; doesn't implement IDisposable diff --git a/docs/description/S2933.md b/docs/description/S2933.md index 3c7f2f7..097c669 100644 --- a/docs/description/S2933.md +++ b/docs/description/S2933.md @@ -1,20 +1,22 @@ ## Why is this an issue? - -`readonly` fields can only be assigned in a class constructor. If a class has a field that’s not marked `readonly` but is only set in the constructor, it could cause confusion about the field’s intended use. To avoid confusion, such fields should be marked `readonly` to make their intended use explicit, and to prevent future maintainers from inadvertently changing their use. - + +`readonly` fields can only be assigned in a class constructor. If a class has a field that’s not marked `readonly` but is +only set in the constructor, it could cause confusion about the field’s intended use. To avoid confusion, such fields should be marked +`readonly` to make their intended use explicit, and to prevent future maintainers from inadvertently changing their use. + ### Exceptions - + - Fields declared in classes marked with the `Serializable` attribute. - Fields declared in `partial` classes. - Fields with attributes are ignored. - Fields of type `struct` that are not primitive or pointer types are also ignored because of possible unwanted behavior. ## How to fix it - + Mark the given field with the `readonly` modifier. - + ### Code examples - + #### Noncompliant code example public class Person @@ -40,7 +42,7 @@ Mark the given field with the `readonly` modifier. } ## Resources - + ### Documentation - Microsoft Learn - [readonly](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/readonly) diff --git a/docs/description/S2934.md b/docs/description/S2934.md index 83227d1..caa819d 100644 --- a/docs/description/S2934.md +++ b/docs/description/S2934.md @@ -1,18 +1,21 @@ ## Why is this an issue? - -While the properties of a [`readonly`](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/readonly) [reference type](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/reference-types) field can still be changed after initialization, those of a `readonly` [value type](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/value-types) field, such as a [`struct`](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/struct), cannot. - -If the member could be either a `class` or a `struct` then assignment to its properties could be unreliable, working sometimes but not others. - + +While the properties of a [`readonly`](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/readonly) +[reference type](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/reference-types) field can still be changed +after initialization, those of a `readonly` [value type](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/value-types) field, such as a [`struct`](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/struct), cannot. + +If the member could be either a `class` or a `struct` then assignment to its properties could be unreliable, working +sometimes but not others. + ## How to fix it - + There are two ways to fix this issue: - + - Restrict the type of the field to a `class` - Remove the assignment entirely, if it is not possible to restrict the type of the field ### Code examples - + #### Noncompliant code example interface IPoint @@ -69,7 +72,7 @@ There are two ways to fix this issue: } ## Resources - + ### Documentation - Microsoft Learn - [readonly (C# Reference)](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/readonly) diff --git a/docs/description/S2952.md b/docs/description/S2952.md index 4364df1..aaceb8c 100644 --- a/docs/description/S2952.md +++ b/docs/description/S2952.md @@ -1,9 +1,11 @@ ## Why is this an issue? - -It is possible in an `IDisposable` to call `Dispose` on class members from any method, but the contract of `Dispose` is that it will clean up all unmanaged resources. Move disposing of members to some other method, and you risk resource leaks. - + +It is possible in an `IDisposable` to call `Dispose` on class members from any method, but the contract of +`Dispose` is that it will clean up all unmanaged resources. Move disposing of members to some other method, and you risk resource +leaks. + This rule also applies for disposable ref structs. - + ### Noncompliant code example public class ResourceHolder : IDisposable @@ -50,5 +52,5 @@ This rule also applies for disposable ref structs. } ## Resources - + - CWE - [CWE-459 - Incomplete Cleanup](https://cwe.mitre.org/data/definitions/459) \ No newline at end of file diff --git a/docs/description/S2953.md b/docs/description/S2953.md index 3228010..dd05f7f 100644 --- a/docs/description/S2953.md +++ b/docs/description/S2953.md @@ -1,18 +1,21 @@ ## Why is this an issue? - -[IDisposable](https://learn.microsoft.com/en-us/dotnet/api/system.idisposable) is an interface implemented by all types which need to provide a mechanism for [releasing unmanaged + +[IDisposable](https://learn.microsoft.com/en-us/dotnet/api/system.idisposable) is an interface implemented by all types which need to +provide a mechanism for [releasing unmanaged resources](https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/unmanaged). - + Unlike managed memory, which is taken care of by the [garbage collection](https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/fundamentals), - -The interface declares a [Dispose](https://learn.microsoft.com/en-us/dotnet/api/system.idisposable.dispose) method, which the implementer has to define. - + +The interface declares a [Dispose](https://learn.microsoft.com/en-us/dotnet/api/system.idisposable.dispose) method, which the +implementer has to define. + The method name `Dispose` should be used exclusively to implement `IDisposable.Dispose` to prevent any confusion. - -It may be tempting to create a `Dispose` method for other purposes, but doing so will result in confusion and likely lead to problems in production. - + +It may be tempting to create a `Dispose` method for other purposes, but doing so will result in confusion and likely lead to problems in +production. + ### Exceptions - + Methods named `Dispose` and invoked from the `IDisposable.Dispose` implementation are not reported. public class GarbageDisposal : IDisposable @@ -29,17 +32,20 @@ Methods named `Dispose` and invoked from the `IDisposable.Dispose` implementatio } ## How to fix it - + First, it is important to determine whether instances of the type defining the `Dispose` method should support the [IDisposable](https://learn.microsoft.com/en-us/dotnet/api/system.idisposable) interface or not. - -The decision would be based on whether the instance can have unmanaged resources which have to be dealt with, upon destruction or earlier in the lifetime of the object. - -The [Dispose pattern](https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/dispose-pattern) can help to take the decision. - -If the type should not support the pattern, the `Dispose` method should be renamed to something which is different than `Dispose`, but still relevant and possibly more specific to the context. - + +The decision would be based on whether the instance can have unmanaged resources which have to be dealt with, upon destruction or earlier in the +lifetime of the object. + +The [Dispose pattern](https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/dispose-pattern) can help to take the +decision. + +If the type should not support the pattern, the `Dispose` method should be renamed to something which is different than +`Dispose`, but still relevant and possibly more specific to the context. + ### Code examples - + #### Noncompliant code example public class GarbageDisposal @@ -71,9 +77,9 @@ or } ## Resources - + ### Documentation - + - [Fundamentals of garbage collection](https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/fundamentals) - [Cleaning up unmanaged resources](https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/unmanaged) - [IDisposable Interface](https://learn.microsoft.com/en-us/dotnet/api/system.idisposable) diff --git a/docs/description/S2955.md b/docs/description/S2955.md index c88c285..2a39369 100644 --- a/docs/description/S2955.md +++ b/docs/description/S2955.md @@ -1,17 +1,18 @@ ## Why is this an issue? - -In C#, without constraints on a generic type parameter, both [reference](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/reference-types) and [value](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/value-types) types can be passed. However, comparing this type parameter to `null` can be misleading as value types, like `struct`, can never be null. - + +In C#, without constraints on a generic type parameter, both [reference](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/reference-types) and [value](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/value-types) types can be passed. However, comparing +this type parameter to `null` can be misleading as value types, like `struct`, can never be null. + ## How to fix it - + To avoid unexpected comparisons: - + - if you expect a value type, use [default()](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/default#default-operator) for comparison - if you expect a reference type, add a [constraint](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/constraints-on-type-parameters) to prevent value types from being passed ### Code examples - + #### Noncompliant code example bool IsDefault(T value) @@ -43,7 +44,7 @@ or } ## Resources - + ### Documentation - Microsoft Learn - [Constraints on type parameters](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/constraints-on-type-parameters) diff --git a/docs/description/S2970.md b/docs/description/S2970.md index bc8f232..f84f90e 100644 --- a/docs/description/S2970.md +++ b/docs/description/S2970.md @@ -1,7 +1,8 @@ ## Why is this an issue? - -This rule addresses the issue of incomplete assertions that can occur when using certain test frameworks. Incomplete assertions can lead to tests that do not effectively verify anything. The rule enforces the use of complete assertions in specific cases, namely: - + +This rule addresses the issue of incomplete assertions that can occur when using certain test frameworks. Incomplete assertions can lead to tests +that do not effectively verify anything. The rule enforces the use of complete assertions in specific cases, namely: + - Fluent Assertions: [Should()](https://fluentassertions.com/introduction) is not followed by an assertion invocation. string actual = "Using Fluent Assertions"; @@ -17,13 +18,14 @@ This rule addresses the issue of incomplete assertions that can occur when using command.Received(); // Noncompliant In such cases, what is intended to be a test doesn’t actually verify anything. - + ## How to fix it in Fluent Assertions - -`Fluent Assertions` provides an interface for writing assertions, and it is important to ensure that `Should()` is properly used in conjunction with an assertion method. - + +`Fluent Assertions` provides an interface for writing assertions, and it is important to ensure that `Should()` is properly +used in conjunction with an assertion method. + ### Code examples - + #### Noncompliant code example string actual = "Hello World!"; @@ -35,11 +37,12 @@ In such cases, what is intended to be a test doesn’t actually verify anything. actual.Should().Contain("Hello"); ## How to fix it in NFluent - -`NFluent` offers a syntax for assertions, and it’s important to follow `Check.That()` with an assertion method to complete the assertion. - + +`NFluent` offers a syntax for assertions, and it’s important to follow `Check.That()` with an assertion method to complete +the assertion. + ### Code examples - + #### Noncompliant code example string actual = "Hello World!"; @@ -51,11 +54,12 @@ In such cases, what is intended to be a test doesn’t actually verify anything. Check.That(actual).Contains("Hello"); ## How to fix it in NSubstitute - -`NSubstitute` is a mocking framework, and `Received()` is used to verify that a specific method has been called. However, invoking a method on the mock after calling `Received()` is necessary to ensure the complete assertion. - + +`NSubstitute` is a mocking framework, and `Received()` is used to verify that a specific method has been called. However, +invoking a method on the mock after calling `Received()` is necessary to ensure the complete assertion. + ### Code examples - + #### Noncompliant code example command.Received(); // Noncompliant @@ -65,7 +69,7 @@ In such cases, what is intended to be a test doesn’t actually verify anything. command.Received().Execute(); ## Resources - + ### Documentation - [Fluent assertions: Should()](https://fluentassertions.com/introduction) diff --git a/docs/description/S2971.md b/docs/description/S2971.md index 1a32f51..25b0995 100644 --- a/docs/description/S2971.md +++ b/docs/description/S2971.md @@ -1,11 +1,12 @@ ## Why is this an issue? - -In the interests of readability, code that can be simplified should be simplified. To that end, there are several ways [IEnumerable](https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.ienumerable-1) language integrated queries (LINQ) can be simplified. This not only improves readabilty but can also lead to improved performance. - + +In the interests of readability, code that can be simplified should be simplified. To that end, there are several ways [IEnumerable](https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.ienumerable-1) language integrated queries (LINQ) can be +simplified. This not only improves readabilty but can also lead to improved performance. + ## How to fix it - + Simplify the LINQ expressions: - + - Use [OfType](https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.oftype) instead of [Select](https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.select) with the [as operator](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast#as-operator) to type cast elements and then null-checking in a query expression to choose elements based on type. - Use `OfType` instead of using [Where](https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.where) and the @@ -16,10 +17,11 @@ Simplify the LINQ expressions: predicate parameter of the method for filtering). - Don’t call [ToArray()](https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.toarray) or [ToList()](https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.tolist) in the middle of a query chain. -Using [Entity Framework](https://learn.microsoft.com/en-us/ef/) may require enforcing client evaluations. Such queries should use [AsEnumerable()](https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.asenumerable) instead of `ToArray()` or `ToList()` in the middle of a query chain. - +Using [Entity Framework](https://learn.microsoft.com/en-us/ef/) may require enforcing client evaluations. Such queries should use [AsEnumerable()](https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.asenumerable) instead of `ToArray()` or +`ToList()` in the middle of a query chain. + ### Code examples - + #### Noncompliant code example public void Foo(IEnumerable seq, List list) @@ -51,7 +53,7 @@ Using [Entity Framework](https://learn.microsoft.com/en-us/ef/) may require enfo } ## Resources - + ### Documentation - [Language Integrated Queries in C#](https://learn.microsoft.com/en-us/dotnet/csharp/linq) \ No newline at end of file diff --git a/docs/description/S2995.md b/docs/description/S2995.md index 00fff08..82f648b 100644 --- a/docs/description/S2995.md +++ b/docs/description/S2995.md @@ -1,18 +1,24 @@ ## Why is this an issue? - -In C#, the [`Object.ReferenceEquals`](https://learn.microsoft.com/en-us/dotnet/api/system.object.referenceequals) method is used to compare two [reference type](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/reference-types) variables. If you use this method to compare two [value types](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/value-types), such as `int`, `float`, or `bool` you will not get the expected results because value type variables contain an instance of the type and not a reference to it. - -Due to value type variables containing directly an instance of the type, they can’t have the same reference, and using `Object.ReferenceEquals` to compare them will always return `false` even if the compared variables have the same value. - + +In C#, the [`Object.ReferenceEquals`](https://learn.microsoft.com/en-us/dotnet/api/system.object.referenceequals) method is +used to compare two [reference type](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/reference-types) +variables. If you use this method to compare two [value types](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/value-types), such as `int`, +`float`, or `bool` you will not get the expected results because value type variables contain an instance of the type and not a +reference to it. + +Due to value type variables containing directly an instance of the type, they can’t have the same reference, and using +`Object.ReferenceEquals` to compare them will always return `false` even if the compared variables have the same value. + ## How to fix it - + When comparing value types, prefer using the [`Object.Equals`](https://learn.microsoft.com/en-us/dotnet/api/system.object.equals). - -Note that in the case of [structure types](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/struct), it is recommended to [implement + +Note that in the case of [structure types](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/struct), it +is recommended to [implement value equality](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/how-to-define-value-equality-for-a-type#struct-example). If not, {rule:csharpsquid:S3898} might raise. - + ### Code examples - + #### Noncompliant code example using System; @@ -66,9 +72,9 @@ value equality](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guid } ## Resources - + ### Documentation - + - Microsoft Learn - [`Object.ReferenceEquals(Object, Object)` Method](https://learn.microsoft.com/en-us/dotnet/api/system.object.referenceequals) - Microsoft Learn - [`Object.Equals` Method](https://learn.microsoft.com/en-us/dotnet/api/system.object.equals) diff --git a/docs/description/S2996.md b/docs/description/S2996.md index 6237449..f14cbc9 100644 --- a/docs/description/S2996.md +++ b/docs/description/S2996.md @@ -1,9 +1,11 @@ ## Why is this an issue? - -When an object has a field annotated with `ThreadStatic`, that field is shared within a given thread, but unique across threads. Since a class' static initializer is only invoked for the first thread created, it also means that only the first thread will have the expected initial values. - + +When an object has a field annotated with `ThreadStatic`, that field is shared within a given thread, but unique across threads. Since a +class' static initializer is only invoked for the first thread created, it also means that only the first thread will have the expected initial +values. + Instead, allow such fields to be initialized to their default values or make the initialization lazy. - + ### Noncompliant code example public class Foo diff --git a/docs/description/S2997.md b/docs/description/S2997.md index c30aa0b..762e2d3 100644 --- a/docs/description/S2997.md +++ b/docs/description/S2997.md @@ -1,13 +1,17 @@ ## Why is this an issue? - -When you use a [`using` statement](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/using), the goal is to ensure the correct disposal of an [`IDisposable`](https://learn.microsoft.com/en-us/dotnet/api/system.idisposable) instance when the control leaves the `using` statement block. - -If you return that `IDisposable` instance inside the block, `using` will dispose it before the caller can use it, likely causing exceptions at runtime. You should either remove `using` statement or avoid returning the `IDisposable` in the `using` statement block. - + +When you use a [`using` statement](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/using), the +goal is to ensure the correct disposal of an [`IDisposable`](https://learn.microsoft.com/en-us/dotnet/api/system.idisposable) +instance when the control leaves the `using` statement block. + +If you return that `IDisposable` instance inside the block, `using` will dispose it before the caller can use it, likely +causing exceptions at runtime. You should either remove `using` statement or avoid returning the `IDisposable` in the +`using` statement block. + ## How to fix it - + ### Code examples - + #### Noncompliant code example public FileStream WriteToFile(string path, string text) @@ -31,9 +35,9 @@ If you return that `IDisposable` instance inside the block, `using` will dispose } ## Resources - + ### Documentation - + - Microsoft Learn - [using statement - ensure the correct use of disposable objects](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/using) - Microsoft Learn - [IDisposable](https://learn.microsoft.com/en-us/dotnet/api/system.idisposable) \ No newline at end of file diff --git a/docs/description/S3005.md b/docs/description/S3005.md index 24a4622..e848cd6 100644 --- a/docs/description/S3005.md +++ b/docs/description/S3005.md @@ -1,14 +1,16 @@ ## Why is this an issue? - + When you annotate a field with the [`ThreadStatic` -attribute](https://learn.microsoft.com/en-us/dotnet/api/system.threadstaticattribute), it is an indication that the value of this field is unique for each thread. But if you don’t mark the field as `static`, then the `ThreadStatic` attribute is ignored. - -The `ThreadStatic` attribute should either be removed or replaced with the use of [`ThreadLocal`](https://learn.microsoft.com/en-us/dotnet/api/system.threading.threadlocal-1) class, which gives a similar behavior for non-static fields. - +attribute](https://learn.microsoft.com/en-us/dotnet/api/system.threadstaticattribute), it is an indication that the value of this field is unique for each thread. But if you don’t mark the field as `static`, +then the `ThreadStatic` attribute is ignored. + +The `ThreadStatic` attribute should either be removed or replaced with the use of [`ThreadLocal`](https://learn.microsoft.com/en-us/dotnet/api/system.threading.threadlocal-1) class, which gives a similar +behavior for non-static fields. + ## How to fix it - + ### Code examples - + #### Noncompliant code example public class MyClass @@ -42,8 +44,8 @@ or } ## Resources - + ### Documentation - + - Microsoft Learn - [ThreadStaticAttribute Class](https://learn.microsoft.com/en-us/dotnet/api/system.threadstaticattribute) - Microsoft Learn - [ThreadLocal<T> Class](https://learn.microsoft.com/en-us/dotnet/api/system.threading.threadlocal-1) \ No newline at end of file diff --git a/docs/description/S3010.md b/docs/description/S3010.md index 5d42884..8484cdd 100644 --- a/docs/description/S3010.md +++ b/docs/description/S3010.md @@ -1,9 +1,10 @@ ## Why is this an issue? - -Assigning a value to a `static` field in a constructor could cause unreliable behavior at runtime since it will change the value for all instances of the class. - + +Assigning a value to a `static` field in a constructor could cause unreliable behavior at runtime since it will change the value for all +instances of the class. + Instead remove the field’s `static` modifier, or initialize it statically. - + ### Noncompliant code example public class Person diff --git a/docs/description/S3011.md b/docs/description/S3011.md index 0d520d6..5e0d166 100644 --- a/docs/description/S3011.md +++ b/docs/description/S3011.md @@ -1,8 +1,10 @@ ## Why is this an issue? - -Altering or bypassing the accessibility of classes, methods, or fields through reflection violates the encapsulation principle. This can break the internal contracts of the accessed target and lead to maintainability issues and runtime errors. - -This rule raises an issue when reflection is used to change the visibility of a class, method or field, and when it is used to directly update a field value. + +Altering or bypassing the accessibility of classes, methods, or fields through reflection violates the encapsulation principle. This can break the +internal contracts of the accessed target and lead to maintainability issues and runtime errors. + +This rule raises an issue when reflection is used to change the visibility of a class, method or field, and when it is used to directly update a +field value. using System.Reflection; @@ -13,7 +15,7 @@ This rule raises an issue when reflection is used to change the visibility of a object result = dynMethod.Invoke(dynClass, null); ## Resources - + ### Documentation - + - [Wikipedia definition of Encapsulation](https://en.wikipedia.org/wiki/Encapsulation_%28computer_programming%29) \ No newline at end of file diff --git a/docs/description/S3052.md b/docs/description/S3052.md index 9b54b17..ca6a696 100644 --- a/docs/description/S3052.md +++ b/docs/description/S3052.md @@ -1,7 +1,9 @@ ## Why is this an issue? - -The compiler automatically initializes class fields, auto-properties and events to their default values before setting them with any initialization values, so there is no need to explicitly set a member to its default value. Further, under the logic that cleaner code is better code, it’s considered poor style to do so. - + +The compiler automatically initializes class fields, auto-properties and events to their default values before setting them with any initialization +values, so there is no need to explicitly set a member to its default value. Further, under the logic that cleaner code is better code, it’s +considered poor style to do so. + ### Noncompliant code example class X @@ -23,5 +25,5 @@ The compiler automatically initializes class fields, auto-properties and events } ### Exceptions - + `const` fields are ignored. \ No newline at end of file diff --git a/docs/description/S3059.md b/docs/description/S3059.md index c99288c..a69ea26 100644 --- a/docs/description/S3059.md +++ b/docs/description/S3059.md @@ -1,9 +1,10 @@ ## Why is this an issue? - -There’s no point in having a `public` member in a non-`public` type because objects that can’t access the type will never have the chance to access the member. - + +There’s no point in having a `public` member in a non-`public` type because objects that can’t access the type will never +have the chance to access the member. + This rule raises an issue when a type has methods, fields, or inner types with higher visibility than the type itself has. - + ### Noncompliant code example internal class MyClass @@ -47,7 +48,7 @@ This rule raises an issue when a type has methods, fields, or inner types with h } ### Exceptions - + User defined operators need to be public: public static implicit operator byte(MyClass a) => 1; // Compliant diff --git a/docs/description/S3060.md b/docs/description/S3060.md index d467f59..1dce58a 100644 --- a/docs/description/S3060.md +++ b/docs/description/S3060.md @@ -1,13 +1,16 @@ ## Why is this an issue? - + One of the possible ways of performing [type-testing](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast) is via the [is operator](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/is): `food is Pizza`. - -The `is` operator is often used before a direct [cast](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast#cast-expression) to the target type, as a more flexible and powerful alternative to the [as operator](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast#as-operator), especially when used to perform [pattern + +The `is` operator is often used before a direct [cast](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast#cast-expression) to the target type, +as a more flexible and powerful alternative to the [as operator](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast#as-operator), especially when +used to perform [pattern matching](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast#type-testing-with-pattern-matching). if (food is Pizza pizza) -There’s no valid reason to test `this` with `is`. The only plausible explanation for such a test is that you’re executing code in a parent class conditionally based on the kind of child class `this` is. +There’s no valid reason to test `this` with `is`. The only plausible explanation for such a test is that you’re executing +code in a parent class conditionally based on the kind of child class `this` is. public class Food { @@ -21,11 +24,12 @@ There’s no valid reason to test `this` with `is`. The only plausible explanati } However, code that’s specific to a child class should be *in* that child class, not in the parent. - + ## How to fix it - -One way is to take advantage of the [object-orientation](https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/tutorials/oop) of C# and use [polymorphism](https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/object-oriented/polymorphism). - + +One way is to take advantage of the [object-orientation](https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/tutorials/oop) of +C# and use [polymorphism](https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/object-oriented/polymorphism). + - Make the method [virtual](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/virtual), if it is not already. That will allow derived classes to perform [method overriding](https://en.wikipedia.org/wiki/Method_overriding). - Move the code to the right level of the type hierarchy. @@ -33,9 +37,9 @@ One way is to take advantage of the [object-orientation](https://learn.microsoft that has been overridden. For example, when simple method polymorphism is not enough because it is necessary to reuse multiple sections of the parent method, the [Template method pattern](https://en.wikipedia.org/wiki/Template_method_pattern) might help. - + ### Code examples - + #### Noncompliant code example public class Food @@ -70,7 +74,7 @@ For example, when simple method polymorphism is not enough because it is necessa } ## Resources - + ### Documentation - [Type-testing operators and cast diff --git a/docs/description/S3063.md b/docs/description/S3063.md index ebe298b..8d5a8d7 100644 --- a/docs/description/S3063.md +++ b/docs/description/S3063.md @@ -1,7 +1,8 @@ ## Why is this an issue? - -`StringBuilder` instances that never build a `string` clutter the code and worse are a drag on performance. Either they should be removed, or the missing `ToString()` call should be added. - + +`StringBuilder` instances that never build a `string` clutter the code and worse are a drag on performance. Either they +should be removed, or the missing `ToString()` call should be added. + ### Noncompliant code example public void DoSomething(List strings) { @@ -34,9 +35,9 @@ or } ### Exceptions - + No issue is reported when `StringBuilder` is: - + - Accessed through `sb.CopyTo()`, `sb.GetChunks()`, `sb.Length`, or `sb[index]`. - Passed as a method argument, on the grounds that it will likely be accessed through a `ToString()` invocation there. - Passed in as a parameter to the current method, on the grounds that the callee will materialize the string. diff --git a/docs/description/S3168.md b/docs/description/S3168.md index 1cfc469..e0e38dd 100644 --- a/docs/description/S3168.md +++ b/docs/description/S3168.md @@ -1,11 +1,12 @@ ## Why is this an issue? - -An [`async`](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/async) method with a `void` return type does not follow the [task asynchronous programming + +An [`async`](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/async) method with a +`void` return type does not follow the [task asynchronous programming (TAP)](https://learn.microsoft.com/en-us/dotnet/csharp/asynchronous-programming/task-asynchronous-programming-model) model since the return type should be [`Task`](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task) or [`Task`](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task-1) - + Doing so prevents control over the [asynchronous execution](https://learn.microsoft.com/en-us/dotnet/csharp/asynchronous-programming/async-scenarios), such as: - + - waiting for the execution to complete - catching any exception that might occur during execution - testing execution behavior @@ -26,11 +27,11 @@ execution](https://learn.microsoft.com/en-us/dotnet/csharp/asynchronous-programm } ## How to fix it - + Update the return type of the method from `void` to `Task`. - + ### Code examples - + #### Noncompliant code example private async void ThrowExceptionAsync() // Noncompliant: async method return type is 'void' @@ -72,7 +73,7 @@ Update the return type of the method from `void` to `Task`. } ## Resources - + ### Documentation - Microsoft Learn - [`async` (C# diff --git a/docs/description/S3169.md b/docs/description/S3169.md index 21da06a..f70a5f7 100644 --- a/docs/description/S3169.md +++ b/docs/description/S3169.md @@ -1,9 +1,11 @@ ## Why is this an issue? - -There’s no point in chaining multiple `OrderBy` calls in a LINQ; only the last one will be reflected in the result because each subsequent call completely reorders the list. Thus, calling `OrderBy` multiple times is a performance issue as well, because all of the sorting will be executed, but only the result of the last sort will be kept. - + +There’s no point in chaining multiple `OrderBy` calls in a LINQ; only the last one will be reflected in the result because each +subsequent call completely reorders the list. Thus, calling `OrderBy` multiple times is a performance issue as well, because all of the +sorting will be executed, but only the result of the last sort will be kept. + Instead, use `ThenBy` for each call after the first. - + ### Noncompliant code example var x = personList diff --git a/docs/description/S3172.md b/docs/description/S3172.md index bce7648..d81747c 100644 --- a/docs/description/S3172.md +++ b/docs/description/S3172.md @@ -1,9 +1,9 @@ ## Why is this an issue? - + In C#, delegates can be added together to chain their execution, and subtracted to remove their execution from the chain. - + Subtracting a chain of delegates from another one might yield unexpected results as shown hereunder - and is likely to be a bug. - + ### Noncompliant code example MyDelegate first, second, third, fourth; diff --git a/docs/description/S3215.md b/docs/description/S3215.md index c0f7f41..a61bcaf 100644 --- a/docs/description/S3215.md +++ b/docs/description/S3215.md @@ -1,7 +1,9 @@ ## Why is this an issue? - -Needing to cast from an `interface` to a concrete type indicates that something is wrong with the abstractions in use, likely that something is missing from the `interface`. Instead of casting to a discrete type, the missing functionality should be added to the `interface`. Otherwise there is a risk of runtime exceptions. - + +Needing to cast from an `interface` to a concrete type indicates that something is wrong with the abstractions in use, likely that +something is missing from the `interface`. Instead of casting to a discrete type, the missing functionality should be added to the +`interface`. Otherwise there is a risk of runtime exceptions. + ### Noncompliant code example public interface IMyInterface @@ -35,7 +37,7 @@ Needing to cast from an `interface` to a concrete type indicates that something } ### Exceptions - + Casting to `object` doesn’t raise an issue, because it can never fail. static void EntryPoint(IMyInterface interfaceRef) diff --git a/docs/description/S3216.md b/docs/description/S3216.md index 8939f2d..d957c95 100644 --- a/docs/description/S3216.md +++ b/docs/description/S3216.md @@ -1,11 +1,14 @@ ## Why is this an issue? - -After an `await`ed `Task` has executed, you can continue execution in the original, calling thread or any arbitrary thread. Unless the rest of the code needs the context from which the `Task` was spawned, `Task.ConfigureAwait(false)` should be used to keep execution in the `Task` thread to avoid the need for context switching and the possibility of deadlocks. - -This rule raises an issue when code in a class library targeting .Net Framework `await`s a `Task` and continues execution in the original calling thread. - + +After an `await`ed `Task` has executed, you can continue execution in the original, calling thread or any arbitrary thread. +Unless the rest of the code needs the context from which the `Task` was spawned, `Task.ConfigureAwait(false)` should be used to +keep execution in the `Task` thread to avoid the need for context switching and the possibility of deadlocks. + +This rule raises an issue when code in a class library targeting .Net Framework `await`s a `Task` and continues execution in +the original calling thread. + The rule does not raise for .Net Core libraries as there is no `SynchronizationContext` in .Net Core. - + ### Noncompliant code example var response = await httpClient.GetAsync(url); // Noncompliant diff --git a/docs/description/S3217.md b/docs/description/S3217.md index afd61d1..29b7d94 100644 --- a/docs/description/S3217.md +++ b/docs/description/S3217.md @@ -1,11 +1,15 @@ ## Why is this an issue? - -The [foreach](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/iteration-statements#the-foreach-statement) statement was introduced in the C# language prior to generics to make it easier to work with the non-generic collections available at that time such as [ArrayList](https://learn.microsoft.com/en-us/dotnet/api/system.collections.arraylist). The `foreach` statements allow you to downcast elements of a collection of [Objects](https://learn.microsoft.com/en-us/dotnet/api/system.object) to any other type. - + +The [foreach](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/iteration-statements#the-foreach-statement) +statement was introduced in the C# language prior to generics to make it easier to work with the non-generic collections available at that time such +as [ArrayList](https://learn.microsoft.com/en-us/dotnet/api/system.collections.arraylist). The `foreach` statements allow you to +downcast elements of a collection of [Objects](https://learn.microsoft.com/en-us/dotnet/api/system.object) to any other type. + The problem is that to achieve the cast, the `foreach` statements silently perform [explicit type conversion](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/types/casting-and-type-conversions#explicit-conversions), which at runtime can result in an [InvalidCastException](https://learn.microsoft.com/en-us/dotnet/api/system.invalidcastexception). - -C# code iterating on generic collections or arrays should not rely on `foreach` statement’s silent `explicit` conversions. + +C# code iterating on generic collections or arrays should not rely on `foreach` statement’s silent `explicit` +conversions. public class Fruit { } public class Orange : Fruit { } @@ -48,13 +52,14 @@ C# code iterating on generic collections or arrays should not rely on `foreach` } ### Exceptions - -The rule ignores iterations on collections of `objects`. This includes legacy code that uses `ArrayList`. Furthermore, the rule does not report on cases when user-defined conversions are being called. - + +The rule ignores iterations on collections of `objects`. This includes legacy code that uses `ArrayList`. Furthermore, the +rule does not report on cases when user-defined conversions are being called. + ## Resources - + ### Documentation - + - [Foreach statement](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/iteration-statements#the-foreach-statement) - [ArrayList](https://learn.microsoft.com/en-us/dotnet/api/system.collections.arraylist) diff --git a/docs/description/S3218.md b/docs/description/S3218.md index 96a6ea9..657c98a 100644 --- a/docs/description/S3218.md +++ b/docs/description/S3218.md @@ -1,6 +1,8 @@ ## Why is this an issue? - -Naming the members of an inner class the same as the static members of its enclosing class is possible but generally considered a bad practice. That’s because maintainers may be confused about which members are being used in a given context. Instead the inner class member should be given distinct and descriptive name, and all references to it should be updated accordingly. + +Naming the members of an inner class the same as the static members of its enclosing class is possible but generally considered a bad practice. +That’s because maintainers may be confused about which members are being used in a given context. Instead the inner class member should be given +distinct and descriptive name, and all references to it should be updated accordingly. class Outer { @@ -52,8 +54,8 @@ Or if you want to reference the `Inner` A field: } ## Resources - + ### Documentation - + - [Common Coding Conventions](https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/coding-style/coding-conventions) - [Nested Types](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/nested-types) \ No newline at end of file diff --git a/docs/description/S3220.md b/docs/description/S3220.md index 00b9df5..f1abb80 100644 --- a/docs/description/S3220.md +++ b/docs/description/S3220.md @@ -1,9 +1,11 @@ ## Why is this an issue? - -The rules for method resolution are complex and perhaps not properly understood by all coders. The `params` keyword can make method declarations overlap in non-obvious ways, so that slight changes in the argument types of an invocation can resolve to different methods. - -This rule raises an issue when an invocation resolves to a method declaration with `params`, but could also resolve to another non-`params` method too. - + +The rules for method resolution are complex and perhaps not properly understood by all coders. The `params` keyword can make method +declarations overlap in non-obvious ways, so that slight changes in the argument types of an invocation can resolve to different methods. + +This rule raises an issue when an invocation resolves to a method declaration with `params`, but could also resolve to another +non-`params` method too. + ### Noncompliant code example public class MyClass diff --git a/docs/description/S3234.md b/docs/description/S3234.md index d9c12f3..368a7cc 100644 --- a/docs/description/S3234.md +++ b/docs/description/S3234.md @@ -1,11 +1,14 @@ ## Why is this an issue? - -`GC.SuppressFinalize` asks the Common Language Runtime not to call the finalizer of an object. This is useful when implementing the dispose pattern where object finalization is already handled in `IDisposable.Dispose`. However, it has no effect if there is no finalizer defined in the object’s type, so using it in such cases is just confusing. - + +`GC.SuppressFinalize` asks the Common Language Runtime not to call the finalizer of an object. This is useful when implementing the +dispose pattern where object finalization is already handled in `IDisposable.Dispose`. However, it has no effect if there is no finalizer +defined in the object’s type, so using it in such cases is just confusing. + This rule raises an issue when `GC.SuppressFinalize` is called for objects of `sealed` types without a finalizer. - -**Note:** {rule:csharpsquid:S3971} is a stricter version of this rule. Typically it makes sense to activate only one of these 2 rules. - + +**Note:** {rule:csharpsquid:S3971} is a stricter version of this rule. Typically it makes sense to activate only one of these 2 +rules. + ### Noncompliant code example sealed class MyClass diff --git a/docs/description/S3235.md b/docs/description/S3235.md index 362227a..bb52210 100644 --- a/docs/description/S3235.md +++ b/docs/description/S3235.md @@ -1,7 +1,7 @@ ## Why is this an issue? - + Redundant parentheses are simply wasted keystrokes, and should be removed. - + ### Noncompliant code example [MyAttribute()] //Noncompliant diff --git a/docs/description/S3236.md b/docs/description/S3236.md index c133ce1..3563de4 100644 --- a/docs/description/S3236.md +++ b/docs/description/S3236.md @@ -1,7 +1,10 @@ ## Why is this an issue? - -Caller information attributes: `CallerFilePathAttribute`, `CallerLineNumberAttribute`, and `CallerArgumentExpressionAttribute` provide a way to get information about the caller of a method through optional parameters. But the arguments for these optional parameters are only generated if they are not explicitly defined in the call. Thus, specifying the argument values defeats the purpose of the attributes. - + +Caller information attributes: `CallerFilePathAttribute`, `CallerLineNumberAttribute`, and +`CallerArgumentExpressionAttribute` provide a way to get information about the caller of a method through optional parameters. But the +arguments for these optional parameters are only generated if they are not explicitly defined in the call. Thus, specifying the argument values +defeats the purpose of the attributes. + ### Noncompliant code example void TraceMessage(string message, @@ -31,5 +34,5 @@ Caller information attributes: `CallerFilePathAttribute`, `CallerLineNumberAttri } ### Exceptions - + `CallerMemberName` is not checked to avoid False-Positives with WPF/UWP applications. \ No newline at end of file diff --git a/docs/description/S3237.md b/docs/description/S3237.md index 2ba8c54..599c949 100644 --- a/docs/description/S3237.md +++ b/docs/description/S3237.md @@ -1,11 +1,14 @@ ## Why is this an issue? - -When you need to get external input for `set` and `init` methods defined for properties and indexers or for `remove` and `add` methods for events, you should always get this input throught the `value` contextual keyword. - -The contextual keyword `value` is similar to an input parameter of a method; it references the value that the client code is attempting to assign to the property, indexer or event. - -The keyword `value` holds the value the accessor was called with. Not using it means that the accessor ignores the caller’s intent which could cause unexpected results at runtime. - + +When you need to get external input for `set` and `init` methods defined for properties and indexers or for +`remove` and `add` methods for events, you should always get this input throught the `value` contextual keyword. + +The contextual keyword `value` is similar to an input parameter of a method; it references the value that the client code is attempting +to assign to the property, indexer or event. + +The keyword `value` holds the value the accessor was called with. Not using it means that the accessor ignores the caller’s intent which +could cause unexpected results at runtime. + ### Noncompliant code example private int count; @@ -25,13 +28,14 @@ The keyword `value` holds the value the accessor was called with. Not using it m } ### Exceptions - -This rule doesn’t raise an issue when the setter is empty and part of the implementation of an `interface`. The assumption is that this part of the interface is not meaningful to that particular implementation. A good example of that would be a "sink" logger that discards any logs. - + +This rule doesn’t raise an issue when the setter is empty and part of the implementation of an `interface`. The assumption is that this +part of the interface is not meaningful to that particular implementation. A good example of that would be a "sink" logger that discards any logs. + ## Resources - + ### Documentation - + - [Properties](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/properties) - [Value keyword](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/value) - [Add keyword](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/add) diff --git a/docs/description/S3240.md b/docs/description/S3240.md index 1b2446d..bdf3b55 100644 --- a/docs/description/S3240.md +++ b/docs/description/S3240.md @@ -1,7 +1,7 @@ ## Why is this an issue? - + In the interests of keeping code clean, the simplest possible conditional syntax should be used. That means - + - using the `??=` operator for a self-assign-if-not-null operation, - using the `??` operator for an assign-if-not-null operation, and - using the ternary operator `?:` for assignment to a single variable. diff --git a/docs/description/S3241.md b/docs/description/S3241.md index 2b69aea..f900450 100644 --- a/docs/description/S3241.md +++ b/docs/description/S3241.md @@ -1,7 +1,8 @@ ## Why is this an issue? - -Private methods are intended for use only within their scope. If these methods return values that are not utilized by any calling functions, it indicates that the return operation is unnecessary. Removing such returns can enhance both efficiency and code clarity. - + +Private methods are intended for use only within their scope. If these methods return values that are not utilized by any calling functions, it +indicates that the return operation is unnecessary. Removing such returns can enhance both efficiency and code clarity. + ### Noncompliant code example class SomeClass diff --git a/docs/description/S3242.md b/docs/description/S3242.md index f1467a3..555c9f2 100644 --- a/docs/description/S3242.md +++ b/docs/description/S3242.md @@ -1,9 +1,10 @@ ## Why is this an issue? - -When a derived type is used as a parameter instead of the base type, it limits the uses of the method. If the additional functionality that is provided in the derived type is not required then that limitation isn’t required, and should be removed. - + +When a derived type is used as a parameter instead of the base type, it limits the uses of the method. If the additional functionality that is +provided in the derived type is not required then that limitation isn’t required, and should be removed. + This rule raises an issue when a method declaration includes a parameter that is a derived type and accesses only members of the base type. - + ### Noncompliant code example using System; diff --git a/docs/description/S3244.md b/docs/description/S3244.md index 0e2e796..46dd880 100644 --- a/docs/description/S3244.md +++ b/docs/description/S3244.md @@ -1,27 +1,31 @@ ## Why is this an issue? - + When working with [anonymous functions](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/lambda-expressions), it is important to keep in mind that each time you create one, it is a completely new instance. - -In this example, even though the same lambda expression is used, the expressions are stored separately in the memory and are therefore not equal or the same. + +In this example, even though the same lambda expression is used, the expressions are stored separately in the memory and are therefore not equal or +the same. Func lambda1 = x => x + 1; Func lambda2 = x => x + 1; var result = lambda1 == lambda2; // result is false here -This is even more true when working with [events](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/events/) since they are [multicast +This is even more true when working with [events](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/events/) since they +are [multicast delegates](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/delegates/how-to-combine-delegates-multicast-delegates) that offer ways of [subscribing and -unsubscribing](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/events/how-to-subscribe-to-and-unsubscribe-from-events) to them. If an anonymous function is used to subscribe to an event, it is impossible to unsubscribe from it. This happens because to remove the entry from the subscription list, a reference to the original method is needed, but if the anonymous function has not been stored before subscribing, there is no way to find a reference to it. - +unsubscribing](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/events/how-to-subscribe-to-and-unsubscribe-from-events) to them. If an anonymous function is used to subscribe to an event, it is impossible to unsubscribe from it. This happens because to +remove the entry from the subscription list, a reference to the original method is needed, but if the anonymous function has not been stored before +subscribing, there is no way to find a reference to it. + Instead, store the callback to a variable or a named method and use the variable or method to subscribe and unsubscribe. - + ## How to fix it - + Store the callback to a variable or a named method and use the variable or method to subscribe and unsubscribe. - + ### Code examples - + #### Noncompliant code example event EventHandler myEvent; @@ -46,9 +50,9 @@ Store the callback to a variable or a named method and use the variable or metho } ## Resources - + ### Documentation - + - Microsoft Learn - [Events (C# Programming Guide)](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/events/) - Microsoft Learn - [Lambda expressions and anonymous functions](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/lambda-expressions) diff --git a/docs/description/S3246.md b/docs/description/S3246.md index 4df4f4e..743dd65 100644 --- a/docs/description/S3246.md +++ b/docs/description/S3246.md @@ -1,11 +1,18 @@ ## Why is this an issue? - -In the interests of making code as usable as possible, interfaces and delegates with generic parameters should use the `out` and `in` modifiers when possible to make the interfaces and delegates covariant and contravariant, respectively. - -The `out` keyword can be used when the type parameter is used only as a return type in the interface or delegate. Doing so makes the parameter covariant, and allows interface and delegate instances created with a sub-type to be used as instances created with a base type. The most notable example of this is `IEnumerable`, which allows the assignment of an `IEnumerable` instance to an `IEnumerable` variable, for instance. - -The `in` keyword can be used when the type parameter is used only as a method parameter in the interface or a parameter in the delegate. Doing so makes the parameter contravariant, and allows interface and delegate instances created with a base type to be used as instances created with a sub-type. I.e. this is the inversion of covariance. The most notable example of this is the `Action` delegate, which allows the assignment of an `Action` instance to a `Action` variable, for instance. - + +In the interests of making code as usable as possible, interfaces and delegates with generic parameters should use the `out` and +`in` modifiers when possible to make the interfaces and delegates covariant and contravariant, respectively. + +The `out` keyword can be used when the type parameter is used only as a return type in the interface or delegate. Doing so makes the +parameter covariant, and allows interface and delegate instances created with a sub-type to be used as instances created with a base type. The most +notable example of this is `IEnumerable`, which allows the assignment of an `IEnumerable` instance to +an `IEnumerable` variable, for instance. + +The `in` keyword can be used when the type parameter is used only as a method parameter in the interface or a parameter in the delegate. +Doing so makes the parameter contravariant, and allows interface and delegate instances created with a base type to be used as instances created with +a sub-type. I.e. this is the inversion of covariance. The most notable example of this is the `Action` delegate, which allows +the assignment of an `Action` instance to a `Action` variable, for instance. + ### Noncompliant code example interface IConsumer // Noncompliant diff --git a/docs/description/S3247.md b/docs/description/S3247.md index 94abae4..d8774de 100644 --- a/docs/description/S3247.md +++ b/docs/description/S3247.md @@ -1,8 +1,24 @@ ## Why is this an issue? - -Because the `is` operator performs a cast if the object is not null, using `is` to check type and then casting the same argument to that type, necessarily performs two casts. The same result can be achieved more efficiently with a single cast using `as`, followed by a null-check. - -### Noncompliant code example + +In C#, the [`is` +type testing operator](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast#is-operator) can be used to check if the run-time type of an object is compatible with a given type. If the object is not null, then the +`is` operator performs a cast, and so performing another cast following the check result is redundant. + +This can impact: + +- Performance: Performing the type check and cast separately can lead to minor performance issues. While this might not be noticeable in small + applications, it can add up in larger, more complex systems. +- Readability: The code is less readable and less clean because it requires two lines (and two operations) to achieve something that could be + done in one. + +## How to fix it + +Use [pattern macthing](https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/functional/pattern-matching) to perform the check +and retrieve the cast result. + +### Code examples + +#### Noncompliant code example if (x is Fruit) // Noncompliant { @@ -10,16 +26,19 @@ Because the `is` operator performs a cast if the object is not null, using `is` // ... } -### Compliant solution +#### Compliant solution - // C# 6 - var f = x as Fruit; - if (f != null) - { - // ... - } - // C# 7 if (x is Fruit fruit) { // ... - } \ No newline at end of file + } + +## Resources + +### Documentation + +- Microsoft Learn - [Type-testing + operators and cast expressions - `is`, `as`, `typeof` and casts](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast) +- Microsoft Learn - [is operator (C# reference)](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/is) +- Microsoft Learn - [Pattern matching + overview](https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/functional/pattern-matching) \ No newline at end of file diff --git a/docs/description/S3249.md b/docs/description/S3249.md index bc26b1d..aa626e5 100644 --- a/docs/description/S3249.md +++ b/docs/description/S3249.md @@ -1,9 +1,11 @@ ## Why is this an issue? - -Making a `base` call when overriding a method is generally a good idea, but not in the case of [`GetHashCode`](https://learn.microsoft.com/en-us/dotnet/api/system.object.gethashcode) and [`Equals`](https://learn.microsoft.com/en-us/dotnet/api/system.object.equals) for classes that directly extend `Object`. These methods are based on the object’s reference, meaning that no two objects that use those `base` methods can be equal or have the same hash. - + +Making a `base` call when overriding a method is generally a good idea, but not in the case of [`GetHashCode`](https://learn.microsoft.com/en-us/dotnet/api/system.object.gethashcode) and [`Equals`](https://learn.microsoft.com/en-us/dotnet/api/system.object.equals) for classes that directly extend `Object`. +These methods are based on the object’s reference, meaning that no two objects that use those `base` methods can be equal or have the same +hash. + ### Exceptions - + This rule doesn’t report on guard conditions checking for reference equality. For example: public override bool Equals(object obj) @@ -16,9 +18,9 @@ This rule doesn’t report on guard conditions checking for reference equality. } ## How to fix it - + ### Code examples - + #### Noncompliant code example var m1 = new MyClass(2); @@ -64,8 +66,8 @@ This rule doesn’t report on guard conditions checking for reference equality. } ## Resources - + ### Documentation - + - Microsoft Learn - [Object.GetHashCode Method](https://learn.microsoft.com/en-us/dotnet/api/system.object.gethashcode?view=net-7.0) - Microsoft Learn - [Object.Equals Method](https://learn.microsoft.com/en-us/dotnet/api/system.object.equals) \ No newline at end of file diff --git a/docs/description/S3251.md b/docs/description/S3251.md index 85472d2..46d7b97 100644 --- a/docs/description/S3251.md +++ b/docs/description/S3251.md @@ -1,9 +1,12 @@ ## Why is this an issue? - -`partial` methods allow an increased degree of flexibility in programming a system. Hooks can be added to generated code by invoking methods that define their signature, but might not have an implementation yet. But if the implementation is still missing when the code makes it to production, the compiler silently removes the call. In the best case scenario, such calls simply represent cruft, but in they worst case they are critical, missing functionality, the loss of which will lead to unexpected results at runtime. - + +`partial` methods allow an increased degree of flexibility in programming a system. Hooks can be added to generated code by invoking +methods that define their signature, but might not have an implementation yet. But if the implementation is still missing when the code makes it to +production, the compiler silently removes the call. In the best case scenario, such calls simply represent cruft, but in they worst case they are +critical, missing functionality, the loss of which will lead to unexpected results at runtime. + This rule raises an issue for partial methods for which no implementation can be found in the assembly. - + ### Noncompliant code example partial class C diff --git a/docs/description/S3253.md b/docs/description/S3253.md index b1b97f9..dc8db11 100644 --- a/docs/description/S3253.md +++ b/docs/description/S3253.md @@ -1,7 +1,9 @@ ## Why is this an issue? - -Since the compiler will automatically invoke the base type’s no-argument constructor, there’s no need to specify its invocation explicitly. Also, when only a single `public` parameterless constructor is defined in a class, then that constructor can be removed because the compiler would generate it automatically. Similarly, empty `static` constructors and empty destructors are also wasted keystrokes. - + +Since the compiler will automatically invoke the base type’s no-argument constructor, there’s no need to specify its invocation explicitly. Also, +when only a single `public` parameterless constructor is defined in a class, then that constructor can be removed because the compiler +would generate it automatically. Similarly, empty `static` constructors and empty destructors are also wasted keystrokes. + ### Noncompliant code example class X diff --git a/docs/description/S3254.md b/docs/description/S3254.md index 546d6b9..3d44525 100644 --- a/docs/description/S3254.md +++ b/docs/description/S3254.md @@ -1,14 +1,14 @@ ## Why is this an issue? - + Specifying the default parameter values in a method call is redundant. Such values should be omitted in the interests of readability. - + ### Noncompliant code example public void M(int x, int y=5, int z = 7) { /* ... */ } // ... - M(1, 5); //Noncompliant, y has the default value - M(1, z: 7); //Noncompliant, z has the default value + M(1, 5); // Noncompliant, y has the default value + M(1, z: 7); // Noncompliant, z has the default value ### Compliant solution diff --git a/docs/description/S3256.md b/docs/description/S3256.md index 5944945..31fe459 100644 --- a/docs/description/S3256.md +++ b/docs/description/S3256.md @@ -1,7 +1,9 @@ ## Why is this an issue? - -Using `string.Equals` to determine if a string is empty is significantly slower than using `string.IsNullOrEmpty()` or checking for `string.Length == 0`. `string.IsNullOrEmpty()` is both clear and concise, and therefore preferred to laborious, error-prone, manual null- and emptiness-checking. - + +Using `string.Equals` to determine if a string is empty is significantly slower than using `string.IsNullOrEmpty()` or +checking for `string.Length == 0`. `string.IsNullOrEmpty()` is both clear and concise, and therefore preferred to laborious, +error-prone, manual null- and emptiness-checking. + ### Noncompliant code example "".Equals(name); // Noncompliant diff --git a/docs/description/S3257.md b/docs/description/S3257.md index 535fcbe..bcb0b5d 100644 --- a/docs/description/S3257.md +++ b/docs/description/S3257.md @@ -1,11 +1,14 @@ ## Why is this an issue? - -In C#, the type of a variable can often be inferred by the compiler. The use of the [var keyword]([https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/implicitly-typed-local-variables](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/implicitly-typed-local-variables)) allows you to avoid repeating the type name in a variable declaration and object instantiation because the declared type can often be inferred by the compiler. - + +In C#, the type of a variable can often be inferred by the compiler. The use of the [var keyword]([https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/implicitly-typed-local-variables](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/implicitly-typed-local-variables)) +allows you to avoid repeating the type name in a variable declaration and object instantiation because the declared type can often be inferred by the +compiler. + Additionally, initializations providing the default value can also be omitted, helping to make the code more concise and readable. - -Unnecessarily verbose declarations and initializations should be simplified. Specifically, the following should be omitted when they can be inferred: - + +Unnecessarily verbose declarations and initializations should be simplified. Specifically, the following should be omitted when they can be +inferred: + - array element type - array size - `new DelegateType` @@ -15,11 +18,11 @@ Unnecessarily verbose declarations and initializations should be simplified. Spe - parameter declarations of anonymous methods when the parameters are not used. ## How to fix it - + Remove any unneeded code. C# provides many features designed to help you write more concise code. - + ### Code examples - + #### Noncompliant code example var l = new List() {}; // Noncompliant, {} can be removed @@ -67,7 +70,7 @@ Remove any unneeded code. C# provides many features designed to help you write m } ## Resources - + ### Documentation - Microsoft Learn - [Declaration diff --git a/docs/description/S3260.md b/docs/description/S3260.md index 25ee5c8..c09e20e 100644 --- a/docs/description/S3260.md +++ b/docs/description/S3260.md @@ -1,17 +1,20 @@ ## Why is this an issue? - -Classes and records with either `private` or `file` access modifiers aren’t visible outside of their assemblies or files, so if they’re not extended inside their scope, they should be made explicitly non-extensible with the addition of the `sealed` keyword. - + +Classes and records with either `private` or `file` access modifiers aren’t visible outside of their assemblies or files, so +if they’re not extended inside their scope, they should be made explicitly non-extensible with the addition of the `sealed` keyword. + ### What is the potential impact? - -We measured at least 4x improvement in execution time. For more details see the `Benchmarks` section from the `More info` tab. - + +We measured at least 4x improvement in execution time. For more details see the `Benchmarks` section from the `More info` +tab. + ## How to fix it - -The code can be improved by adding the `sealed` keyword in front of the `class` or `record` types that have no inheritors. - + +The code can be improved by adding the `sealed` keyword in front of the `class` or `record` types that have no +inheritors. + ### Code examples - + #### Noncompliant code example private class MyClass // Noncompliant @@ -57,9 +60,9 @@ The code can be improved by adding the `sealed` keyword in front of the `class` } ## Resources - + ### Documentation - + - [The `sealed` keyword](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/sealed) ### Articles & blog posts diff --git a/docs/description/S3261.md b/docs/description/S3261.md index 7a3af8f..bb0e1c0 100644 --- a/docs/description/S3261.md +++ b/docs/description/S3261.md @@ -1,7 +1,7 @@ ## Why is this an issue? - + Namespaces with no lines of code clutter a project and should be removed. - + ### Noncompliant code example namespace MyEmptyNamespace // Noncompliant diff --git a/docs/description/S3262.md b/docs/description/S3262.md index bb723d4..6702c22 100644 --- a/docs/description/S3262.md +++ b/docs/description/S3262.md @@ -1,7 +1,8 @@ ## Why is this an issue? - -Overriding methods automatically inherit the `params` behavior. To ease readability, this modifier should be explicitly used in the overriding method as well. - + +Overriding methods automatically inherit the `params` behavior. To ease readability, this modifier should be explicitly used in the +overriding method as well. + ### Noncompliant code example class Base diff --git a/docs/description/S3263.md b/docs/description/S3263.md index 923a04b..e124748 100644 --- a/docs/description/S3263.md +++ b/docs/description/S3263.md @@ -1,7 +1,8 @@ ## Why is this an issue? - -Static field initializers are executed in the order in which they appear in the class from top to bottom. Thus, placing a static field in a class above the field or fields required for its initialization will yield unexpected results. - + +Static field initializers are executed in the order in which they appear in the class from top to bottom. Thus, placing a static field in a class +above the field or fields required for its initialization will yield unexpected results. + ### Noncompliant code example class MyClass diff --git a/docs/description/S3264.md b/docs/description/S3264.md index 0744857..c66c905 100644 --- a/docs/description/S3264.md +++ b/docs/description/S3264.md @@ -1,16 +1,16 @@ ## Why is this an issue? - + Events that are not invoked anywhere are dead code, and there’s no good reason to keep them in the source. - + ### Noncompliant code example class UninvokedEventSample { - private event Action Happened; //Noncompliant + private event Action Happened; // Noncompliant public void RegisterEventHandler(Action handler) { - Happened += handler; //we register some event handlers + Happened += handler; // we register some event handlers } public void RaiseEvent() diff --git a/docs/description/S3265.md b/docs/description/S3265.md index e93112b..152f3cc 100644 --- a/docs/description/S3265.md +++ b/docs/description/S3265.md @@ -1,13 +1,16 @@ ## Why is this an issue? - -[Enumerations](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/enum) are commonly used to identify distinct elements from a set of values. - -However, they can also serve as [bit flags](https://en.wikipedia.org/wiki/Bit_field), enabling bitwise operations to combine multiple elements within a single value. + +[Enumerations](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/enum) are commonly used to identify +distinct elements from a set of values. + +However, they can also serve as [bit flags](https://en.wikipedia.org/wiki/Bit_field), enabling bitwise operations to combine multiple +elements within a single value. // Saturday = 0b00100000, Sunday = 0b01000000, weekend = 0b01100000 var weekend = Days.Saturday | Days.Sunday; // Combining elements -When enumerations are used as bit flags, it is considered [good practice](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/enum#enumeration-types-as-bit-flags) to annotate the enum type with the [FlagsAttribute](https://learn.microsoft.com/en-us/dotnet/api/system.flagsattribute): +When enumerations are used as bit flags, it is considered [good practice](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/enum#enumeration-types-as-bit-flags) to +annotate the enum type with the [FlagsAttribute](https://learn.microsoft.com/en-us/dotnet/api/system.flagsattribute): enum Permissions { @@ -21,7 +24,8 @@ When enumerations are used as bit flags, it is considered [good practice](https: var x = Permissions.Read | Permissions.Write; // Noncompliant: enum is not annotated with [Flags] -The `FlagsAttribute` explicitly marks an enumeration as bit flags, making it clear that it uses bit fields and is intended to be used as flags. +The `FlagsAttribute` explicitly marks an enumeration as bit flags, making it clear that it uses bit fields and is intended to be used as +flags. [Flags] enum Permissions @@ -37,11 +41,11 @@ The `FlagsAttribute` explicitly marks an enumeration as bit flags, making it cle var x = Permissions.Read | Permissions.Write; // Compliant: enum is annotated with [Flags] Additionally, adding the `FlagsAttribute` to the enumeration enable a [better string representation](https://learn.microsoft.com/en-us/dotnet/api/system.flagsattribute#examples) when using the [Enum.ToString](https://learn.microsoft.com/en-us/dotnet/api/system.enum.tostring) method. - + ## Resources - + ### Documentation - + - [Enumeration in C#](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/enum) - [Enumeration types as bit flags](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/enum#enumeration-types-as-bit-flags) diff --git a/docs/description/S3267.md b/docs/description/S3267.md index 6158203..c8472d7 100644 --- a/docs/description/S3267.md +++ b/docs/description/S3267.md @@ -1,7 +1,7 @@ ## Why is this an issue? - + When a loop is filtering, selecting or aggregating, those functions can be handled with a clearer, more concise LINQ expression instead. - + ### Noncompliant code example var result = new List(); diff --git a/docs/description/S3329.md b/docs/description/S3329.md index 6454733..a272ecb 100644 --- a/docs/description/S3329.md +++ b/docs/description/S3329.md @@ -1,9 +1,10 @@ This vulnerability exposes encrypted data to a number of attacks whose goal is to recover the plaintext. - + ## Why is this an issue? - -Encryption algorithms are essential for protecting sensitive information and ensuring secure communications in a variety of domains. They are used for several important reasons: - + +Encryption algorithms are essential for protecting sensitive information and ensuring secure communications in a variety of domains. They are used +for several important reasons: + - Confidentiality, privacy, and intellectual property protection - Security during transmission or on storage devices - Data integrity, general trust, and authentication @@ -13,39 +14,47 @@ When selecting encryption algorithms, tools, or combinations, you should also co 1. No encryption is unbreakable. 2. The strength of an encryption algorithm is usually measured by the effort required to crack it within a reasonable time frame. -In the mode Cipher Block Chaining (CBC), each block is used as cryptographic input for the next block. For this reason, the first block requires an initialization vector (IV), also called a "starting variable" (SV). - -If the same IV is used for multiple encryption sessions or messages, each new encryption of the same plaintext input would always produce the same ciphertext output. This may allow an attacker to detect patterns in the ciphertext. - +In the mode Cipher Block Chaining (CBC), each block is used as cryptographic input for the next block. For this reason, the first block requires an +initialization vector (IV), also called a "starting variable" (SV). + +If the same IV is used for multiple encryption sessions or messages, each new encryption of the same plaintext input would always produce the same +ciphertext output. This may allow an attacker to detect patterns in the ciphertext. + ### What is the potential impact? - -After retrieving encrypted data and performing cryptographic attacks on it on a given timeframe, attackers can recover the plaintext that encryption was supposed to protect. - + +After retrieving encrypted data and performing cryptographic attacks on it on a given timeframe, attackers can recover the plaintext that +encryption was supposed to protect. + Depending on the recovered data, the impact may vary. - + Below are some real-world scenarios that illustrate the potential impact of an attacker exploiting the vulnerability. - + #### Additional attack surface - -By modifying the plaintext of the encrypted message, an attacker may be able to trigger additional vulnerabilities in the code. An attacker can further exploit a system to obtain more information. - Encrypted values are often considered trustworthy because it would not be possible for a third party to modify them under normal circumstances. - + +By modifying the plaintext of the encrypted message, an attacker may be able to trigger additional vulnerabilities in the code. An attacker can +further exploit a system to obtain more information. + Encrypted values are often considered trustworthy because it would not be possible for a +third party to modify them under normal circumstances. + #### Breach of confidentiality and privacy - -When encrypted data contains personal or sensitive information, its retrieval by an attacker can lead to privacy violations, identity theft, financial loss, reputational damage, or unauthorized access to confidential systems. - + +When encrypted data contains personal or sensitive information, its retrieval by an attacker can lead to privacy violations, identity theft, +financial loss, reputational damage, or unauthorized access to confidential systems. + In this scenario, a company, its employees, users, and partners could be seriously affected. - -The impact is twofold, as data breaches and exposure of encrypted data can undermine trust in the organization, as customers, clients and stakeholders may lose confidence in the organization’s ability to protect their sensitive data. - + +The impact is twofold, as data breaches and exposure of encrypted data can undermine trust in the organization, as customers, clients and +stakeholders may lose confidence in the organization’s ability to protect their sensitive data. + #### Legal and compliance issues - -In many industries and locations, there are legal and compliance requirements to protect sensitive data. If encrypted data is compromised and the plaintext can be recovered, companies face legal consequences, penalties, or violations of privacy laws. - + +In many industries and locations, there are legal and compliance requirements to protect sensitive data. If encrypted data is compromised and the +plaintext can be recovered, companies face legal consequences, penalties, or violations of privacy laws. + ## How to fix it in .NET - + ### Code examples - + #### Noncompliant code example using System.IO; @@ -65,7 +74,7 @@ In many industries and locations, there are legal and compliance requirements to } #### Compliant solution - + In this example, the code implicitly uses a number generator that is considered **strong**, thanks to `aes.IV`. using System.IO; @@ -84,21 +93,22 @@ In this example, the code implicitly uses a number generator that is considered } ### How does this work? - + #### Use unique IVs - + To ensure high security, initialization vectors must meet two important criteria: - IVs must be unique for each encryption operation. - For CBC and CFB modes, a secure FIPS-compliant random number generator should be used to generate unpredictable IVs. The IV does not need be secret, so the IV or information sufficient to determine the IV may be transmitted along with the ciphertext. - + In the previous non-compliant example, the problem is not that the IV is hard-coded. - It is that the same IV is used for multiple encryption attempts. - + It is that the same IV is used for multiple encryption +attempts. + ## Resources - + ### Standards - OWASP - [Top 10 2021 Category A2 - Cryptographic Failures](https://owasp.org/Top10/A02_2021-Cryptographic_Failures/) diff --git a/docs/description/S3330.md b/docs/description/S3330.md index 7ac7cf3..5b2a42d 100644 --- a/docs/description/S3330.md +++ b/docs/description/S3330.md @@ -1,31 +1,36 @@ -When a cookie is configured with the `HttpOnly` attribute set to *true*, the browser guaranties that no client-side script will be able to read it. In most cases, when a cookie is created, the default value of `HttpOnly` is *false* and it’s up to the developer to decide whether or not the content of the cookie can be read by the client-side script. As a majority of Cross-Site Scripting (XSS) attacks target the theft of session-cookies, the `HttpOnly` attribute can help to reduce their impact as it won’t be possible to exploit the XSS vulnerability to steal session-cookies. - +When a cookie is configured with the `HttpOnly` attribute set to *true*, the browser guaranties that no client-side script will +be able to read it. In most cases, when a cookie is created, the default value of `HttpOnly` is *false* and it’s up to the developer +to decide whether or not the content of the cookie can be read by the client-side script. As a majority of Cross-Site Scripting (XSS) attacks target +the theft of session-cookies, the `HttpOnly` attribute can help to reduce their impact as it won’t be possible to exploit the XSS +vulnerability to steal session-cookies. + ## Ask Yourself Whether - + - the cookie is sensitive, used to authenticate the user, for instance a *session-cookie* - the `HttpOnly` attribute offer an additional protection (not the case for an *XSRF-TOKEN cookie* / CSRF token for example) There is a risk if you answered yes to any of those questions. - + ## Recommended Secure Coding Practices - By default the `HttpOnly` flag should be set to *true* for most of the cookies and it’s mandatory for session / sensitive-security cookies. ## Sensitive Code Example - + When the `HttpCookie.HttpOnly` property is set to `false` then the cookie can be accessed by client side code: HttpCookie myCookie = new HttpCookie("Sensitive cookie"); myCookie.HttpOnly = false; // Sensitive: this cookie is created with the httponly flag set to false and so it can be stolen easily in case of XSS vulnerability -The [default value](https://docs.microsoft.com/en-us/dotnet/api/system.web.httpcookie.httponly?view=netframework-4.8) of `HttpOnly` flag is `false`, unless overwritten by an application’s configuration file: +The [default value](https://docs.microsoft.com/en-us/dotnet/api/system.web.httpcookie.httponly?view=netframework-4.8) of +`HttpOnly` flag is `false`, unless overwritten by an application’s configuration file: HttpCookie myCookie = new HttpCookie("Sensitive cookie"); // Sensitive: this cookie is created without the httponly flag (by default set to false) and so it can be stolen easily in case of XSS vulnerability ## Compliant Solution - + Set the `HttpCookie.HttpOnly` property to `true`: HttpCookie myCookie = new HttpCookie("Sensitive cookie"); @@ -45,4 +50,6 @@ Or change the default flag values for the whole application by editing the [Web. - OWASP - [Top 10 2017 Category A7 - Cross-Site Scripting (XSS)](https://owasp.org/www-project-top-ten/2017/A7_2017-Cross-Site_Scripting_%28XSS%29) - CWE - [CWE-1004 - Sensitive Cookie Without 'HttpOnly' Flag](https://cwe.mitre.org/data/definitions/1004) -- Derived from FindSecBugs rule [HTTPONLY\_COOKIE](https://find-sec-bugs.github.io/bugs.htm#HTTPONLY_COOKIE) \ No newline at end of file +- Derived from FindSecBugs rule [HTTPONLY_COOKIE](https://find-sec-bugs.github.io/bugs.htm#HTTPONLY_COOKIE) +- STIG Viewer - [Application Security and + Development: V-222575](https://stigviewer.com/stig/application_security_and_development/2023-06-08/finding/V-222575) - The application must set the HTTPOnly flag on session cookies. \ No newline at end of file diff --git a/docs/description/S3343.md b/docs/description/S3343.md index b9848c2..3cee75c 100644 --- a/docs/description/S3343.md +++ b/docs/description/S3343.md @@ -1,20 +1,23 @@ ## Why is this an issue? - -[Caller information attributes](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/caller-information) provide a way to get information about the caller of a method through [optional](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/named-and-optional-arguments#optional-arguments) parameters. But they only work right if their values aren’t provided explicitly. So if you define a method with caller info attributes in the middle of the parameter list, the caller is forced to use named arguments if they want to use the method properly. - + +[Caller information attributes](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/caller-information) +provide a way to get information about the caller of a method through [optional](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/named-and-optional-arguments#optional-arguments) +parameters. But they only work right if their values aren’t provided explicitly. So if you define a method with caller info attributes in the middle +of the parameter list, the caller is forced to use named arguments if they want to use the method properly. + This rule raises an issue when the following attributes are used on parameters before the end of the parameter list: - + - [CallerFilePathAttribute](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.callerfilepathattribute) - [CallerLineNumberAttribute](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.callerlinenumberattribute) - [CallerMemberNameAttribute](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.callermembernameattribute) - [CallerArgumentExpressionAttribute](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.callerargumentexpressionattribute) ## How to fix it - + Move the decorated parameters to the end of the parameter list. - + ### Code examples - + #### Noncompliant code example void TraceMessage([CallerMemberName] string memberName = "", @@ -36,7 +39,7 @@ Move the decorated parameters to the end of the parameter list. } ## Resources - + ### Documentation - [Determine caller information using diff --git a/docs/description/S3346.md b/docs/description/S3346.md index 9dfadf3..496a78d 100644 --- a/docs/description/S3346.md +++ b/docs/description/S3346.md @@ -1,32 +1,40 @@ ## Why is this an issue? - -An assertion is a piece of code that’s used during development when the [compilation debug mode is activated](https://learn.microsoft.com/en-us/visualstudio/debugger/how-to-set-debug-and-release-configurations). It allows a program to check itself as it runs. When an assertion is `true`, that means everything is operating as expected. - -In non-debug mode, all [`Debug.Assert`](https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.debug.assert) calls are automatically left out (via the [`Conditional("DEBUG")`](https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.conditionalattribute) mechanism). So, by contract, the boolean expressions that are evaluated by those assertions must not contain any [side effects](https://en.wikipedia.org/wiki/Side_effect_%28computer_science%29). Otherwise, when leaving the debug mode, the functional behavior of the application is not the same anymore. - -The rule will raise if the method name starts with any of the following `remove`, `delete`, `add`, `pop`, `update`, `retain`, `insert`, `push`, `append`, `clear`, `dequeue`, `enqueue`, `dispose`, `put`, or `set`, although `SetEquals` will be ignored. - + +An assertion is a piece of code that’s used during development when the [compilation debug mode is activated](https://learn.microsoft.com/en-us/visualstudio/debugger/how-to-set-debug-and-release-configurations). It +allows a program to check itself as it runs. When an assertion is `true`, that means everything is operating as expected. + +In non-debug mode, all [`Debug.Assert`](https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.debug.assert) calls +are automatically left out (via the [`Conditional("DEBUG")`](https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.conditionalattribute) mechanism). So, by +contract, the boolean expressions that are evaluated by those assertions must not contain any [side effects](https://en.wikipedia.org/wiki/Side_effect_%28computer_science%29). Otherwise, when leaving the debug mode, the functional behavior +of the application is not the same anymore. + +The rule will raise if the method name starts with any of the following `remove`, `delete`, `add`, +`pop`, `update`, `retain`, `insert`, `push`, `append`, `clear`, +`dequeue`, `enqueue`, `dispose`, `put`, or `set`, although `SetEquals` will be +ignored. + ## How to fix it - -In the following example, the assertion checks the return value of the remove method in the argument. Because the whole line is skipped in non-debug builds, the call to `Remove` never happens in such builds. - + +In the following example, the assertion checks the return value of the remove method in the argument. Because the whole line is skipped in +non-debug builds, the call to `Remove` never happens in such builds. + ### Code examples - + #### Noncompliant code example Debug.Assert(list.Remove("dog")); #### Compliant solution - + The `Remove` call must be extracted and the return value needs to be asserted instead. bool result = list.Remove("dog"); Debug.Assert(result); ## Resources - + ### Documentation - + - Microsoft Learn [`Debug.Assert` Method](https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.debug.assert/) - Microsoft Learn [Debugging, tracing, and profiling](https://learn.microsoft.com/en-us/dotnet/framework/debug-trace-profile/) - Microsoft Learn [How to: Compile diff --git a/docs/description/S3353.md b/docs/description/S3353.md index 951b5a5..780092d 100644 --- a/docs/description/S3353.md +++ b/docs/description/S3353.md @@ -1,17 +1,20 @@ ## Why is this an issue? - -If a variable that is not supposed to change is not marked as `const`, it could be accidentally reassigned elsewhere in the code, leading to unexpected behavior and bugs that can be hard to track down. - -By declaring a variable as `const`, you ensure that its value remains constant throughout the code. It also signals to other developers that this value is intended to remain constant. This can make the code easier to understand and maintain. - -In some cases, using `const` can lead to performance improvements. The compiler might be able to make optimizations knowing that the value of a `const` variable will not change. - + +If a variable that is not supposed to change is not marked as `const`, it could be accidentally reassigned elsewhere in the code, +leading to unexpected behavior and bugs that can be hard to track down. + +By declaring a variable as `const`, you ensure that its value remains constant throughout the code. It also signals to other developers +that this value is intended to remain constant. This can make the code easier to understand and maintain. + +In some cases, using `const` can lead to performance improvements. The compiler might be able to make optimizations knowing that the +value of a `const` variable will not change. + ## How to fix it - + Mark the given variable with the `const` modifier. - + ### Code examples - + #### Noncompliant code example public bool Seek(int[] input) @@ -63,7 +66,7 @@ Mark the given variable with the `const` modifier. } ## Resources - + ### Documentation - + - Microsoft Learn - [const](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/const) \ No newline at end of file diff --git a/docs/description/S3358.md b/docs/description/S3358.md index 1477112..4133352 100644 --- a/docs/description/S3358.md +++ b/docs/description/S3358.md @@ -1,5 +1,5 @@ ## Why is this an issue? - + Nested ternaries are hard to read and can make the order of operations complex to understand. public string GetReadableStatus(Job j) diff --git a/docs/description/S3363.md b/docs/description/S3363.md index 3e0f2f2..a60cf29 100644 --- a/docs/description/S3363.md +++ b/docs/description/S3363.md @@ -1,9 +1,12 @@ -You should only set a property of a temporal type (like `DateTime` or `DateTimeOffset`) as the primary key of a table if the values are guaranteed to be unique. - +You should only set a property of a temporal type (like `DateTime` or `DateTimeOffset`) as the primary key of a table if the +values are guaranteed to be unique. + ## Why is this an issue? - -Using temporal types as the primary key of a table is risky. When these types are used as primary keys, it usually means that each new key is created with the use of `.Now` or `.UtcNow` properties from `DateTime` and `DateTimeOffset` classes. In those cases, duplicate keys exceptions may occur in many ways: - + +Using temporal types as the primary key of a table is risky. When these types are used as primary keys, it usually means that each new key is +created with the use of `.Now` or `.UtcNow` properties from `DateTime` and `DateTimeOffset` classes. In +those cases, duplicate keys exceptions may occur in many ways: + - when entries are added consecutively by a machine with low-enough system clock resolution; - when two different threads are inserting entries in close enough sequence for both to have the same time; - when changes such as daylight saving time (DST) transitions occur, where values can be repeated the following hour (only for @@ -22,11 +25,11 @@ The rule raises an issue if: - [System.TimeOnly](https://learn.microsoft.com/en-us/dotnet/api/system.timeonly) ## How to fix it - + Either use a GUID or the auto generated ID as a primary key. - + ### Code examples - + #### Noncompliant code example internal class Account @@ -48,7 +51,7 @@ Either use a GUID or the auto generated ID as a primary key. } or - + #### Noncompliant code example internal class Person @@ -72,7 +75,7 @@ or } ## Resources - + ### Documentation - [Entity Framework keys and data annotation](https://learn.microsoft.com/en-us/ef/core/modeling/keys?tabs=data-annotations) diff --git a/docs/description/S3366.md b/docs/description/S3366.md index 8bd4b3b..cafed45 100644 --- a/docs/description/S3366.md +++ b/docs/description/S3366.md @@ -1,11 +1,16 @@ ## Why is this an issue? - -In single-threaded environments, the use of `this` in constructors is normal, and expected. But in multi-threaded environments, it could expose partially-constructed objects to other threads, and should be used with caution. - -The classic example is a class with a `static` list of its instances. If the constructor stores `this` in the list, another thread could access the object before it’s fully-formed. Even when the storage of `this` is the last instruction in the constructor, there’s still a danger if the class is not `final`. In that case, the initialization of subclasses won’t be complete before `this` is exposed. - -This rule raises an issue when `this` is assigned to any globally-visible object in a constructor, and when it is passed to the method of another object in a constructor - + +In single-threaded environments, the use of `this` in constructors is normal, and expected. But in multi-threaded environments, it could +expose partially-constructed objects to other threads, and should be used with caution. + +The classic example is a class with a `static` list of its instances. If the constructor stores `this` in the list, another +thread could access the object before it’s fully-formed. Even when the storage of `this` is the last instruction in the constructor, +there’s still a danger if the class is not `final`. In that case, the initialization of subclasses won’t be complete before +`this` is exposed. + +This rule raises an issue when `this` is assigned to any globally-visible object in a constructor, and when it is passed to the method +of another object in a constructor + ### Noncompliant code example public class Monument @@ -23,5 +28,6 @@ This rule raises an issue when `this` is assigned to any globally-visible object } ### Exceptions - -This rule ignores instances of assigning `this` directly to a `static` field of the same class because that case is covered by {rule:csharpsquid:S3010} . \ No newline at end of file + +This rule ignores instances of assigning `this` directly to a `static` field of the same class because that case is covered +by {rule:csharpsquid:S3010} . \ No newline at end of file diff --git a/docs/description/S3376.md b/docs/description/S3376.md index 83b10c6..6f06d50 100644 --- a/docs/description/S3376.md +++ b/docs/description/S3376.md @@ -1,10 +1,11 @@ ## Why is this an issue? - + Adherence to the standard naming conventions makes your code not only more readable, but more usable. For instance, `class FirstAttribute : Attribute` can be used simply with `First`, but you must use the full name for `class AttributeOne : Attribute`. - -This rule raises an issue when classes extending `Attribute`, `EventArgs`, or `Exception`, do not end with their parent class names. - + +This rule raises an issue when classes extending `Attribute`, `EventArgs`, or `Exception`, do not end with their +parent class names. + ### Noncompliant code example class AttributeOne : Attribute // Noncompliant @@ -18,8 +19,9 @@ This rule raises an issue when classes extending `Attribute`, `EventArgs`, or `E } ### Exceptions - -If a class' direct base class doesn’t follow the convention, then no issue is reported on the class itself, regardless of whether or not it conforms to the convention. + +If a class' direct base class doesn’t follow the convention, then no issue is reported on the class itself, regardless of whether or not it +conforms to the convention. class Timeout : Exception // Noncompliant { diff --git a/docs/description/S3397.md b/docs/description/S3397.md index f9b1114..6cd9f0f 100644 --- a/docs/description/S3397.md +++ b/docs/description/S3397.md @@ -1,9 +1,12 @@ ## Why is this an issue? - -`object.Equals()` overrides can be optimized by checking first for reference equality between `this` and the parameter. This check can be implemented by calling `object.ReferenceEquals()` or `base.Equals()`, where `base` is `object`. However, using `base.Equals()` is a maintenance hazard because while it works if you extend `Object` directly, if you introduce a new base class that overrides `Equals`, it suddenly stops working. - + +`object.Equals()` overrides can be optimized by checking first for reference equality between `this` and the parameter. This +check can be implemented by calling `object.ReferenceEquals()` or `base.Equals()`, where `base` is +`object`. However, using `base.Equals()` is a maintenance hazard because while it works if you extend `Object` +directly, if you introduce a new base class that overrides `Equals`, it suddenly stops working. + This rule raises an issue if `base.Equals()` is used but `base` is not `object`. - + ### Noncompliant code example class Base diff --git a/docs/description/S3398.md b/docs/description/S3398.md index ea619ad..dd37727 100644 --- a/docs/description/S3398.md +++ b/docs/description/S3398.md @@ -1,7 +1,8 @@ ## Why is this an issue? - -When a `private static` method is only invoked by a nested class, there’s no reason not to move it into that class. It will still have the same access to the outer class' static members, but the outer class will be clearer and less cluttered. - + +When a `private static` method is only invoked by a nested class, there’s no reason not to move it into that class. It will still have +the same access to the outer class' static members, but the outer class will be clearer and less cluttered. + ### Noncompliant code example public class Outer diff --git a/docs/description/S3400.md b/docs/description/S3400.md index 8e0c9ca..d044ba4 100644 --- a/docs/description/S3400.md +++ b/docs/description/S3400.md @@ -1,9 +1,10 @@ ## Why is this an issue? - -There’s no point in forcing the overhead of a method call for a method that always returns the same constant value. Even worse, the fact that a method call must be made will likely mislead developers who call the method thinking that something more is done. Declare a constant instead. - + +There’s no point in forcing the overhead of a method call for a method that always returns the same constant value. Even worse, the fact that a +method call must be made will likely mislead developers who call the method thinking that something more is done. Declare a constant instead. + This rule raises an issue if on methods that contain only one statement: the `return` of a constant value. - + ### Noncompliant code example int GetBestNumber() diff --git a/docs/description/S3415.md b/docs/description/S3415.md index 4d18fa1..f012c6d 100644 --- a/docs/description/S3415.md +++ b/docs/description/S3415.md @@ -1,19 +1,23 @@ ## Why is this an issue? - -The standard assertions library methods such as `AreEqual` and `AreSame` in **MSTest** and **NUnit**, or `Equal` and `Same` in **XUnit**, expect the first argument to be the expected value and the second argument to be the actual value. - + +The standard assertions library methods such as `AreEqual` and `AreSame` in **MSTest** and +**NUnit**, or `Equal` and `Same` in **XUnit**, expect the first argument to be the expected value and +the second argument to be the actual value. + ### What is the potential impact? - -Having the expected value and the actual value in the wrong order will not alter the outcome of tests, (succeed/fail when it should) but the error messages will contain misleading information. - + +Having the expected value and the actual value in the wrong order will not alter the outcome of tests, (succeed/fail when it should) but the error +messages will contain misleading information. + This rule raises an issue when the actual argument to an assertions library method is a hard-coded value and the expected argument is not. - + ## How to fix it - -You should provide the assertion methods with a hard-coded value as the expected value, while the actual value of the assertion should derive from the portion of code that you want to test. - + +You should provide the assertion methods with a hard-coded value as the expected value, while the actual value of the assertion should derive from +the portion of code that you want to test. + ### Code examples - + #### Noncompliant code example Assert.AreEqual(runner.ExitCode, 0, "Unexpected exit code"); // Noncompliant; Yields error message like: Expected:<-1>. Actual:<0>. diff --git a/docs/description/S3416.md b/docs/description/S3416.md index cec8918..b615b8b 100644 --- a/docs/description/S3416.md +++ b/docs/description/S3416.md @@ -1,6 +1,7 @@ ## Why is this an issue? - -It is a well-established convention to name each logger after its enclosing type. This rule raises an issue when the convention is not respected. + +It is a well-established convention to name each logger after its enclosing type. This rule raises an issue when the convention is not +respected. class EnclosingType { @@ -14,8 +15,9 @@ It is a well-established convention to name each logger after its enclosing type } Not following such a convention can result in confusion and logging misconfiguration. - -For example, the person configuring the log may attempt to change the logging behavior for the `MyNamespace.EnclosingType` type, by overriding defaults for the logger named after that type. + +For example, the person configuring the log may attempt to change the logging behavior for the `MyNamespace.EnclosingType` type, by +overriding defaults for the logger named after that type. { "Logging": { @@ -26,15 +28,17 @@ For example, the person configuring the log may attempt to change the logging be } } -However, if the convention is not in place, the override would not affect logs from `MyNamespace.EnclosingType`, since they are made via a logger with a different name. - -Moreover, using the same logger name for multiple types prevents the granular configuration of each type’s logger, since there is no way to distinguish them in configuration. - +However, if the convention is not in place, the override would not affect logs from `MyNamespace.EnclosingType`, since they are made via +a logger with a different name. + +Moreover, using the same logger name for multiple types prevents the granular configuration of each type’s logger, since there is no way to +distinguish them in configuration. + The rule targets the following logging frameworks: \* [Microsoft Extensions Logging](https://learn.microsoft.com/en-us/dotnet/core/extensions/logging) \* [Apache log4net](https://logging.apache.org/log4net/) \* [NLog](https://nlog-project.org/) - + ### Exceptions - + The rule doesn’t raise issues when custom handling of logging names is in place, and the logger name is not derived from a `Type`. class EnclosingType @@ -49,7 +53,7 @@ The rule doesn’t raise issues when custom handling of logging names is in plac } ## How to fix it - + When the logger name is defined by a generic type parameter: class EnclosingType @@ -98,9 +102,9 @@ When the logger name is a string, derived from a `Type`: } ## Resources - + ### Documentation - + - Microsoft Learn - [.NET logging and tracing](https://learn.microsoft.com/en-us/dotnet/core/diagnostics/logging-tracing) - Microsoft Learn - [Logging in C# and .NET - Log category](https://learn.microsoft.com/en-us/dotnet/core/extensions/logging?tabs=command-line#log-category) diff --git a/docs/description/S3427.md b/docs/description/S3427.md index 2cbacfd..f88c95a 100644 --- a/docs/description/S3427.md +++ b/docs/description/S3427.md @@ -1,11 +1,13 @@ ## Why is this an issue? - -The rules for method resolution can be complex and may not be fully understood by all developers. The situation becomes even more challenging when dealing with method overloads that have optional parameter values. - -This rule raises an issue when an overload with default parameter values is hidden by another overload that does not have the optional parameters. - + +The rules for method resolution can be complex and may not be fully understood by all developers. The situation becomes even more challenging when +dealing with method overloads that have optional parameter values. + +This rule raises an issue when an overload with default parameter values is hidden by another overload that does not have the optional +parameters. + ### What is the potential impact? - + See the following example: MyClass.Print(1); // which overload of Print will be called? @@ -16,19 +18,20 @@ See the following example: public static void Print(int number, string delimiter = "\n") { } // Noncompliant, default parameter value is hidden by overload } -In this code snippet, the `Print` method is overloaded with two versions, where the first one hides the second one. This can lead to confusion and uncertainty about which overload of the method will be invoked when calling it. - +In this code snippet, the `Print` method is overloaded with two versions, where the first one hides the second one. This can lead to +confusion and uncertainty about which overload of the method will be invoked when calling it. + ## How to fix it - + To address the problem you have a couple of options: - + - Adjust the existing overloads to expose the optional parameters consistently across all overloads. By doing so, callers will have explicit control over which overload they want to invoke. - Alternatively, you can differentiate the overloads by giving them distinct names. This approach clarifies the usage and intent of each overload, making it clear to developers which overload to use in different contexts. ### Code examples - + #### Noncompliant code example MyClass.Print(1); // which overload of Print will be called? @@ -50,7 +53,7 @@ To address the problem you have a couple of options: } ## Resources - + ### Documentation - [Member overloading](https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/member-overloading) diff --git a/docs/description/S3431.md b/docs/description/S3431.md index 1c86170..17d3368 100644 --- a/docs/description/S3431.md +++ b/docs/description/S3431.md @@ -1,9 +1,10 @@ ## Why is this an issue? - -It should be clear to a casual reader what code a test is testing and what results are expected. Unfortunately, that’s not usually the case with the `ExpectedException` attribute since an exception could be thrown from almost any line in the method. - + +It should be clear to a casual reader what code a test is testing and what results are expected. Unfortunately, that’s not usually the case with +the `ExpectedException` attribute since an exception could be thrown from almost any line in the method. + This rule detects MSTest and NUnit `ExpectedException` attribute. - + ### Noncompliant code example [TestMethod] @@ -39,5 +40,5 @@ or } ### Exceptions - + This rule ignores one-line test methods, since it is obvious in such methods where the exception is expected to be thrown. \ No newline at end of file diff --git a/docs/description/S3433.md b/docs/description/S3433.md index 31780f0..3859f5d 100644 --- a/docs/description/S3433.md +++ b/docs/description/S3433.md @@ -1,12 +1,14 @@ ## Why is this an issue? - + A method is identified as a test method if it is marked with one of the following attributes: - + - `[TestMethod]` or `[DataTestMethod]` (for **MSTest**). - `[Fact]` or `[Theory]` (for **xUnit**). - `[Test]`, `[TestCase]`, `[TestCaseSource]`, or `[Theory]` (for **NUnit**). -However, non-`public` methods are not considered test methods and will not be executed, regardless of whether they have a test attribute. Additionally, methods with the `async void` modifier or methods that contain generics `` anywhere in their signatures are also excluded from being recognized as tests and will not be executed. +However, non-`public` methods are not considered test methods and will not be executed, regardless of whether they have a test +attribute. Additionally, methods with the `async void` modifier or methods that contain generics `` anywhere in their +signatures are also excluded from being recognized as tests and will not be executed. [TestMethod] void TestNullArg() // Noncompliant, method is not public @@ -33,13 +35,15 @@ However, non-`public` methods are not considered test methods and will not be ex { /* ... */ } ### Exceptions - -For **xUnit**, accessibility is disregarded when it comes to `[Fact]` test methods, as they do not necessarily need to be declared as `public`. - -In **xUnit**, `[Theory]` test methods, as well as `[TestCase]` and `[TestCaseSource]` test methods in **NUnit**, have the flexibility to be generic, allowing for a wider range of test scenarios. - + +For **xUnit**, accessibility is disregarded when it comes to `[Fact]` test methods, as they do not necessarily need to be +declared as `public`. + +In **xUnit**, `[Theory]` test methods, as well as `[TestCase]` and `[TestCaseSource]` test methods in +**NUnit**, have the flexibility to be generic, allowing for a wider range of test scenarios. + ## Resources - + ### Documentation - [Unit testing C# with MSTest](https://learn.microsoft.com/en-us/dotnet/core/testing/unit-testing-with-mstest) diff --git a/docs/description/S3440.md b/docs/description/S3440.md index d94864c..e5483fb 100644 --- a/docs/description/S3440.md +++ b/docs/description/S3440.md @@ -1,7 +1,8 @@ ## Why is this an issue? - -There’s no point in checking a variable against the value you’re about to assign it. Save the cycles and lines of code, and simply perform the assignment. - + +There’s no point in checking a variable against the value you’re about to assign it. Save the cycles and lines of code, and simply perform the +assignment. + ### Noncompliant code example if (x != a) // Noncompliant; why bother? @@ -14,8 +15,9 @@ There’s no point in checking a variable against the value you’re about to as x = a; ### Exceptions - -Properties and checks inside setters are excluded from this rule because they could have side effects and removing the check could lead to undesired side effects. + +Properties and checks inside setters are excluded from this rule because they could have side effects and removing the check could lead to +undesired side effects. if (MyProperty != a) { diff --git a/docs/description/S3441.md b/docs/description/S3441.md index bea3872..3f54191 100644 --- a/docs/description/S3441.md +++ b/docs/description/S3441.md @@ -1,7 +1,8 @@ ## Why is this an issue? - -When an anonymous type’s properties are copied from properties or variables with the same names, it yields cleaner code to omit the new type’s property name and the assignment operator. - + +When an anonymous type’s properties are copied from properties or variables with the same names, it yields cleaner code to omit the new type’s +property name and the assignment operator. + ### Noncompliant code example var X = 5; diff --git a/docs/description/S3442.md b/docs/description/S3442.md index 361a2b2..cbdfcdd 100644 --- a/docs/description/S3442.md +++ b/docs/description/S3442.md @@ -1,15 +1,19 @@ ## Why is this an issue? - -The [abstract](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/abstract) modifier in a class declaration is used to indicate that a class is intended only to be a base class of other classes, not instantiated on its own. - -Since `abstract` classes cannot be instantiated, there is no need for `public` or `internal` constructors. If there is basic initialization logic that should run when an extending class instance is created, you can add it in a `private`, `private protected` or `protected` constructor. - + +The [abstract](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/abstract) modifier in a class declaration is +used to indicate that a class is intended only to be a base class of other classes, not instantiated on its own. + +Since `abstract` classes cannot be instantiated, there is no need for `public` or `internal` constructors. If +there is basic initialization logic that should run when an extending class instance is created, you can add it in a `private`, +`private protected` or `protected` constructor. + ## How to fix it - -Restrict the constructor visibility to the minimum: `private`, `private protected` or `protected`, depending on the usage. - + +Restrict the constructor visibility to the minimum: `private`, `private protected` or `protected`, depending on +the usage. + ### Code examples - + #### Noncompliant code example abstract class Base @@ -31,8 +35,8 @@ Restrict the constructor visibility to the minimum: `private`, `private protecte } ## Resources - + ### Documentation - + - [abstract keyword](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/abstract) - [abstract type](https://en.wikipedia.org/wiki/Abstract_type) \ No newline at end of file diff --git a/docs/description/S3443.md b/docs/description/S3443.md index 73b91dc..2faad54 100644 --- a/docs/description/S3443.md +++ b/docs/description/S3443.md @@ -1,21 +1,24 @@ ## Why is this an issue? - -Calling `GetType` on a `Type` variable will always return the `System.Type` representation, which is equivalent to `typeof(System.Type)`. This also applies to passing a `Type` argument to `IsInstanceOfType` which always returns `false`. - + +Calling `GetType` on a `Type` variable will always return the `System.Type` representation, which is equivalent to +`typeof(System.Type)`. This also applies to passing a `Type` argument to `IsInstanceOfType` which always returns +`false`. + In both cases, the results are entirely predictable and should be avoided. - + ### Exceptions - -Calling `GetType` on `System.Type` is considered compliant to get an instance of `System.RuntimeType`, as demonstrated in the following example: + +Calling `GetType` on `System.Type` is considered compliant to get an instance of `System.RuntimeType`, as +demonstrated in the following example: typeof(Type).GetType(); // Can be used by convention to get an instance of 'System.RuntimeType' ## How to fix it - + Make sure the usage of `GetType` or `IsInstanceOfType` is invoked with the correct variable or argument type. - + ### Code examples - + #### Noncompliant code example void ExamineSystemType(string str) @@ -38,9 +41,9 @@ Make sure the usage of `GetType` or `IsInstanceOfType` is invoked with the corre } ## Resources - + ### Documentation - + - ["Type" class](https://learn.microsoft.com/en-us/dotnet/api/system.type) - ["GetType" Method](https://learn.microsoft.com/en-us/dotnet/api/system.object.gettype) - ["IsInstanceOfType" Method](https://learn.microsoft.com/en-us/dotnet/api/system.type.isinstanceoftype) diff --git a/docs/description/S3444.md b/docs/description/S3444.md index 6c20808..0ffdcd3 100644 --- a/docs/description/S3444.md +++ b/docs/description/S3444.md @@ -1,9 +1,11 @@ ## Why is this an issue? - -When an interface inherits from two interfaces that both define a member with the same name, trying to access that member through the derived interface will result in the compiler error `CS0229 Ambiguity between 'IBase1.SomeProperty' and 'IBase2.SomeProperty'`. - -So instead, every caller will be forced to cast instances of the derived interface to one or the other of its base interfaces to resolve the ambiguity and be able to access the member. Instead, it is better to resolve the ambiguity in the definition of the derived interface either by: - + +When an interface inherits from two interfaces that both define a member with the same name, trying to access that member through the derived +interface will result in the compiler error `CS0229 Ambiguity between 'IBase1.SomeProperty' and 'IBase2.SomeProperty'`. + +So instead, every caller will be forced to cast instances of the derived interface to one or the other of its base interfaces to resolve the +ambiguity and be able to access the member. Instead, it is better to resolve the ambiguity in the definition of the derived interface either by: + - renaming the member in one of the base interfaces to remove the collision - also defining that member in the derived interface. Use this only if all copies of the member are meant to hold the same value. diff --git a/docs/description/S3445.md b/docs/description/S3445.md index 9d37ced..7c6a020 100644 --- a/docs/description/S3445.md +++ b/docs/description/S3445.md @@ -1,13 +1,16 @@ ## Why is this an issue? - -In C#, the [throw](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/statements#13106-the-throw-statement) statement can be used in two different ways: - + +In C#, the [throw](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/statements#13106-the-throw-statement) +statement can be used in two different ways: + - by specifying an expression - without specifying an expression ### By specifying an expression - -In the software development context, an expression is a value or anything that executes and ends up being a value. The expression shall be implicitly convertible to `System.Exception`, and the result of evaluating the expression is converted to `System.Exception` before being thrown. + +In the software development context, an expression is a value or anything that executes and ends up being a value. The expression shall be +implicitly convertible to `System.Exception`, and the result of evaluating the expression is converted to `System.Exception` +before being thrown. try { @@ -18,11 +21,13 @@ In the software development context, an expression is a value or anything that e throw exception; // The exception stack trace is cleared up to this point. } -In this case, the [stack trace](https://en.wikipedia.org/wiki/Stack_trace), will be cleared, losing the list of method calls between the original method that threw the exception and the current method. - +In this case, the [stack trace](https://en.wikipedia.org/wiki/Stack_trace), will be cleared, losing the list of method calls between the +original method that threw the exception and the current method. + ### Without specifying an expression - -This syntax is supported only in a `catch` block, in which case, that statement re-throws the exception currently being handled by that `catch` block, preserving the stack trace. + +This syntax is supported only in a `catch` block, in which case, that statement re-throws the exception currently being handled by that +`catch` block, preserving the stack trace. try { @@ -34,7 +39,7 @@ This syntax is supported only in a `catch` block, in which case, that statement } ### Exceptions - + It is allowed using the thrown `exception` as an argument and wrapping it in another `exception`. try @@ -46,11 +51,12 @@ It is allowed using the thrown `exception` as an argument and wrapping it in ano } ## How to fix it - -The recommended way to re-throw an exception is to use the throw statement without including an expression. This ensures that all call stack information is preserved when the exception is propagated to the caller, making debugging easier. - + +The recommended way to re-throw an exception is to use the throw statement without including an expression. This ensures that all call stack +information is preserved when the exception is propagated to the caller, making debugging easier. + ### Code examples - + #### Noncompliant code example try @@ -72,7 +78,7 @@ The recommended way to re-throw an exception is to use the throw statement witho } ## Resources - + ### Documentation - [Re-throwing an exception](https://learn.microsoft.com/en-us/dotnet/api/system.exception#re-throwing-an-exception) diff --git a/docs/description/S3447.md b/docs/description/S3447.md index 552a638..fec43aa 100644 --- a/docs/description/S3447.md +++ b/docs/description/S3447.md @@ -1,9 +1,14 @@ ## Why is this an issue? - -The use of [ref](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/ref) or [out](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/out-parameter-modifier) in combination with [Optional](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.optionalattribute) attribute is both confusing and contradictory. `[Optional]` indicates that the parameter doesn’t have to be provided, while `out` and `ref` mean that the parameter will be used to return data to the caller (`ref` additionally indicates that the parameter may also be used to pass data into the method). - -Thus, making it `[Optional]` to provide the parameter in which you will be passing back the method results doesn’t make sense. In fact, the compiler will raise an error on such code. Unfortunately, it raises the error on method calls where the `[Optional]` parameter has been omitted, not the source of the problem, the method declaration. - + +The use of [ref](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/ref) or [out](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/out-parameter-modifier) in combination with [Optional](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.optionalattribute) attribute is both confusing and +contradictory. `[Optional]` indicates that the parameter doesn’t have to be provided, while `out` and `ref` mean that +the parameter will be used to return data to the caller (`ref` additionally indicates that the parameter may also be used to pass data into +the method). + +Thus, making it `[Optional]` to provide the parameter in which you will be passing back the method results doesn’t make sense. In fact, +the compiler will raise an error on such code. Unfortunately, it raises the error on method calls where the `[Optional]` parameter has been +omitted, not the source of the problem, the method declaration. + ### Noncompliant code example class MyClass @@ -36,9 +41,9 @@ Thus, making it `[Optional]` to provide the parameter in which you will be passi } ## Resources - + ### Documentation - + - [ref keyword](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/ref) - [out parameter modifier](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/out-parameter-modifier) - [OptionalAttribute](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.optionalattribute) \ No newline at end of file diff --git a/docs/description/S3449.md b/docs/description/S3449.md index 9c0d8de..15c3b68 100644 --- a/docs/description/S3449.md +++ b/docs/description/S3449.md @@ -1,7 +1,11 @@ ## Why is this an issue? - -Numbers can be shifted with the `<<` and `>>` [operators](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-and-shift-operators#left-shift-operator-), but the right operand of the operation needs to be an `int` or a type that has an [implicit -conversion](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/conversions#102-implicit-conversions) to `int`. However, when the left operand is [dynamic](https://learn.microsoft.com/en-us/dotnet/csharp/advanced-topics/interop/using-type-dynamic), the compiler’s type checking is turned off, so you can pass anything to the right of a shift operator and have it compile. And if the argument can’t be implicitly converted to `int` at runtime, then a [RuntimeBinderException](https://learn.microsoft.com/en-us/dotnet/api/microsoft.csharp.runtimebinder.runtimebinderexception) will be raised. + +Numbers can be shifted with the `<<` and `>>` [operators](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-and-shift-operators#left-shift-operator-), +but the right operand of the operation needs to be an `int` or a type that has an [implicit +conversion](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/conversions#102-implicit-conversions) to `int`. However, when the left operand is [dynamic](https://learn.microsoft.com/en-us/dotnet/csharp/advanced-topics/interop/using-type-dynamic), the compiler’s type checking is turned +off, so you can pass anything to the right of a shift operator and have it compile. And if the argument can’t be implicitly converted to +`int` at runtime, then a [RuntimeBinderException](https://learn.microsoft.com/en-us/dotnet/api/microsoft.csharp.runtimebinder.runtimebinderexception) will be +raised. dynamic d = 5; var x = d >> 5.4; // Noncompliant @@ -9,9 +13,9 @@ conversion](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/l x <<= new object(); // Noncompliant ## Resources - + ### Documentation - + - [Shift Operators](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-and-shift-operators#left-shift-operator-) - [Implicit diff --git a/docs/description/S3450.md b/docs/description/S3450.md index 0f5dd87..a91b4ed 100644 --- a/docs/description/S3450.md +++ b/docs/description/S3450.md @@ -1,7 +1,8 @@ ## Why is this an issue? - -There is no point in providing a default value for a parameter if callers are required to provide a value for it anyway. Thus, `[DefaultParameterValue]` should always be used in conjunction with `[Optional]`. - + +There is no point in providing a default value for a parameter if callers are required to provide a value for it anyway. Thus, +`[DefaultParameterValue]` should always be used in conjunction with `[Optional]`. + ### Noncompliant code example public void MyMethod([DefaultParameterValue(5)] int j) //Noncompliant, useless diff --git a/docs/description/S3451.md b/docs/description/S3451.md index ded3af4..8ad289d 100644 --- a/docs/description/S3451.md +++ b/docs/description/S3451.md @@ -1,22 +1,28 @@ ## Why is this an issue? - -[DefaultValue](https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.defaultvalueattribute) does not make the compiler set the default value, as its name may suggest. What you probably wanted to use is [DefaultParameterValue](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.defaultparametervalueattribute). - -The [DefaultValue](https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.defaultvalueattribute) attribute from the `System.ComponentModel` namespace, is sometimes used to declare a member’s default value. This can be used, for instance, by the reset feature of a visual designer or by a code generator. + +[DefaultValue](https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.defaultvalueattribute) does not make the compiler set +the default value, as its name may suggest. What you probably wanted to use is [DefaultParameterValue](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.defaultparametervalueattribute). + +The [DefaultValue](https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.defaultvalueattribute) attribute from the +`System.ComponentModel` namespace, is sometimes used to declare a member’s default value. This can be used, for instance, by the reset +feature of a visual designer or by a code generator. public void DoStuff([DefaultValue(4)] int i) { // i is not automatically assigned 4 } -The [Optional](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.optionalattribute) attribute from the `System.Runtime.InteropServices` namespace is sometimes used to indicate that a parameter is optional, as an alternative to the language-specific construct. +The [Optional](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.optionalattribute) attribute from the +`System.Runtime.InteropServices` namespace is sometimes used to indicate that a parameter is optional, as an alternative to the +language-specific construct. public void DoStuff([Optional] int i) { // i would be assigned default(int) = 0 } -The use of `[DefaultValue]` with `[Optional]` has no more effect than `[Optional]` alone. That’s because `[DefaultValue]` doesn’t actually do anything; it merely indicates the intent for the value. +The use of `[DefaultValue]` with `[Optional]` has no more effect than `[Optional]` alone. That’s because +`[DefaultValue]` doesn’t actually do anything; it merely indicates the intent for the value. class MyClass { @@ -31,7 +37,8 @@ The use of `[DefaultValue]` with `[Optional]` has no more effect than `[Optional } } -More than likely, `[DefaultValue]` was used in confusion instead of `[DefaultParameterValue]`, the language-agnostic version of the default parameter initialization mechanism provided by C#. +More than likely, `[DefaultValue]` was used in confusion instead of `[DefaultParameterValue]`, the language-agnostic version +of the default parameter initialization mechanism provided by C#. class MyClass { @@ -51,9 +58,9 @@ Notice that you can’t use both `[DefaultParameterValue]` and default parameter void DoStuff([Optional][DefaultParameterValue(4)] int i = 5) // Error CS1745 Cannot specify default parameter value in conjunction with DefaultParameterAttribute or OptionalAttribute ## Resources - + ### Documentation - + - [OptionalAttribute Class](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.optionalattribute) - [DefaultValueAttribute Class](https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.defaultvalueattribute) - [DefaultParameterValueAttribute diff --git a/docs/description/S3453.md b/docs/description/S3453.md index 9ec8430..918d942 100644 --- a/docs/description/S3453.md +++ b/docs/description/S3453.md @@ -1,9 +1,10 @@ ## Why is this an issue? - -When a class has only a `private` constructor, it can’t be instantiated except within the class itself. Such classes can be considered [dead code](https://en.wikipedia.org/wiki/Dead_code) and should be fixed - + +When a class has only a `private` constructor, it can’t be instantiated except within the class itself. Such classes can be considered +[dead code](https://en.wikipedia.org/wiki/Dead_code) and should be fixed + ### Exceptions - + - Classes that access their private constructors ([singletons](https://en.wikipedia.org/wiki/Singleton_pattern) or [smart enums](https://learn.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/enumeration-classes-over-enum-types)) are ignored. - Classes with only `static` members are also ignored because they are covered by Rule {rule:csharpsquid:S1118}. @@ -11,9 +12,9 @@ When a class has only a `private` constructor, it can’t be instantiated except they can be instantiate through [P/Invoke](https://learn.microsoft.com/en-us/dotnet/standard/native-interop/pinvoke). ## How to fix it - + ### Code examples - + #### Noncompliant code example public class MyClass // Noncompliant: the class contains only private constructors @@ -29,7 +30,7 @@ When a class has only a `private` constructor, it can’t be instantiated except } ## Resources - + ### Documentation - {rule:csharpsquid:S1118} - Utility classes should not have public constructors diff --git a/docs/description/S3456.md b/docs/description/S3456.md index fb559b4..1adbc3c 100644 --- a/docs/description/S3456.md +++ b/docs/description/S3456.md @@ -1,14 +1,17 @@ ## Why is this an issue? - -The `string` type offers an indexer property that allows you to treat it as a `char` array. Therefore, if you just need to access a specific character or iterate over all of them, the `ToCharArray` call should be omitted. For these cases, not omitting makes the code harder to read and less efficient as `ToCharArray` copies the characters from the `string` object into a new Unicode character array. - + +The `string` type offers an indexer property that allows you to treat it as a `char` array. Therefore, if you just need to +access a specific character or iterate over all of them, the `ToCharArray` call should be omitted. For these cases, not omitting makes the +code harder to read and less efficient as `ToCharArray` copies the characters from the `string` object into a new Unicode +character array. + The same principle applies to [utf-8 literals types](https://devblogs.microsoft.com/dotnet/csharp-11-preview-updates/#utf-8-string-literals) (`ReadOnlySpan`, `Span`) and the [`ToArray`](https://learn.microsoft.com/en-us/dotnet/api/system.span-1.toarray?view=net-7.0) method. - + ## How to fix it - + ### Code examples - + #### Noncompliant code example string str = "some string"; @@ -38,9 +41,9 @@ types](https://devblogs.microsoft.com/dotnet/csharp-11-preview-updates/#utf-8-st } ## Resources - + ### Documentation - + - [String.ToCharArray Method](https://learn.microsoft.com/en-us/dotnet/api/system.string.tochararray) - [Accessing individual characters](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/strings/#accessing-individual-characters) diff --git a/docs/description/S3457.md b/docs/description/S3457.md index 4409549..3bb701a 100644 --- a/docs/description/S3457.md +++ b/docs/description/S3457.md @@ -1,11 +1,14 @@ ## Why is this an issue? - -A [composite format string]([https://learn.microsoft.com/en-us/dotnet/standard/base-types/composite-formatting](https://learn.microsoft.com/en-us/dotnet/standard/base-types/composite-formatting)) is a string that contains placeholders, represented by indices inside curly braces "{0}", "{1}", etc. These placeholders are replaced by values when the string is printed or logged. - -Because composite format strings are interpreted at runtime, rather than validated by the compiler, they can contain errors that lead to unexpected behaviors or runtime errors. - + +A [composite format string]([https://learn.microsoft.com/en-us/dotnet/standard/base-types/composite-formatting](https://learn.microsoft.com/en-us/dotnet/standard/base-types/composite-formatting)) +is a string that contains placeholders, represented by indices inside curly braces "{0}", "{1}", etc. These placeholders are replaced by values when +the string is printed or logged. + +Because composite format strings are interpreted at runtime, rather than validated by the compiler, they can contain errors that lead to unexpected +behaviors or runtime errors. + This rule validates the correspondence between arguments and composite formats when calling the following methods: - + - [`String.Format`](https://learn.microsoft.com/en-us/dotnet/api/system.string.format?view=net-7.0) - [`StringBuilder.AppendFormat`](https://learn.microsoft.com/en-us/dotnet/api/system.text.stringbuilder.appendformat?view=net-7.0) - [`Console.Write`](https://learn.microsoft.com/en-us/dotnet/api/system.console.write?view=net-7.0) @@ -33,13 +36,14 @@ This rule validates the correspondence between arguments and composite formats w - This rule doesn’t check whether the format specifier (defined after the `:`) is actually valid. ## How to fix it - -A composite format string contains placeholders, replaced by values when the string is printed or logged. Mismatch in the format specifiers and the arguments provided can lead to incorrect strings being created. - + +A composite format string contains placeholders, replaced by values when the string is printed or logged. Mismatch in the format specifiers and the +arguments provided can lead to incorrect strings being created. + To avoid issues, a developer should ensure that the provided arguments match format specifiers. - + Moreover, use [string interpolation](https://learn.microsoft.com/en-us/dotnet/csharp/tutorials/string-interpolation) when possible. - + Instead of string str = string.Format("Hello {0} {1}!", firstName, lastName); @@ -54,7 +58,7 @@ With string interpolation: - modern code editors provide auto-completion when typing the interpolation expression ### Code examples - + #### Noncompliant code example s = string.Format("{0}", arg0, arg1); // Noncompliant, arg1 is declared but not used. diff --git a/docs/description/S3458.md b/docs/description/S3458.md index 5007bed..a7b7b93 100644 --- a/docs/description/S3458.md +++ b/docs/description/S3458.md @@ -1,7 +1,8 @@ ## Why is this an issue? - -Empty `case` clauses that fall through to the default are useless. Whether or not such a `case` is present, the `default` clause will be invoked. Such `case`s simply clutter the code, and should be removed. - + +Empty `case` clauses that fall through to the default are useless. Whether or not such a `case` is present, the +`default` clause will be invoked. Such `case`s simply clutter the code, and should be removed. + ### Noncompliant code example switch(ch) diff --git a/docs/description/S3459.md b/docs/description/S3459.md index f246e49..65894f1 100644 --- a/docs/description/S3459.md +++ b/docs/description/S3459.md @@ -1,7 +1,8 @@ ## Why is this an issue? - -Fields and auto-properties that are never assigned to hold the default values for their types. They are either pointless code or, more likely, mistakes. - + +Fields and auto-properties that are never assigned to hold the default values for their types. They are either pointless code or, more likely, +mistakes. + ### Noncompliant code example class MyClass @@ -30,5 +31,5 @@ Fields and auto-properties that are never assigned to hold the default values fo } ### Exceptions - + - Fields on types decorated with `System.SerializableAttribute` attribute. \ No newline at end of file diff --git a/docs/description/S3464.md b/docs/description/S3464.md index 37ebae9..94c7387 100644 --- a/docs/description/S3464.md +++ b/docs/description/S3464.md @@ -1,7 +1,8 @@ ## Why is this an issue? - -[Recursion](https://en.wikipedia.org/wiki/Recursion) is a technique used to define a problem in terms of the problem itself, usually in terms of a simpler version of the problem itself. - + +[Recursion](https://en.wikipedia.org/wiki/Recursion) is a technique used to define a problem in terms of the problem itself, usually in +terms of a simpler version of the problem itself. + For example, the implementation of the generator for the n-th value of the [Fibonacci sequence](https://en.wikipedia.org/wiki/Fibonacci_sequence) comes naturally from its mathematical definition, when recursion is used: @@ -69,9 +70,9 @@ In more complex scenarios, however, the code will compile but execution will res var c2 = new C2(); // This would result into a TypeLoadException ## Resources - + ### Documentation - + - [Recursion](https://en.wikipedia.org/wiki/Recursion_%28computer_science%29) - [TypeLoadException](https://learn.microsoft.com/en-us/dotnet/api/system.typeloadexception) diff --git a/docs/description/S3466.md b/docs/description/S3466.md index 46a4ac1..de08ccb 100644 --- a/docs/description/S3466.md +++ b/docs/description/S3466.md @@ -1,11 +1,12 @@ ## Why is this an issue? - -When optional parameter values are not passed to base method calls, the value passed in by the caller is ignored. This can cause the function to behave differently than expected, leading to errors and making the code difficult to debug. - + +When optional parameter values are not passed to base method calls, the value passed in by the caller is ignored. This can cause the function to +behave differently than expected, leading to errors and making the code difficult to debug. + ## How to fix it - + ### Code examples - + #### Noncompliant code example public class BaseClass @@ -57,8 +58,8 @@ When optional parameter values are not passed to base method calls, the value pa } ## Resources - + ### Documentation - + Microsoft Learn - [Optional Arguments](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/named-and-optional-arguments#optional-arguments) \ No newline at end of file diff --git a/docs/description/S3532.md b/docs/description/S3532.md index 2708b22..58b31aa 100644 --- a/docs/description/S3532.md +++ b/docs/description/S3532.md @@ -1,7 +1,7 @@ ## Why is this an issue? - + The `default` clause should take appropriate action. Having an empty `default` is a waste of keystrokes. - + ### Noncompliant code example enum Fruit @@ -57,5 +57,6 @@ or } ### Exceptions - -`default` clauses containing only a comment are ignored with the assumption that they are empty on purpose and the comment documents why. \ No newline at end of file + +`default` clauses containing only a comment are ignored with the assumption that they are empty on purpose and the comment documents +why. \ No newline at end of file diff --git a/docs/description/S3597.md b/docs/description/S3597.md index 5bf42eb..4c0a9d9 100644 --- a/docs/description/S3597.md +++ b/docs/description/S3597.md @@ -1,7 +1,12 @@ ## Why is this an issue? - -The `ServiceContract` attribute specifies that a class or interface defines the communication contract of a Windows Communication Foundation (WCF) service. The service operations of this class or interface are defined by `OperationContract` attributes added to methods. It doesn’t make sense to define a contract without any service operations; thus, in a `ServiceContract` class or interface at least one method should be annotated with `OperationContract`. Similarly, WCF only serves `OperationContract` methods that are defined inside `ServiceContract` classes or interfaces; thus, this rule also checks that `ServiceContract` is added to the containing type of `OperationContract` methods. - + +The `ServiceContract` attribute specifies that a class or interface defines the communication contract of a Windows Communication +Foundation (WCF) service. The service operations of this class or interface are defined by `OperationContract` attributes added to methods. +It doesn’t make sense to define a contract without any service operations; thus, in a `ServiceContract` class or interface at least one +method should be annotated with `OperationContract`. Similarly, WCF only serves `OperationContract` methods that are defined +inside `ServiceContract` classes or interfaces; thus, this rule also checks that `ServiceContract` is added to the containing +type of `OperationContract` methods. + ### Noncompliant code example [ServiceContract] diff --git a/docs/description/S3598.md b/docs/description/S3598.md index b7c97ad..3b1217d 100644 --- a/docs/description/S3598.md +++ b/docs/description/S3598.md @@ -1,15 +1,19 @@ ## Why is this an issue? - -When declaring a Windows Communication Foundation (WCF) [`OperationContract`](https://learn.microsoft.com/en-us/dotnet/api/system.servicemodel.operationcontractattribute?view=dotnet-plat-ext-7.0) method as [`one-way`](https://learn.microsoft.com/en-us/dotnet/api/system.servicemodel.operationcontractattribute.isoneway?view=dotnet-plat-ext-7.0), that service method won’t return any result, not even an underlying empty confirmation message. These are fire-and-forget methods that are useful in event-like communication. Therefore, specifying a return type has no effect and can confuse readers. - + +When declaring a Windows Communication Foundation (WCF) [`OperationContract`](https://learn.microsoft.com/en-us/dotnet/api/system.servicemodel.operationcontractattribute?view=dotnet-plat-ext-7.0) +method as [`one-way`](https://learn.microsoft.com/en-us/dotnet/api/system.servicemodel.operationcontractattribute.isoneway?view=dotnet-plat-ext-7.0), +that service method won’t return any result, not even an underlying empty confirmation message. These are fire-and-forget methods that are useful in +event-like communication. Therefore, specifying a return type has no effect and can confuse readers. + ### Exceptions - -The rule doesn’t report if [`OperationContractAttribute.AsyncPattern`](https://learn.microsoft.com/en-us/dotnet/api/system.servicemodel.operationcontractattribute.asyncpattern) is set to `true`. - + +The rule doesn’t report if [`OperationContractAttribute.AsyncPattern`](https://learn.microsoft.com/en-us/dotnet/api/system.servicemodel.operationcontractattribute.asyncpattern) +is set to `true`. + ## How to fix it - + ### Code examples - + #### Noncompliant code example [ServiceContract] @@ -29,7 +33,7 @@ The rule doesn’t report if [`OperationContractAttribute.AsyncPattern`](https:/ } ## Resources - + ### Documentation - + Microsoft Learn - [OperationContractAttribute](https://learn.microsoft.com/en-us/dotnet/api/system.servicemodel.operationcontractattribute) \ No newline at end of file diff --git a/docs/description/S3600.md b/docs/description/S3600.md index 5d2b8b7..928a89e 100644 --- a/docs/description/S3600.md +++ b/docs/description/S3600.md @@ -1,7 +1,8 @@ ## Why is this an issue? - -Adding [params](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/params) to a method override has no effect. The compiler accepts it, but the callers won’t be able to benefit from the added modifier. - + +Adding [params](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/params) to a method override has no effect. +The compiler accepts it, but the callers won’t be able to benefit from the added modifier. + ### Noncompliant code example class Base @@ -37,7 +38,7 @@ Adding [params](https://learn.microsoft.com/en-us/dotnet/csharp/language-referen } ## Resources - + ### Documentation - + - [params keyword](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/params) \ No newline at end of file diff --git a/docs/description/S3603.md b/docs/description/S3603.md index da079a0..4a30676 100644 --- a/docs/description/S3603.md +++ b/docs/description/S3603.md @@ -1,13 +1,15 @@ ## Why is this an issue? - -Marking a method with the [`Pure`](https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.contracts.pureattribute) attribute indicates that the method doesn’t make any visible state changes. Therefore, a `Pure` method should return a result. Otherwise, it indicates a no-operation call. - + +Marking a method with the [`Pure`](https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.contracts.pureattribute) +attribute indicates that the method doesn’t make any visible state changes. Therefore, a `Pure` method should return a result. Otherwise, +it indicates a no-operation call. + Using `Pure` on a `void` method is either by mistake or the method is not doing a meaningful task. - + ## How to fix it - + ### Code examples - + #### Noncompliant code example class Person @@ -30,7 +32,7 @@ Using `Pure` on a `void` method is either by mistake or the method is not doing } ## Resources - + ### Documentation - + - Microsoft Learn - [PureAttribute Class](https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.contracts.pureattribute) \ No newline at end of file diff --git a/docs/description/S3604.md b/docs/description/S3604.md index 14515e7..f5ca1f9 100644 --- a/docs/description/S3604.md +++ b/docs/description/S3604.md @@ -1,7 +1,8 @@ ## Why is this an issue? - -Fields, properties and events can be initialized either inline or in the constructor. Initializing them inline and in the constructor at the same time is redundant; the inline initialization will be overridden. - + +Fields, properties and events can be initialized either inline or in the constructor. Initializing them inline and in the constructor at the same +time is redundant; the inline initialization will be overridden. + ### Noncompliant code example class Person @@ -25,5 +26,6 @@ Fields, properties and events can be initialized either inline or in the constru } ### Exceptions - -This rule doesn’t report an issue if not all constructors initialize the field. If the field is initialized inline to its default value, then {rule:csharpsquid:S3052} already reports an issue on the initialization. \ No newline at end of file + +This rule doesn’t report an issue if not all constructors initialize the field. If the field is initialized inline to its default value, then +{rule:csharpsquid:S3052} already reports an issue on the initialization. \ No newline at end of file diff --git a/docs/description/S3610.md b/docs/description/S3610.md index 4efc138..137fd04 100644 --- a/docs/description/S3610.md +++ b/docs/description/S3610.md @@ -1,11 +1,14 @@ ## Why is this an issue? - -Calling [GetType()](https://learn.microsoft.com/en-us/dotnet/api/system.object.gettype) on a [nullable value type](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/nullable-value-types) object returns the underlying value type. Therefore, comparing the returned [`Type`](https://learn.microsoft.com/en-us/dotnet/api/system.type) object to `typeof(Nullable)` will either throw an [NullReferenceException](https://learn.microsoft.com/en-us/dotnet/api/system.nullreferenceexception) or the result will always be `true` or `false` and can be known at compile time. - + +Calling [GetType()](https://learn.microsoft.com/en-us/dotnet/api/system.object.gettype) on a [nullable value type](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/nullable-value-types) object returns +the underlying value type. Therefore, comparing the returned [`Type`](https://learn.microsoft.com/en-us/dotnet/api/system.type) +object to `typeof(Nullable)` will either throw an [NullReferenceException](https://learn.microsoft.com/en-us/dotnet/api/system.nullreferenceexception) or the result will always be +`true` or `false` and can be known at compile time. + ## How to fix it - + ### Code examples - + #### Noncompliant code example void DoChecks(Nullable value) where T : struct @@ -29,9 +32,9 @@ Calling [GetType()](https://learn.microsoft.com/en-us/dotnet/api/system.object.g } ## Resources - + ### Documentation - + - Microsoft Learn - [Object.GetType Method](https://learn.microsoft.com/en-us/dotnet/api/system.object.gettype) - Microsoft Learn - [Nullable value types (C# reference)](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/nullable-value-types) diff --git a/docs/description/S3626.md b/docs/description/S3626.md index 71d23ad..db698e5 100644 --- a/docs/description/S3626.md +++ b/docs/description/S3626.md @@ -1,7 +1,8 @@ ## Why is this an issue? - -Jump statements, such as `return`, `yield break`, `goto`, and `continue` let you change the default flow of program execution, but jump statements that direct the control flow to the original direction are just a waste of keystrokes. - + +Jump statements, such as `return`, `yield break`, `goto`, and `continue` let you change the default +flow of program execution, but jump statements that direct the control flow to the original direction are just a waste of keystrokes. + ### Noncompliant code example void Foo() diff --git a/docs/description/S3655.md b/docs/description/S3655.md index 6d12d1d..a02d98d 100644 --- a/docs/description/S3655.md +++ b/docs/description/S3655.md @@ -1,13 +1,15 @@ ## Why is this an issue? - + [Nullable value types](https://learn.microsoft.com/en-us/dotnet/api/system.nullable-1) can hold either a value or `null`. - -The value held in the nullable type can be accessed with the `Value` property or by casting it to the underlying type. Still, both operations throw an `InvalidOperationException` when the value is `null`. A nullable type should always be tested before accessing the value to avoid raising exceptions. - + +The value held in the nullable type can be accessed with the `Value` property or by casting it to the underlying type. Still, both +operations throw an `InvalidOperationException` when the value is `null`. A nullable type should always be tested before +accessing the value to avoid raising exceptions. + ## How to fix it - + ### Code examples - + #### Noncompliant code example void Sample(bool condition) @@ -37,8 +39,8 @@ The value held in the nullable type can be accessed with the `Value` property or } ## Resources - + ### Documentation - + - [Nullable<T>](https://learn.microsoft.com/en-us/dotnet/api/system.nullable-1) - CWE - [CWE-476 - NULL Pointer Dereference](https://cwe.mitre.org/data/definitions/476) \ No newline at end of file diff --git a/docs/description/S3717.md b/docs/description/S3717.md index 5b5eae2..8f6ebaa 100644 --- a/docs/description/S3717.md +++ b/docs/description/S3717.md @@ -1,9 +1,11 @@ ## Why is this an issue? - -`NotImplementedException` is often used to mark methods which must be implemented for the overall functionality to be complete, but which the developer wants to implement later. That’s as opposed to the `NotSupportedException` which is thrown by methods which are required by base classes or interfaces, but which are not appropriate to the current class. - + +`NotImplementedException` is often used to mark methods which must be implemented for the overall functionality to be complete, but +which the developer wants to implement later. That’s as opposed to the `NotSupportedException` which is thrown by methods which are +required by base classes or interfaces, but which are not appropriate to the current class. + This rule raises an exception when `NotImplementedException` is thrown. - + ### Noncompliant code example void doTheThing() @@ -12,5 +14,5 @@ This rule raises an exception when `NotImplementedException` is thrown. } ### Exceptions - + Exceptions derived from `NotImplementedException` are ignored. \ No newline at end of file diff --git a/docs/description/S3776.md b/docs/description/S3776.md index 122a396..41661c5 100644 --- a/docs/description/S3776.md +++ b/docs/description/S3776.md @@ -1,15 +1,16 @@ This rule raises an issue when the code cognitive complexity of a function is above a certain threshold. - + ## Why is this an issue? - -Cognitive Complexity is a measure of how hard it is to understand the control flow of a unit of code. Code with high cognitive complexity is hard to read, understand, test, and modify. - + +Cognitive Complexity is a measure of how hard it is to understand the control flow of a unit of code. Code with high cognitive complexity is hard +to read, understand, test, and modify. + As a rule of thumb, high cognitive complexity is a sign that the code should be refactored into smaller, easier-to-manage pieces. - + ### Which syntax in code does impact cognitive complexity score? - + Here are the core concepts: - + - **Cognitive complexity is incremented each time the code breaks the normal linear reading flow.** This concerns, for example, loop structures, conditionals, catches, switches, jumps to labels, and conditions mixing multiple operators. @@ -23,13 +24,14 @@ Here are the core concepts: apply to recursive calls, those will increment cognitive score. The method of computation is fully detailed in the pdf linked in the resources. - + ### What is the potential impact? - -Developers spend more time reading and understanding code than writing it. High cognitive complexity slows down changes and increases the cost of maintenance. - + +Developers spend more time reading and understanding code than writing it. High cognitive complexity slows down changes and increases the cost of +maintenance. + ## How to fix it - + Reducing cognitive complexity can be challenging. Here are a few suggestions: @@ -47,11 +49,11 @@ Reducing cognitive complexity can be challenging. replaces multiple tests and simplifies the flow. ### Code examples - + **Extraction of a complex condition in a new function.** - + #### Noncompliant code example - + The code is using a complex condition and has a cognitive cost of 3. decimal CalculateFinalPrice(User user, Cart cart) @@ -70,8 +72,9 @@ The code is using a complex condition and has a cognitive cost of 3. } #### Compliant solution - -Even if the cognitive complexity of the whole program did not change, it is easier for a reader to understand the code of the `calculateFinalPrice` function, which now only has a cognitive cost of 1. + +Even if the cognitive complexity of the whole program did not change, it is easier for a reader to understand the code of the +`calculateFinalPrice` function, which now only has a cognitive cost of 1. decimal CalculateFinalPrice(User user, Cart cart) { @@ -93,11 +96,12 @@ Even if the cognitive complexity of the whole program did not change, it is easi } **Break down large functions.** - + #### Noncompliant code example - + For example, consider a function that calculates the total price of a shopping cart, including sales tax and shipping. - *Note:* The code is simplified here, to illustrate the purpose. Please imagine there is more happening in the `foreach` loops. + *Note:* The code +is simplified here, to illustrate the purpose. Please imagine there is more happening in the `foreach` loops. decimal CalculateTotal(Cart cart) { @@ -119,8 +123,9 @@ For example, consider a function that calculates the total price of a shopping c return total; } -This function could be refactored into smaller functions: The complexity is spread over multiple functions and the complex `CalculateTotal` has now a complexity score of zero. - +This function could be refactored into smaller functions: The complexity is spread over multiple functions and the complex +`CalculateTotal` has now a complexity score of zero. + #### Compliant solution decimal CalculateTotal(Cart cart) @@ -159,9 +164,9 @@ This function could be refactored into smaller functions: The complexity is spre } **Avoid deep nesting by returning early.** - + #### Noncompliant code example - + The below code has a cognitive complexity of 6. decimal CalculateDiscount(decimal price, User user) @@ -188,7 +193,7 @@ The below code has a cognitive complexity of 6. } #### Compliant solution - + Checking for the edge case first flattens the `if` statements and reduces the cognitive complexity to 3. decimal CalculateDiscount(decimal price, User user) @@ -212,9 +217,10 @@ Checking for the edge case first flattens the `if` statements and reduces the co } **Use the null-conditional operator to access data.** - -In the below code, the cognitive complexity is increased due to the multiple checks required to access the manufacturer’s name. This can be simplified using the optional chaining operator. - + +In the below code, the cognitive complexity is increased due to the multiple checks required to access the manufacturer’s name. This can be +simplified using the optional chaining operator. + #### Noncompliant code example string GetManufacturerName(Product product) @@ -235,8 +241,9 @@ In the below code, the cognitive complexity is increased due to the multiple che } #### Compliant solution - -The optional chaining operator will return `null` if any reference in the chain is `null`, avoiding multiple checks. The `??` operator allows to provide the default value to use. + +The optional chaining operator will return `null` if any reference in the chain is `null`, avoiding multiple checks. The +`??` operator allows to provide the default value to use. string GetManufacturerName(Product product) { @@ -244,11 +251,11 @@ The optional chaining operator will return `null` if any reference in the chain } ### Pitfalls - + As this code is complex, ensure that you have unit tests that cover the code before refactoring. - + ## Resources - + ### Documentation - Sonar - [Cognitive Complexity](https://www.sonarsource.com/docs/CognitiveComplexity.pdf) diff --git a/docs/description/S3869.md b/docs/description/S3869.md index 788e994..e03ddc5 100644 --- a/docs/description/S3869.md +++ b/docs/description/S3869.md @@ -1,11 +1,15 @@ ## Why is this an issue? - -The `SafeHandle.DangerousGetHandle` method poses significant risks and should be used carefully. This method carries the inherent danger of potentially returning an invalid handle, which can result in resource leaks and security vulnerabilities. Although it is technically possible to utilize this method without encountering issues, doing so correctly requires a high level of expertise. Therefore, it is recommended to avoid using this method altogether. - + +The `SafeHandle.DangerousGetHandle` method poses significant risks and should be used carefully. This method carries the inherent danger +of potentially returning an invalid handle, which can result in resource leaks and security vulnerabilities. Although it is technically possible to +utilize this method without encountering issues, doing so correctly requires a high level of expertise. Therefore, it is recommended to avoid using +this method altogether. + ### What is the potential impact? - -The `SafeHandle.DangerousGetHandle` method is potentially prone to leaks and vulnerabilities due to its nature and usage. Here are a few reasons why: - + +The `SafeHandle.DangerousGetHandle` method is potentially prone to leaks and vulnerabilities due to its nature and usage. Here are a few +reasons why: + - **Invalid handles**: the method retrieves the raw handle value without performing any validation or safety checks. This means that the method can return a handle that is no longer valid or has been closed, leading to undefined behavior or errors when attempting to use it. - **Resource leaks**: by directly accessing the handle without the proper safeguards and cleanup provided by the @@ -21,7 +25,7 @@ The `SafeHandle.DangerousGetHandle` method is potentially prone to leaks and vul } ## Resources - + ### Documentation - [SafeHandle.DangerousGetHandle diff --git a/docs/description/S3871.md b/docs/description/S3871.md index d7665bd..d02e775 100644 --- a/docs/description/S3871.md +++ b/docs/description/S3871.md @@ -1,19 +1,21 @@ ## Why is this an issue? - -The point of having custom exception types is to convey more information than is available in standard types. But custom exception types must be `public` for that to work. - -If a method throws a non-public exception, the best you can do on the caller’s side is to `catch` the closest `public` base of the class. However, you lose all the information that the new exception type carries. - + +The point of having custom exception types is to convey more information than is available in standard types. But custom exception types must be +`public` for that to work. + +If a method throws a non-public exception, the best you can do on the caller’s side is to `catch` the closest `public` base +of the class. However, you lose all the information that the new exception type carries. + This rule will raise an issue if you directly inherit one of the following exception types in a non-public class: - + - [Exception](https://learn.microsoft.com/en-us/dotnet/api/system.exception) - [SystemException](https://learn.microsoft.com/en-us/dotnet/api/system.systemexception) - [ApplicationException](https://learn.microsoft.com/en-us/dotnet/api/system.applicationexception) ## How to fix it - + ### Code examples - + #### Noncompliant code example internal class MyException : Exception // Noncompliant @@ -29,7 +31,7 @@ This rule will raise an issue if you directly inherit one of the following excep } ## Resources - + ### Documentation - OWASP - [Top 10 2017 Category A10 - diff --git a/docs/description/S3872.md b/docs/description/S3872.md index f75f92c..1495f85 100644 --- a/docs/description/S3872.md +++ b/docs/description/S3872.md @@ -1,7 +1,9 @@ ## Why is this an issue? - -The name of a method should communicate what it does, and the names of its parameters should indicate how they’re used. If a method and its parameter have the same name it is an indication that one of these rules of thumb has been broken, if not both. Even if by some trick of language that’s not the case, it is still likely to confuse callers and maintainers. - + +The name of a method should communicate what it does, and the names of its parameters should indicate how they’re used. If a method and its +parameter have the same name it is an indication that one of these rules of thumb has been broken, if not both. Even if by some trick of language +that’s not the case, it is still likely to confuse callers and maintainers. + ### Noncompliant code example public void Login(string login) // Noncompliant diff --git a/docs/description/S3874.md b/docs/description/S3874.md index fa2a7db..fcd990d 100644 --- a/docs/description/S3874.md +++ b/docs/description/S3874.md @@ -1,9 +1,13 @@ ## Why is this an issue? - -Passing a parameter by reference, which is what happens when you use the `out` or `ref` parameter modifiers, means that the method will receive a pointer to the argument, rather than the argument itself. If the argument was a value type, the method will be able to change the argument’s values. If it was a reference type, then the method receives a pointer to a pointer, which is usually not what was intended. Even when it is what was intended, this is the sort of thing that’s difficult to get right, and should be used with caution. - -This rule raises an issue when `out` or `ref` is used on a non-`Optional` parameter in a public method. `Optional` parameters are covered by {rule:csharpsquid:S3447}. - + +Passing a parameter by reference, which is what happens when you use the `out` or `ref` parameter modifiers, means that the +method will receive a pointer to the argument, rather than the argument itself. If the argument was a value type, the method will be able to change +the argument’s values. If it was a reference type, then the method receives a pointer to a pointer, which is usually not what was intended. Even when +it is what was intended, this is the sort of thing that’s difficult to get right, and should be used with caution. + +This rule raises an issue when `out` or `ref` is used on a non-`Optional` parameter in a public method. +`Optional` parameters are covered by {rule:csharpsquid:S3447}. + ### Noncompliant code example public void GetReply( @@ -26,9 +30,9 @@ This rule raises an issue when `out` or `ref` is used on a non-`Optional` parame { ... } ### Exceptions - + This rule will not raise issues for: - + - non-public methods - methods with only 'out' parameters, name starting with "Try" and return type bool. - interface implementation methods \ No newline at end of file diff --git a/docs/description/S3875.md b/docs/description/S3875.md index 723450b..90c1b19 100644 --- a/docs/description/S3875.md +++ b/docs/description/S3875.md @@ -1,6 +1,8 @@ ## Why is this an issue? - -The use of `==` to compare two objects is expected to do a reference comparison. That is, it is expected to return `true` if and only if they are the same object instance. Overloading the operator to do anything else will inevitably lead to the introduction of bugs by callers. + +The use of `==` to compare two objects is expected to do a reference comparison. That is, it is expected to return `true` if +and only if they are the same object instance. Overloading the operator to do anything else will inevitably lead to the introduction of bugs by +callers. public static bool operator ==(MyType x, MyType y) // Noncompliant: confusing for the caller { @@ -20,13 +22,13 @@ On the other hand, overloading it to do exactly that is pointless; that’s what } ### Exceptions - + - Classes with overloaded `operator +` or `operator -` are ignored. - Classes that implement `IComparable` or `IEquatable` most probably behave as value-type objects and are ignored. ## Resources - + ### Documentation - [Reference types](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/reference-types) diff --git a/docs/description/S3876.md b/docs/description/S3876.md index 14a0066..012e6ae 100644 --- a/docs/description/S3876.md +++ b/docs/description/S3876.md @@ -1,7 +1,8 @@ ## Why is this an issue? - -Strings and integral types are typically used as indexers. When some other type is required, it typically indicates design problems, and potentially a situation where a method should be used instead. - + +Strings and integral types are typically used as indexers. When some other type is required, it typically indicates design problems, and +potentially a situation where a method should be used instead. + ### Noncompliant code example public int this[MyCustomClass index] // Noncompliant diff --git a/docs/description/S3877.md b/docs/description/S3877.md index 54c8237..158b653 100644 --- a/docs/description/S3877.md +++ b/docs/description/S3877.md @@ -1,6 +1,7 @@ ## Why is this an issue? - -The rule is reporting when an exception is thrown from certain methods and constructors. These methods are expected to behave in a specific way and throwing an exception from them can lead to unexpected behavior and break the calling code. + +The rule is reporting when an exception is thrown from certain methods and constructors. These methods are expected to behave in a specific way and +throwing an exception from them can lead to unexpected behavior and break the calling code. public override string ToString() { @@ -12,7 +13,7 @@ The rule is reporting when an exception is thrown from certain methods and const } An issue is raised when an exception is thrown from any of the following: - + - [ToString](https://learn.microsoft.com/en-us/dotnet/api/system.object.tostring) - [Object.Equals](https://learn.microsoft.com/en-us/dotnet/api/system.object.equals) - [IEquatable.Equals](https://learn.microsoft.com/en-us/dotnet/api/system.iequatable-1.equals) @@ -26,7 +27,7 @@ An issue is raised when an exception is thrown from any of the following: operators](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/user-defined-conversion-operators) ### Exceptions - + Certain exceptions will be ignored in specific contexts, thus not raising the issue: - `System.NotImplementedException` and its derivatives are ignored for all the aforementioned. @@ -34,7 +35,7 @@ Certain exceptions will be ignored in specific contexts, thus not raising the is derivatives are ignored in event accessors. ## Resources - + ### Documentation - [Exceptions and Exception Handling](https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/exceptions/) diff --git a/docs/description/S3878.md b/docs/description/S3878.md index 5db3cf4..0d35aac 100644 --- a/docs/description/S3878.md +++ b/docs/description/S3878.md @@ -1,7 +1,8 @@ ## Why is this an issue? - -There’s no point in creating an array solely for the purpose of passing it to a `params` parameter. Simply pass the elements directly. They will be consolidated into an array automatically. - + +There’s no point in creating an array solely for the purpose of passing it to a `params` parameter. Simply pass the elements directly. +They will be consolidated into an array automatically. + ### Noncompliant code example public void Base() diff --git a/docs/description/S3880.md b/docs/description/S3880.md index 4d4ba95..4b102d8 100644 --- a/docs/description/S3880.md +++ b/docs/description/S3880.md @@ -1,7 +1,8 @@ ## Why is this an issue? - -Finalizers come with a performance cost due to the overhead of tracking the life cycle of objects. An empty one is consequently costly with no benefit or justification. - + +Finalizers come with a performance cost due to the overhead of tracking the life cycle of objects. An empty one is consequently costly with no +benefit or justification. + ### Noncompliant code example public class Foo diff --git a/docs/description/S3881.md b/docs/description/S3881.md index 7d45be3..25ec42f 100644 --- a/docs/description/S3881.md +++ b/docs/description/S3881.md @@ -1,11 +1,12 @@ ## Why is this an issue? - -The `IDisposable` interface is a mechanism to release unmanaged resources, if not implemented correctly this could result in resource leaks or more severe bugs. - + +The `IDisposable` interface is a mechanism to release unmanaged resources, if not implemented correctly this could result in resource +leaks or more severe bugs. + This rule raises an issue when the recommended dispose pattern, as defined by Microsoft, is not adhered to. See the **CompliantSolution** section for examples. - + Satisfying the rule’s conditions will enable potential derived classes to correctly dispose the members of your class: - + - `sealed` classes are not checked. - If a base class implements `IDisposable` your class should not have `IDisposable` in the list of its interfaces. In such cases it is recommended to override the base class’s `protected virtual void Dispose(bool)` method or its equivalent. @@ -121,7 +122,7 @@ Satisfying the rule’s conditions will enable potential derived classes to corr } ## Resources - + Refer to - [MSDN](https://msdn.microsoft.com/en-us/library/498928w2.aspx) for complete documentation on the dispose pattern. diff --git a/docs/description/S3884.md b/docs/description/S3884.md index 557b09c..73559e2 100644 --- a/docs/description/S3884.md +++ b/docs/description/S3884.md @@ -1,11 +1,14 @@ This rule is deprecated, and will eventually be removed. - + ## Why is this an issue? - -`CoSetProxyBlanket` and `CoInitializeSecurity` both work to set the permissions context in which the process invoked immediately after is executed. Calling them from within that process is useless because it’s too late at that point; the permissions context has already been set. - -Specifically, these methods are meant to be called from non-managed code such as a C++ wrapper that then invokes the managed, i.e. C# or VB.NET, code. - + +`CoSetProxyBlanket` and `CoInitializeSecurity` both work to set the permissions context in which the process invoked +immediately after is executed. Calling them from within that process is useless because it’s too late at that point; the permissions context has +already been set. + +Specifically, these methods are meant to be called from non-managed code such as a C++ wrapper that then invokes the managed, i.e. C# or VB.NET, +code. + ### Noncompliant code example [DllImport("ole32.dll")] @@ -32,7 +35,7 @@ Specifically, these methods are meant to be called from non-managed code such as } ## Resources - + - OWASP - [Top 10 2021 Category A1 - Broken Access Control](https://owasp.org/Top10/A01_2021-Broken_Access_Control/) - OWASP - [Top 10 2017 Category A6 - Security Misconfiguration](https://owasp.org/www-project-top-ten/2017/A6_2017-Security_Misconfiguration) diff --git a/docs/description/S3885.md b/docs/description/S3885.md index 6b70eda..d2724cc 100644 --- a/docs/description/S3885.md +++ b/docs/description/S3885.md @@ -1,9 +1,11 @@ ## Why is this an issue? - -The parameter to `Assembly.Load` includes the full specification of the dll to be loaded. Use another method, and you might end up with a dll other than the one you expected. - -This rule raises an issue when `Assembly.LoadFrom`, `Assembly.LoadFile`, or `Assembly.LoadWithPartialName` is called. - + +The parameter to `Assembly.Load` includes the full specification of the dll to be loaded. Use another method, and you might end up with +a dll other than the one you expected. + +This rule raises an issue when `Assembly.LoadFrom`, `Assembly.LoadFile`, or `Assembly.LoadWithPartialName` is +called. + ### Noncompliant code example static void Main(string[] args) diff --git a/docs/description/S3887.md b/docs/description/S3887.md index 3664de9..c0799fa 100644 --- a/docs/description/S3887.md +++ b/docs/description/S3887.md @@ -1,15 +1,20 @@ ## Why is this an issue? - -Using the [`readonly` keyword](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/readonly) on a field means it can’t be changed after initialization. However, that’s only partly true when applied to collections or arrays. The `readonly` keyword enforces that another instance can’t be assigned to the field, but it cannot keep the contents from being updated. In practice, the field value can be changed, and the use of `readonly` on such a field is misleading, and you’re likely not getting the behavior you expect. - + +Using the [`readonly` keyword](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/readonly) on a +field means it can’t be changed after initialization. However, that’s only partly true when applied to collections or arrays. The +`readonly` keyword enforces that another instance can’t be assigned to the field, but it cannot keep the contents from being updated. In +practice, the field value can be changed, and the use of `readonly` on such a field is misleading, and you’re likely not getting the +behavior you expect. + This rule raises an issue when a non-private, `readonly` field is an array or collection. - + ## How to fix it - -To fix this, you should either use an [immutable](https://learn.microsoft.com/en-us/dotnet/api/system.collections.immutable) or [frozen](https://learn.microsoft.com/en-us/dotnet/api/system.collections.frozen) collection or remove the `readonly` modifier to clarify the behavior. - + +To fix this, you should either use an [immutable](https://learn.microsoft.com/en-us/dotnet/api/system.collections.immutable) or [frozen](https://learn.microsoft.com/en-us/dotnet/api/system.collections.frozen) collection or remove the `readonly` modifier to +clarify the behavior. + ### Code examples - + #### Noncompliant code example public class MyClass @@ -32,7 +37,7 @@ To fix this, you should either use an [immutable](https://learn.microsoft.com/en } ## Resources - + ### Documentation - + - Microsoft Learn - [readonly (C# Reference)](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/readonly) \ No newline at end of file diff --git a/docs/description/S3889.md b/docs/description/S3889.md index 4a1990f..316f7b7 100644 --- a/docs/description/S3889.md +++ b/docs/description/S3889.md @@ -1,16 +1,18 @@ ## Why is this an issue? - -`Thread.Suspend` and `Thread.Resume` can give unpredictable results, and both methods have been deprecated. Indeed, if `Thread.Suspend` is not used very carefully, a [thread](https://en.wikipedia.org/wiki/Thread_%28computing%29) can be suspended while holding a [lock](https://en.wikipedia.org/wiki/Lock_%28computer_science%29), thus leading to a [deadlock](https://en.wikipedia.org/wiki/Deadlock). - + +`Thread.Suspend` and `Thread.Resume` can give unpredictable results, and both methods have been deprecated. Indeed, if +`Thread.Suspend` is not used very carefully, a [thread](https://en.wikipedia.org/wiki/Thread_%28computing%29) can be suspended while +holding a [lock](https://en.wikipedia.org/wiki/Lock_%28computer_science%29), thus leading to a [deadlock](https://en.wikipedia.org/wiki/Deadlock). + There are other synchronization mechanisms that are safer and should be used instead, such as: - + - `Monitor` provides a mechanism that synchronizes access to objects. - `Mutex` provides a mechanism that synchronizes interprocess access to a protected resource. - `Semaphore` provides a mechanism that allows limiting the number of threads that have access to a protected resources concurrently. - `Events` enable a class to notify others when something of interest occurs. ## Resources - + ### Documentation - [Thread.Resume Method](https://msdn.microsoft.com/en-us/library/system.threading.thread.resume.aspx) diff --git a/docs/description/S3897.md b/docs/description/S3897.md index e46c668..d94bb4b 100644 --- a/docs/description/S3897.md +++ b/docs/description/S3897.md @@ -1,9 +1,11 @@ ## Why is this an issue? - -The `IEquatable` interface has only one method in it: `Equals()`. If you’ve already written `Equals(T)`, there’s no reason not to explicitly implement `IEquatable`. Doing so expands the utility of your class by allowing it to be used where an `IEquatable` is called for. - + +The `IEquatable` interface has only one method in it: `Equals()`. If you’ve already written +`Equals(T)`, there’s no reason not to explicitly implement `IEquatable`. Doing so expands the utility of your class by +allowing it to be used where an `IEquatable` is called for. + **Note**: Classes that implement `IEquatable` should also be `sealed`. - + ### Noncompliant code example class MyClass // Noncompliant diff --git a/docs/description/S3898.md b/docs/description/S3898.md index bd22388..1946f63 100644 --- a/docs/description/S3898.md +++ b/docs/description/S3898.md @@ -1,7 +1,9 @@ ## Why is this an issue? - -If you’re using a `struct`, it is likely because you’re interested in performance. But by failing to implement `IEquatable` you’re loosing performance when comparisons are made because without `IEquatable`, boxing and reflection are used to make comparisons. - + +If you’re using a `struct`, it is likely because you’re interested in performance. But by failing to implement +`IEquatable` you’re loosing performance when comparisons are made because without `IEquatable`, boxing and +reflection are used to make comparisons. + ### Noncompliant code example struct MyStruct // Noncompliant @@ -22,5 +24,5 @@ If you’re using a `struct`, it is likely because you’re interested in perfor } ## Resources - + - [IEquatable<T> Interface](https://learn.microsoft.com/en-us/dotnet/api/system.iequatable-1) \ No newline at end of file diff --git a/docs/description/S3900.md b/docs/description/S3900.md index f788ee9..298de96 100644 --- a/docs/description/S3900.md +++ b/docs/description/S3900.md @@ -1,9 +1,12 @@ ## Why is this an issue? - -Methods declared as `public`, `protected`, or `protected internal` can be accessed from other assemblies, which means you should validate parameters to be within the expected constraints. In general, checking against `null` is recommended in defensive programming. - -This rule raises an issue when a parameter of a publicly accessible method is not validated against `null` before being dereferenced. - + +Methods declared as `public`, `protected`, or `protected internal` can be accessed from other assemblies, which +means you should validate parameters to be within the expected constraints. In general, checking against `null` is recommended in defensive +programming. + +This rule raises an issue when a parameter of a publicly accessible method is not validated against `null` before being +dereferenced. + ### Noncompliant code example public class MyClass @@ -62,7 +65,7 @@ This rule raises an issue when a parameter of a publicly accessible method is no } ### Exceptions - + - Arguments validated for `null` via helper methods should be annotated with the [`\[NotNull`](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/nullable-analysis#postconditions-maybenull-and-notnull)] attribute. - Method parameters marked with the `[NotNull]` [Resharper code annotation attribute](https://www.jetbrains.com/help/resharper/Reference__Code_Annotation_Attributes.html#ItemNotNullAttribute) are supported as well. diff --git a/docs/description/S3902.md b/docs/description/S3902.md index 9310643..65c464d 100644 --- a/docs/description/S3902.md +++ b/docs/description/S3902.md @@ -1,9 +1,13 @@ ## Why is this an issue? - -Using `Type.Assembly` to get the current assembly is nearly free in terms of performance; it’s a simple property access. On the other hand, `Assembly.GetExecutingAssembly()` can take up to 30 times as long because it walks up the call stack to find the assembly. - -Note that `Assembly.GetExecutingAssembly()` is different than `Type.Assembly` because it dynamically returns the assembly that contains the startup object of the currently executed application. For example, if executed from an application it will return the application assembly, but if executed from a unit test project it could return the unit test assembly. `Type.Assembly` always returns the assembly that contains the specified type. - + +Using `Type.Assembly` to get the current assembly is nearly free in terms of performance; it’s a simple property access. On the other +hand, `Assembly.GetExecutingAssembly()` can take up to 30 times as long because it walks up the call stack to find the assembly. + +Note that `Assembly.GetExecutingAssembly()` is different than `Type.Assembly` because it dynamically returns the assembly +that contains the startup object of the currently executed application. For example, if executed from an application it will return the application +assembly, but if executed from a unit test project it could return the unit test assembly. `Type.Assembly` always returns the assembly that +contains the specified type. + ### Noncompliant code example public class Example diff --git a/docs/description/S3903.md b/docs/description/S3903.md index 14ebaed..71606a4 100644 --- a/docs/description/S3903.md +++ b/docs/description/S3903.md @@ -1,7 +1,8 @@ ## Why is this an issue? - -Types are declared in namespaces in order to prevent name collisions and as a way to organize them into the object hierarchy. Types that are defined outside any named namespace are in a global namespace that cannot be referenced in code. - + +Types are declared in namespaces in order to prevent name collisions and as a way to organize them into the object hierarchy. Types that are +defined outside any named namespace are in a global namespace that cannot be referenced in code. + ### Noncompliant code example public class Foo // Noncompliant diff --git a/docs/description/S3904.md b/docs/description/S3904.md index ad2cfd3..a55c27b 100644 --- a/docs/description/S3904.md +++ b/docs/description/S3904.md @@ -1,9 +1,11 @@ ## Why is this an issue? - -The [AssemblyVersion](https://learn.microsoft.com/en-us/dotnet/api/system.reflection.assemblyversionattribute) attribute is used to specify the version number of an assembly. An assembly is a compiled unit of code, which can be marked with a version number by applying the attribute to an assembly’s source code file. - + +The [AssemblyVersion](https://learn.microsoft.com/en-us/dotnet/api/system.reflection.assemblyversionattribute) attribute is used to +specify the version number of an assembly. An assembly is a compiled unit of code, which can be marked with a version number by applying the attribute +to an assembly’s source code file. + The `AssemblyVersion` attribute is useful for many reasons: - + - **Versioning**: The attribute allows developers to track and manage different versions of an assembly. By incrementing the version number for each new release, you can easily identify and differentiate between different versions of the same assembly. This is particularly useful when distributing and deploying software, as it helps manage updates and compatibility between different versions. @@ -14,12 +16,13 @@ The `AssemblyVersion` attribute is useful for many reasons: Assembly Cache, is a central repository for storing shared assemblies on a system. The AssemblyVersion attribute plays a crucial role in managing assemblies in the GAC. Different versions of an assembly can coexist in the GAC, allowing applications to use the specific version they require. -If no `AssemblyVersion` is provided, the same default version will be used for every build. Since the version number is used by .NET Framework to uniquely identify an assembly, this can lead to broken dependencies. - +If no `AssemblyVersion` is provided, the same default version will be used for every build. Since the version number is used by .NET +Framework to uniquely identify an assembly, this can lead to broken dependencies. + ## How to fix it - + ### Code examples - + #### Noncompliant code example using System.Reflection; @@ -42,7 +45,7 @@ If no `AssemblyVersion` is provided, the same default version will be used for e } ## Resources - + ### Documentation - [Assembly Versioning](https://docs.microsoft.com/en-us/dotnet/standard/assembly/versioning) diff --git a/docs/description/S3906.md b/docs/description/S3906.md index 593181b..7a01120 100644 --- a/docs/description/S3906.md +++ b/docs/description/S3906.md @@ -1,13 +1,13 @@ ## Why is this an issue? - + Delegate event handlers (i.e. delegates used as type of an event) should have a very specific signature: - + - Return type `void`. - First argument of type `System.Object` and named 'sender'. - Second argument of type `System.EventArgs` (or any derived type) and is named 'e'. This rule raises an issue whenever a `delegate` declaration doesn’t match that signature. - + ### Noncompliant code example public delegate void AlarmEventHandler(object s); @@ -27,5 +27,5 @@ This rule raises an issue whenever a `delegate` declaration doesn’t match that } ## Resources - + [Handling and Raising Events](https://msdn.microsoft.com/en-us/library/edzehd2t.aspx) \ No newline at end of file diff --git a/docs/description/S3908.md b/docs/description/S3908.md index 40e5019..39e83ff 100644 --- a/docs/description/S3908.md +++ b/docs/description/S3908.md @@ -1,9 +1,11 @@ ## Why is this an issue? - -Since .Net Framework version 2.0 it is not necessary to declare a delegate that specifies a class derived from `System.EventArgs`. The `System.EventHandler` delegate mechanism should be used instead as it allows any class derived from `EventArgs` to be used with that handler. - + +Since .Net Framework version 2.0 it is not necessary to declare a delegate that specifies a class derived from `System.EventArgs`. The +`System.EventHandler` delegate mechanism should be used instead as it allows any class derived from +`EventArgs` to be used with that handler. + This rule raises an issue when an old style delegate is used as an event handler. - + ### Noncompliant code example public class MyEventArgs : EventArgs diff --git a/docs/description/S3909.md b/docs/description/S3909.md index d1b4996..1190124 100644 --- a/docs/description/S3909.md +++ b/docs/description/S3909.md @@ -1,9 +1,10 @@ ## Why is this an issue? - -The NET Framework 2.0 introduced the generic interface `System.Collections.Generic.IEnumerable` and it should be preferred over the older, non generic, interfaces. - + +The NET Framework 2.0 introduced the generic interface `System.Collections.Generic.IEnumerable` and it should be preferred over +the older, non generic, interfaces. + This rule raises an issue when a public type implements `System.Collections.IEnumerable`. - + ### Noncompliant code example using System; diff --git a/docs/description/S3923.md b/docs/description/S3923.md index d45eaa6..0d8e079 100644 --- a/docs/description/S3923.md +++ b/docs/description/S3923.md @@ -1,7 +1,7 @@ ## Why is this an issue? - + Having all branches of a `switch` or `if` chain with the same implementation indicates a problem. - + In the following code: if (b == 0) // Noncompliant @@ -31,9 +31,9 @@ In the following code: } Either there is a copy-paste error that needs fixing or an unnecessary `switch` or `if` chain that should be removed. - + ### Exceptions - + This rule does not apply to `if` chains without `else`, nor to `switch` without a `default` clause. if (b == 0) //no issue, this could have been done on purpose to make the code more readable diff --git a/docs/description/S3925.md b/docs/description/S3925.md index 2ff488a..5daf5a7 100644 --- a/docs/description/S3925.md +++ b/docs/description/S3925.md @@ -1,11 +1,13 @@ ## Why is this an issue? - -The [`ISerializable`](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.serialization.iserializable) interface is the mechanism to control the type serialization process. If not implemented correctly this could result in an invalid serialization and hard-to-detect bugs. - + +The [`ISerializable`](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.serialization.iserializable) interface is +the mechanism to control the type serialization process. If not implemented correctly this could result in an invalid serialization and hard-to-detect +bugs. + This rule raises an issue on types that implement `ISerializable` without following the [serialization pattern recommended by Microsoft](https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/serialization). - + Specifically, this rule checks for these problems: - + - The [`SerializableAttribute`](https://learn.microsoft.com/en-us/dotnet/api/system.serializableattribute) attribute is missing. - Non-serializable fields are not marked with the [`NonSerializedAttribute`](https://learn.microsoft.com/en-us/dotnet/api/system.nonserializedattribute) attribute. @@ -17,10 +19,15 @@ Specifically, this rule checks for these problems: - A derived type has an `ISerializable.GetObjectData` method that does not call the `base` method. - A derived type has serializable fields but the `ISerializable.GetObjectData` method is not overridden. -Classes that inherit from [`Exception`](https://learn.microsoft.com/en-us/dotnet/api/system.exception) are implementing `ISerializable`. Make sure the `[Serializable]` attribute is used and that `ISerializable` is correctly implemented. Even if you don’t plan to explicitly serialize the object yourself, it might still require serialization, for instance when crossing the boundary of an [`AppDomain`](https://learn.microsoft.com/en-us/dotnet/api/system.appdomain). - -This rule only raises an issue on classes that indicate that they are interested in serialization (see the *Exceptions* section). That is to reduce noise because a lot of classes in the base class library are implementing `ISerializable`, including the following classes: [`Exception`](https://learn.microsoft.com/en-us/dotnet/api/system.exception), [`Uri`](https://learn.microsoft.com/en-us/dotnet/api/system.uri), [`Hashtable`](https://learn.microsoft.com/en-us/dotnet/api/system.collections.hashtable), [`Dictionary`](https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.dictionary-2), [`DataSet`](https://learn.microsoft.com/en-us/dotnet/api/system.data.dataset), [`HttpWebRequest`](https://learn.microsoft.com/en-us/dotnet/api/system.net.httpwebrequest), [`Regex`](https://learn.microsoft.com/en-us/dotnet/api/system.text.regularexpressions.regex) [`TreeNode`](https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.treenode), and others. There is often no need to add serialization support in classes derived from these types. - +Classes that inherit from [`Exception`](https://learn.microsoft.com/en-us/dotnet/api/system.exception) are implementing +`ISerializable`. Make sure the `[Serializable]` attribute is used and that `ISerializable` is correctly implemented. +Even if you don’t plan to explicitly serialize the object yourself, it might still require serialization, for instance when crossing the boundary of +an [`AppDomain`](https://learn.microsoft.com/en-us/dotnet/api/system.appdomain). + +This rule only raises an issue on classes that indicate that they are interested in serialization (see the *Exceptions* section). That is to +reduce noise because a lot of classes in the base class library are implementing `ISerializable`, including the following classes: [`Exception`](https://learn.microsoft.com/en-us/dotnet/api/system.exception), [`Uri`](https://learn.microsoft.com/en-us/dotnet/api/system.uri), [`Hashtable`](https://learn.microsoft.com/en-us/dotnet/api/system.collections.hashtable), [`Dictionary`](https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.dictionary-2), [`DataSet`](https://learn.microsoft.com/en-us/dotnet/api/system.data.dataset), [`HttpWebRequest`](https://learn.microsoft.com/en-us/dotnet/api/system.net.httpwebrequest), [`Regex`](https://learn.microsoft.com/en-us/dotnet/api/system.text.regularexpressions.regex) [`TreeNode`](https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.treenode), and others. There is often no need to add +serialization support in classes derived from these types. + ### Exceptions - Classes in test projects are not checked. @@ -47,11 +54,12 @@ This rule only raises an issue on classes that indicate that they are interested } ## How to fix it - -Make sure to follow the [recommended guidelines](https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/serialization) when implementing `ISerializable`. - + +Make sure to follow the [recommended guidelines](https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/serialization) when +implementing `ISerializable`. + ### Code examples - + #### Noncompliant code example public class Bar @@ -173,7 +181,7 @@ Make sure to follow the [recommended guidelines](https://learn.microsoft.com/en- } ## Resources - + ### Documentation - Microsoft Learn - [Serialization](https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/serialization) diff --git a/docs/description/S3926.md b/docs/description/S3926.md index 6f33f4d..45ed3c9 100644 --- a/docs/description/S3926.md +++ b/docs/description/S3926.md @@ -1,9 +1,13 @@ ## Why is this an issue? - -Fields marked with `System.Runtime.Serialization.OptionalFieldAttribute` are serialized just like any other field. But such fields are ignored on deserialization, and retain the default values associated with their types. Therefore, deserialization event handlers should be declared to set such fields during the deserialization process. - -This rule raises when at least one field with the `System.Runtime.Serialization.OptionalFieldAttribute` attribute is declared but one (or both) of the following event handlers `System.Runtime.Serialization.OnDeserializingAttribute` or `System.Runtime.Serialization.OnDeserializedAttribute` are not present. - + +Fields marked with `System.Runtime.Serialization.OptionalFieldAttribute` are serialized just like any other field. But such fields are +ignored on deserialization, and retain the default values associated with their types. Therefore, deserialization event handlers should be declared to +set such fields during the deserialization process. + +This rule raises when at least one field with the `System.Runtime.Serialization.OptionalFieldAttribute` attribute is declared but one +(or both) of the following event handlers `System.Runtime.Serialization.OnDeserializingAttribute` or +`System.Runtime.Serialization.OnDeserializedAttribute` are not present. + ### Noncompliant code example [Serializable] diff --git a/docs/description/S3927.md b/docs/description/S3927.md index 5c15945..0c52d3d 100644 --- a/docs/description/S3927.md +++ b/docs/description/S3927.md @@ -1,22 +1,24 @@ ## Why is this an issue? - -Serialization event handlers that don’t have the correct signature will not be called, bypassing augmentations to automated serialization and deserialization events. - + +Serialization event handlers that don’t have the correct signature will not be called, bypassing augmentations to automated serialization and +deserialization events. + A method is designated a serialization event handler by applying one of the following serialization event attributes: - + - [`OnSerializingAttribute`](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.serialization.onserializingattribute) - [`OnSerializedAttribute`](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.serialization.onserializedattribute) - [`OnDeserializingAttribute`](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.serialization.ondeserializingattribute) - [`OnDeserializedAttribute`](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.serialization.ondeserializedattribute) -Serialization event handlers take a single parameter of type [`StreamingContext`](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.serialization.streamingcontext), return `void`, and have `private` visibility. - +Serialization event handlers take a single parameter of type [`StreamingContext`](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.serialization.streamingcontext), return +`void`, and have `private` visibility. + This rule raises an issue when any of these constraints are not respected. - + ## How to fix it - + ### Code examples - + #### Noncompliant code example [Serializable] @@ -57,7 +59,7 @@ This rule raises an issue when any of these constraints are not respected. } ## Resources - + ### Documentation - Microsoft Learn - [CA2238: Implement serialization methods diff --git a/docs/description/S3928.md b/docs/description/S3928.md index 0f35f0b..fdeed87 100644 --- a/docs/description/S3928.md +++ b/docs/description/S3928.md @@ -1,7 +1,8 @@ ## Why is this an issue? - -Some constructors of the `ArgumentException`, `ArgumentNullException`, `ArgumentOutOfRangeException` and `DuplicateWaitObjectException` classes must be fed with a valid parameter name. This rule raises an issue in two cases: - + +Some constructors of the `ArgumentException`, `ArgumentNullException`, `ArgumentOutOfRangeException` and +`DuplicateWaitObjectException` classes must be fed with a valid parameter name. This rule raises an issue in two cases: + - When this parameter name doesn’t match any existing ones. - When a call is made to the default (parameterless) constructor @@ -43,5 +44,5 @@ Some constructors of the `ArgumentException`, `ArgumentNullException`, `Argument } ### Exceptions - + The rule won’t raise an issue if the parameter name is not a constant value. \ No newline at end of file diff --git a/docs/description/S3937.md b/docs/description/S3937.md index f362b6b..459dedc 100644 --- a/docs/description/S3937.md +++ b/docs/description/S3937.md @@ -1,9 +1,10 @@ ## Why is this an issue? - -The use of punctuation characters to separate subgroups in a number can make the number more readable. For instance consider 1,000,000,000 versus 1000000000. But when the grouping is irregular, such as 1,000,00,000; it indicates an error. - + +The use of punctuation characters to separate subgroups in a number can make the number more readable. For instance consider 1,000,000,000 versus +1000000000. But when the grouping is irregular, such as 1,000,00,000; it indicates an error. + This rule raises an issue when underscores (`_`) are used to break a number into irregular subgroups. - + ### Noncompliant code example int thousand = 100_0; diff --git a/docs/description/S3949.md b/docs/description/S3949.md index 539f4d5..08f8771 100644 --- a/docs/description/S3949.md +++ b/docs/description/S3949.md @@ -1,7 +1,9 @@ ## Why is this an issue? - -Numbers are infinite, but the types that hold them are not. Each numeric type has hard upper and lower bounds. Try to calculate or assign numbers beyond those bounds, and the result will be a value that has silently wrapped around from the expected positive value to a negative one, or vice versa. - + +Numbers are infinite, but the types that hold them are not. Each numeric type has hard upper and lower bounds. Try to calculate or assign numbers +beyond those bounds, and the result will be a value that has silently wrapped around from the expected positive value to a negative one, or vice +versa. + ## Noncompliant code example public int Transform(int value) @@ -24,4 +26,11 @@ Numbers are infinite, but the types that hold them are not. Each numeric type ha } long number = int.MaxValue; return number + value; - } \ No newline at end of file + } + +## Resources + +### Standards + +- STIG Viewer - [Application Security and + Development: V-222612](https://stigviewer.com/stig/application_security_and_development/2023-06-08/finding/V-222612) - The application must not be vulnerable to overflow attacks. \ No newline at end of file diff --git a/docs/description/S3956.md b/docs/description/S3956.md index d3e9364..dd9a647 100644 --- a/docs/description/S3956.md +++ b/docs/description/S3956.md @@ -1,7 +1,9 @@ ## Why is this an issue? - -`System.Collections.Generic.List` is a generic collection that is designed for performance and not inheritance. For example, it does not contain virtual members that make it easier to change the behavior of an inherited class. That means that future attempts to expand the behavior will be spoiled because the extension points simply aren’t there. Instead, one of the following generic collections should be used: - + +`System.Collections.Generic.List` is a generic collection that is designed for performance and not inheritance. For example, it +does not contain virtual members that make it easier to change the behavior of an inherited class. That means that future attempts to expand the +behavior will be spoiled because the extension points simply aren’t there. Instead, one of the following generic collections should be used: + - `System.Collections.Generic.IEnumerable` - `System.Collections.Generic.IReadOnlyCollection` - `System.Collections.Generic.ICollection` diff --git a/docs/description/S3962.md b/docs/description/S3962.md index f5fb529..d020b45 100644 --- a/docs/description/S3962.md +++ b/docs/description/S3962.md @@ -1,9 +1,10 @@ ## Why is this an issue? - -The value of a `static readonly` field is computed at runtime while the value of a `const` field is calculated at compile time, which improves performance. - + +The value of a `static readonly` field is computed at runtime while the value of a `const` field is calculated at compile +time, which improves performance. + This rule raises an issue when a `static readonly` field is initialized with a value that is computable at compile time. - + As specified by Microsoft, the list of types that can have a constant value are: | C# type | .Net Fwk type | diff --git a/docs/description/S3963.md b/docs/description/S3963.md index 07370f5..478695e 100644 --- a/docs/description/S3963.md +++ b/docs/description/S3963.md @@ -1,9 +1,10 @@ ## Why is this an issue? - -When a `static` constructor serves no other purpose that initializing `static` fields, it comes with an unnecessary performance cost because the compiler generates a check before each `static` method or instance constructor invocation. - + +When a `static` constructor serves no other purpose that initializing `static` fields, it comes with an unnecessary +performance cost because the compiler generates a check before each `static` method or instance constructor invocation. + Instead, inline initialization is highly recommended. - + ### Noncompliant code example namespace myLib diff --git a/docs/description/S3966.md b/docs/description/S3966.md index cadde85..f37ce49 100644 --- a/docs/description/S3966.md +++ b/docs/description/S3966.md @@ -1,13 +1,17 @@ ## Why is this an issue? - -Disposing an object twice in the same method, either with the [using](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/using) keyword or by calling `Dispose` directly, is confusing and error-prone. For example, another developer might try to use an already-disposed object, or there can be runtime errors for specific paths in the code. - -In addition, even if the [documentation](https://learn.microsoft.com/en-us/dotnet/api/system.idisposable.dispose#System_IDisposable_Dispose) explicitly states that calling the `Dispose` method multiple times should not throw an exception, some implementations still do it. Thus it is safer to not dispose of an object twice when possible. - + +Disposing an object twice in the same method, either with the [using](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/using) keyword or by calling `Dispose` +directly, is confusing and error-prone. For example, another developer might try to use an already-disposed object, or there can be runtime errors for +specific paths in the code. + +In addition, even if the [documentation](https://learn.microsoft.com/en-us/dotnet/api/system.idisposable.dispose#System_IDisposable_Dispose) explicitly states that +calling the `Dispose` method multiple times should not throw an exception, some implementations still do it. Thus it is safer to not +dispose of an object twice when possible. + ## How to fix it - + ### Code examples - + #### Noncompliant code example var foo = new Disposable(); @@ -30,9 +34,9 @@ In addition, even if the [documentation](https://learn.microsoft.com/en-us/dotne } ## Resources - + ### Documentation - + - [Dispose method](https://learn.microsoft.com/en-us/dotnet/api/system.idisposable.dispose?redirectedfrom=MSDN#System_IDisposable_Dispose) - [DisposeAsync method](https://learn.microsoft.com/en-us/dotnet/api/system.iasyncdisposable.disposeasync) diff --git a/docs/description/S3967.md b/docs/description/S3967.md index 30abe19..03fe55f 100644 --- a/docs/description/S3967.md +++ b/docs/description/S3967.md @@ -1,7 +1,8 @@ ## Why is this an issue? - -A jagged array is an array whose elements are arrays. It is recommended over a multidimensional array because the arrays that make up the elements can be of different sizes, which avoids wasting memory space. - + +A jagged array is an array whose elements are arrays. It is recommended over a multidimensional array because the arrays that make up the elements +can be of different sizes, which avoids wasting memory space. + ### Noncompliant code example int [,] myArray = // Noncompliant diff --git a/docs/description/S3971.md b/docs/description/S3971.md index 9a2764f..db9bc96 100644 --- a/docs/description/S3971.md +++ b/docs/description/S3971.md @@ -1,5 +1,6 @@ ## Why is this an issue? - -`GC.SuppressFinalize` requests that the system not call the finalizer for the specified object. This should only be done when implementing `Dispose` as part of the [Dispose Pattern](https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose). - + +`GC.SuppressFinalize` requests that the system not call the finalizer for the specified object. This should only be done when +implementing `Dispose` as part of the [Dispose Pattern](https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose). + This rule raises an issue when `GC.SuppressFinalize` is called outside that pattern. \ No newline at end of file diff --git a/docs/description/S3972.md b/docs/description/S3972.md index edc11c5..3f947e4 100644 --- a/docs/description/S3972.md +++ b/docs/description/S3972.md @@ -1,7 +1,9 @@ ## Why is this an issue? - -Placing an `if` statement on the same line as the closing `}` from a preceding `if`, `else`, or `else if` block can lead to confusion and potential errors. It may indicate a missing `else` statement or create ambiguity for maintainers who might fail to understand that the two statements are unconnected. - + +Placing an `if` statement on the same line as the closing `}` from a preceding `if`, `else`, or +`else if` block can lead to confusion and potential errors. It may indicate a missing `else` statement or create ambiguity for +maintainers who might fail to understand that the two statements are unconnected. + The following code snippet is confusing: if (condition1) { @@ -29,7 +31,7 @@ Or they were supposed to be exclusive and you should use `else if` instead: } ## Resources - + ### Documentation - + - [If statement](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/selection-statements#the-if-statement) \ No newline at end of file diff --git a/docs/description/S3973.md b/docs/description/S3973.md index a21438b..598d907 100644 --- a/docs/description/S3973.md +++ b/docs/description/S3973.md @@ -1,9 +1,10 @@ ## Why is this an issue? - -When the line immediately after conditional statements has neither curly braces nor indentation, the intent of the code is unclear and perhaps not executed as expected. Additionally, such code is confusing to maintainers. - + +When the line immediately after conditional statements has neither curly braces nor indentation, the intent of the code is unclear and perhaps not +executed as expected. Additionally, such code is confusing to maintainers. + The rule will check the line indentation after the following conditional statements: - + - [if and if-else statements](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/selection-statements#the-if-statement) - [for diff --git a/docs/description/S3981.md b/docs/description/S3981.md index 5bf489f..91228aa 100644 --- a/docs/description/S3981.md +++ b/docs/description/S3981.md @@ -1,6 +1,7 @@ ## Why is this an issue? - -The size of a collection and the length of an array are always greater than or equal to zero. Testing it doesn’t make sense, since the result is always `true`. + +The size of a collection and the length of an array are always greater than or equal to zero. Testing it doesn’t make sense, since the result is +always `true`. if(collection.Count >= 0){...} // Noncompliant: always true diff --git a/docs/description/S3984.md b/docs/description/S3984.md index 721255e..f68254b 100644 --- a/docs/description/S3984.md +++ b/docs/description/S3984.md @@ -1,6 +1,7 @@ ## Why is this an issue? - -Creating a new [`Exception`](https://learn.microsoft.com/en-us/dotnet/api/system.exception) without actually throwing does not achieve the intended purpose. + +Creating a new [`Exception`](https://learn.microsoft.com/en-us/dotnet/api/system.exception) without actually throwing does +not achieve the intended purpose. if (x < 0) { @@ -16,9 +17,9 @@ statement](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/st } ## Resources - + ### Documentation - + - Microsoft Learn - [`Exception` Class](https://learn.microsoft.com/en-us/dotnet/api/system.exception) - Microsoft Learn - [Exception-handling statements - `throw`, `try-catch`, `try-finally`, and `try-catch-finally`](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/exception-handling-statements) \ No newline at end of file diff --git a/docs/description/S3990.md b/docs/description/S3990.md index 7495dd4..4b6ce2e 100644 --- a/docs/description/S3990.md +++ b/docs/description/S3990.md @@ -1,7 +1,8 @@ ## Why is this an issue? - -Assemblies should conform with the Common Language Specification (CLS) in order to be usable across programming languages. To be compliant an assembly has to indicate it with `System.CLSCompliantAttribute`. - + +Assemblies should conform with the Common Language Specification (CLS) in order to be usable across programming languages. To be compliant an +assembly has to indicate it with `System.CLSCompliantAttribute`. + ### Compliant solution using System; diff --git a/docs/description/S3992.md b/docs/description/S3992.md index 1b86f84..b99a129 100644 --- a/docs/description/S3992.md +++ b/docs/description/S3992.md @@ -1,9 +1,10 @@ ## Why is this an issue? - -Assemblies should explicitly indicate whether they are meant to be COM visible or not. If the `ComVisibleAttribute` is not present, the default is to make the content of the assembly visible to COM clients. - + +Assemblies should explicitly indicate whether they are meant to be COM visible or not. If the `ComVisibleAttribute` is not present, the +default is to make the content of the assembly visible to COM clients. + Note that COM visibility can be overridden for individual types and members. - + ### Noncompliant code example using System; diff --git a/docs/description/S3993.md b/docs/description/S3993.md index a467185..bab297c 100644 --- a/docs/description/S3993.md +++ b/docs/description/S3993.md @@ -1,7 +1,8 @@ ## Why is this an issue? - -When defining custom attributes, `System.AttributeUsageAttribute` must be used to indicate where the attribute can be applied. This will determine its valid locations in the code. - + +When defining custom attributes, `System.AttributeUsageAttribute` must be used to indicate where the attribute can be applied. This will +determine its valid locations in the code. + ### Noncompliant code example using System; diff --git a/docs/description/S3994.md b/docs/description/S3994.md index dba48df..66fe092 100644 --- a/docs/description/S3994.md +++ b/docs/description/S3994.md @@ -1,9 +1,12 @@ ## Why is this an issue? - -String representations of URIs or URLs are prone to parsing and encoding errors which can lead to vulnerabilities. The `System.Uri` class is a safe alternative and should be preferred. At minimum, an overload of the method taking a `System.Uri` as a parameter should be provided in each class that contains a method with an apparent Uri passed as a `string`. - -This rule raises issues when a method has a string parameter with a name containing "uri", "Uri", "urn", "Urn", "url" or "Url", and the type doesn’t declare a corresponding overload taking an `System.Uri` parameter instead. - + +String representations of URIs or URLs are prone to parsing and encoding errors which can lead to vulnerabilities. The `System.Uri` +class is a safe alternative and should be preferred. At minimum, an overload of the method taking a `System.Uri` as a parameter should be +provided in each class that contains a method with an apparent Uri passed as a `string`. + +This rule raises issues when a method has a string parameter with a name containing "uri", "Uri", "urn", "Urn", "url" or "Url", and the type +doesn’t declare a corresponding overload taking an `System.Uri` parameter instead. + ### Noncompliant code example using System; diff --git a/docs/description/S3995.md b/docs/description/S3995.md index 79ce5cc..dceb128 100644 --- a/docs/description/S3995.md +++ b/docs/description/S3995.md @@ -1,9 +1,11 @@ ## Why is this an issue? - -String representations of URIs or URLs are prone to parsing and encoding errors which can lead to vulnerabilities. The `System.Uri` class is a safe alternative and should be preferred. - -This rule raises an issue when a method has a `string` return type and its name contains "Uri", "Urn", or "Url" or begins with "uri", "urn", or "url". - + +String representations of URIs or URLs are prone to parsing and encoding errors which can lead to vulnerabilities. The `System.Uri` +class is a safe alternative and should be preferred. + +This rule raises an issue when a method has a `string` return type and its name contains "Uri", "Urn", or "Url" or begins with "uri", +"urn", or "url". + ### Noncompliant code example using System; diff --git a/docs/description/S3996.md b/docs/description/S3996.md index 78b00ae..8c31cbf 100644 --- a/docs/description/S3996.md +++ b/docs/description/S3996.md @@ -1,9 +1,10 @@ ## Why is this an issue? - -String representations of URIs or URLs are prone to parsing and encoding errors which can lead to vulnerabilities. The `System.Uri` class is a safe alternative and should be preferred. - + +String representations of URIs or URLs are prone to parsing and encoding errors which can lead to vulnerabilities. The `System.Uri` +class is a safe alternative and should be preferred. + This rule raises an issue when a property is a string type and its name contains "uri", "Uri", "urn", "Urn", "url" or "Url". - + ### Noncompliant code example using System; diff --git a/docs/description/S3997.md b/docs/description/S3997.md index 2d45b56..482acc4 100644 --- a/docs/description/S3997.md +++ b/docs/description/S3997.md @@ -1,9 +1,12 @@ ## Why is this an issue? - -String representations of URIs or URLs are prone to parsing and encoding errors which can lead to vulnerabilities. The `System.Uri` class is a safe alternative and should be preferred. - -This rule raises an issue when two overloads differ only by the string / `Uri` parameter and the string overload doesn’t call the `Uri` overload. It is assumed that the string parameter represents a URI because of the exact match besides that parameter type. It stands to reason that the safer overload should be used. - + +String representations of URIs or URLs are prone to parsing and encoding errors which can lead to vulnerabilities. The `System.Uri` +class is a safe alternative and should be preferred. + +This rule raises an issue when two overloads differ only by the string / `Uri` parameter and the string overload doesn’t call the +`Uri` overload. It is assumed that the string parameter represents a URI because of the exact match besides that parameter type. It stands +to reason that the safer overload should be used. + ### Noncompliant code example using System; diff --git a/docs/description/S3998.md b/docs/description/S3998.md index fb99dca..80fd64f 100644 --- a/docs/description/S3998.md +++ b/docs/description/S3998.md @@ -1,12 +1,14 @@ ## Why is this an issue? - + Objects that can be accessed across [application -domain](https://learn.microsoft.com/en-us/dotnet/framework/app-domains/application-domains) boundaries are said to have weak identity. This means that these objects can be considered shared resources outside of the domain, which can be lead to them being accessed or modified by multiple threads or concurrent parts of a program, outside of the domain. - -A [thread](https://en.wikipedia.org/wiki/Thread_%28computing%29) acquiring a [lock](https://en.wikipedia.org/wiki/Lock_%28computer_science%29) on such an object runs the risk of being blocked by another thread in a different application domain, leading to poor performance and potentially [thread starvation](https://stackoverflow.com/questions/1162587/what-is-starvation) and [deadlocks](https://en.wikipedia.org/wiki/Deadlock). - +domain](https://learn.microsoft.com/en-us/dotnet/framework/app-domains/application-domains) boundaries are said to have weak identity. This means that these objects can be considered shared resources outside of the domain, which +can be lead to them being accessed or modified by multiple threads or concurrent parts of a program, outside of the domain. + +A [thread](https://en.wikipedia.org/wiki/Thread_%28computing%29) acquiring a [lock](https://en.wikipedia.org/wiki/Lock_%28computer_science%29) on such an object runs the risk of being blocked by another thread in a +different application domain, leading to poor performance and potentially [thread starvation](https://stackoverflow.com/questions/1162587/what-is-starvation) and [deadlocks](https://en.wikipedia.org/wiki/Deadlock). + Types with weak identity are: - + - [MarshalByRefObject](https://learn.microsoft.com/en-us/dotnet/api/system.marshalbyrefobject) - [ExecutionEngineException](https://learn.microsoft.com/en-us/dotnet/api/system.executionengineexception) - [OutOfMemoryException](https://learn.microsoft.com/en-us/dotnet/api/system.outofmemoryexception) @@ -17,9 +19,9 @@ Types with weak identity are: - [Thread](https://learn.microsoft.com/en-us/dotnet/api/system.threading.thread) ## How to fix it - + ### Code examples - + #### Noncompliant code example public class Sample @@ -51,7 +53,7 @@ Types with weak identity are: } ## Resources - + ### Documentation - [Thread](https://en.wikipedia.org/wiki/Thread_%28computing%29) diff --git a/docs/description/S4000.md b/docs/description/S4000.md index 0686f78..4309e90 100644 --- a/docs/description/S4000.md +++ b/docs/description/S4000.md @@ -1,7 +1,9 @@ ## Why is this an issue? - -Pointer and unmanaged function pointer types such as `IntPtr`, `UIntPtr`, `int*` etc. are used to access unmanaged memory, usually in order to use C or C++ libraries. If such a pointer is not secured by making it `private`, `internal` or `readonly`, it can lead to a vulnerability allowing access to arbitrary locations. - + +Pointer and unmanaged function pointer types such as `IntPtr`, `UIntPtr`, `int*` etc. are used to access unmanaged +memory, usually in order to use C or C++ libraries. If such a pointer is not secured by making it `private`, `internal` or +`readonly`, it can lead to a vulnerability allowing access to arbitrary locations. + ### Noncompliant code example using System; diff --git a/docs/description/S4002.md b/docs/description/S4002.md index 5cda777..f53cbe3 100644 --- a/docs/description/S4002.md +++ b/docs/description/S4002.md @@ -1,7 +1,7 @@ ## Why is this an issue? - + This rule raises an issue when a disposable type contains fields of the following types and does not implement a finalizer: - + - `System.IntPtr` - `System.UIntPtr` - `System.Runtime.InteropService.HandleRef` diff --git a/docs/description/S4004.md b/docs/description/S4004.md index 9c0cff7..6a80f0f 100644 --- a/docs/description/S4004.md +++ b/docs/description/S4004.md @@ -1,9 +1,13 @@ ## Why is this an issue? - -A writable collection property can be replaced by a completely different collection. Making it `readonly` prevents that while still allowing individual members to be set. If you want to allow the replacement of the whole collection the recommended pattern is to implement a method to remove all the elements (e.g. `System.Collections.List.Clear`) and a method to populate the collection (e.g. `System.Collections.List.AddRange`). - -This rule raises an issue when an externally visible writable property is of a type that implements `System.Collections.ICollection` or `System.Collections.Generic.ICollection`. - + +A writable collection property can be replaced by a completely different collection. Making it `readonly` prevents that while still +allowing individual members to be set. If you want to allow the replacement of the whole collection the recommended pattern is to implement a method +to remove all the elements (e.g. `System.Collections.List.Clear`) and a method to populate the collection (e.g. +`System.Collections.List.AddRange`). + +This rule raises an issue when an externally visible writable property is of a type that implements `System.Collections.ICollection` or +`System.Collections.Generic.ICollection`. + ### Noncompliant code example using System; @@ -42,9 +46,9 @@ This rule raises an issue when an externally visible writable property is of a t } ### Exceptions - + This rule does not raise issues for - + - `string`, `Array` and `PermissionSet,` - properties marked as `DataMemberAttribute` - classes marked as `Serializable` diff --git a/docs/description/S4005.md b/docs/description/S4005.md index 3091e4e..eda3c2d 100644 --- a/docs/description/S4005.md +++ b/docs/description/S4005.md @@ -1,11 +1,14 @@ ## Why is this an issue? - -String representations of URIs or URLs are prone to parsing and encoding errors which can lead to vulnerabilities. The `System.Uri` class is a safe alternative and should be preferred. - -This rule raises an issue when a called method has a string parameter with a name containing "uri", "Uri", "urn", "Urn", "url" or "Url" and the declaring type contains a corresponding overload that takes a `System.Uri` as a parameter. - -When there is a choice between two overloads that differ only regarding the representation of a URI, the user should choose the overload that takes a `System.Uri` argument. - + +String representations of URIs or URLs are prone to parsing and encoding errors which can lead to vulnerabilities. The `System.Uri` +class is a safe alternative and should be preferred. + +This rule raises an issue when a called method has a string parameter with a name containing "uri", "Uri", "urn", "Urn", "url" or "Url" and the +declaring type contains a corresponding overload that takes a `System.Uri` as a parameter. + +When there is a choice between two overloads that differ only regarding the representation of a URI, the user should choose the overload that takes +a `System.Uri` argument. + ### Noncompliant code example using System; diff --git a/docs/description/S4015.md b/docs/description/S4015.md index 9acc8eb..8a7b5c3 100644 --- a/docs/description/S4015.md +++ b/docs/description/S4015.md @@ -1,7 +1,8 @@ ## Why is this an issue? - + Decreasing the [accessibility -level](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/access-modifiers) of an inherited method that is not [overridable](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/override) to [private](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/private) will shadow the name of the base method and can lead to confusion. +level](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/access-modifiers) of an inherited method that is not [overridable](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/override) to [private](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/private) will shadow the name of the base method and can +lead to confusion. public class Base { @@ -21,7 +22,8 @@ level](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes } } -Another potential problem is the case of a class deriving from `Derived` and accessing `SomeMethod`. In this scenario, the method accessed will instead be the `Base` implementation, which might not be what was expected. +Another potential problem is the case of a class deriving from `Derived` and accessing `SomeMethod`. In this scenario, the +method accessed will instead be the `Base` implementation, which might not be what was expected. public class Base { @@ -40,7 +42,8 @@ Another potential problem is the case of a class deriving from `Derived` and acc } } -One way to mitigate this, is by sealing the `Derived` class by using the [sealed](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/sealed) modifier, thus preventing inheritance from this point on. +One way to mitigate this, is by sealing the `Derived` class by using the [sealed](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/sealed) modifier, thus preventing inheritance from this +point on. public class Base { @@ -51,7 +54,8 @@ One way to mitigate this, is by sealing the `Derived` class by using the [sealed private void SomeMethod(int count) { } // Compliant: class is marked as sealed } -Another way to mitigate this, is by having the `Derived` implementation match the [accessibility](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/access-modifiers) modifier of the `Base` implementation of `SomeMethod`. From a caller’s perspective, this is closer to the expected behavior. +Another way to mitigate this, is by having the `Derived` implementation match the [accessibility](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/access-modifiers) modifier of the +`Base` implementation of `SomeMethod`. From a caller’s perspective, this is closer to the expected behavior. using System; @@ -76,7 +80,8 @@ Another way to mitigate this, is by having the `Derived` implementation match th } } -Last but not least, consider using a different name for the `Derived` method, thus completely eliminating any confusion caused by the naming collision. +Last but not least, consider using a different name for the `Derived` method, thus completely eliminating any confusion caused by the +naming collision. public class Base { @@ -88,9 +93,9 @@ Last but not least, consider using a different name for the `Derived` method, th } ## Resources - + ### Documentation - + - [Access Modifiers](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/access-modifiers) - [override](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/override) - [sealed](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/sealed) \ No newline at end of file diff --git a/docs/description/S4016.md b/docs/description/S4016.md index ce9727e..41d39ab 100644 --- a/docs/description/S4016.md +++ b/docs/description/S4016.md @@ -1,9 +1,11 @@ ## Why is this an issue? - -If an `enum` member’s name contains the word "reserved" it implies it is not currently used and will be change in the future. However changing an `enum` member is a breaking change and can create significant problems. There is no need to reserve an `enum` member since a new member can be added in the future, and such an addition will usually not be a breaking change. - + +If an `enum` member’s name contains the word "reserved" it implies it is not currently used and will be change in the future. However +changing an `enum` member is a breaking change and can create significant problems. There is no need to reserve an `enum` member +since a new member can be added in the future, and such an addition will usually not be a breaking change. + This rule raises an issue when the name of an enumeration member contains "reserved". - + ### Noncompliant code example using System; diff --git a/docs/description/S4017.md b/docs/description/S4017.md index 6a90e4e..8c3476c 100644 --- a/docs/description/S4017.md +++ b/docs/description/S4017.md @@ -1,7 +1,8 @@ ## Why is this an issue? - -A nested type is a type argument that is also a generic type. Calling a method with such a nested type argument requires complicated and confusing code. It should be avoided as much as possible. - + +A nested type is a type argument that is also a generic type. Calling a method with such a nested type argument requires complicated and confusing +code. It should be avoided as much as possible. + ### Noncompliant code example using System; diff --git a/docs/description/S4018.md b/docs/description/S4018.md index e65f8a4..58fcf31 100644 --- a/docs/description/S4018.md +++ b/docs/description/S4018.md @@ -1,7 +1,8 @@ ## Why is this an issue? - -Type inference enables the call of a generic method without explicitly specifying its type arguments. This is not possible when a parameter type is missing from the argument list. - + +Type inference enables the call of a generic method without explicitly specifying its type arguments. This is not possible when a parameter type is +missing from the argument list. + ### Noncompliant code example using System; diff --git a/docs/description/S4019.md b/docs/description/S4019.md index 186bbaf..579aa56 100644 --- a/docs/description/S4019.md +++ b/docs/description/S4019.md @@ -1,13 +1,14 @@ ## Why is this an issue? - + When a method in a derived class has: - + - the same name as a method in the base class - but types of parameters that are ancestors (for example `string` in the base class and `object` in the derived class) the result is that the base method becomes hidden. - -As shown in the following code snippet, when an instance of the derived class is used, invoking the method with an argument that matches the less derived parameter type will invoke the derived class method instead of the base class method: + +As shown in the following code snippet, when an instance of the derived class is used, invoking the method with an argument that matches the less +derived parameter type will invoke the derived class method instead of the base class method: class BaseClass { @@ -49,14 +50,15 @@ As shown in the following code snippet, when an instance of the derived class is BaseClass derivedAsBase = new DerivedClass(); derivedAsBase.MyMethod("Hello"); // Output: BaseClass: Method(string) -Keep in mind that you cannot fix this issue by using the [new keyword](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/new-modifier) or by marking the method in the base class as `virtual` and overriding it in the `DerivedClass` because the parameter types are different. - +Keep in mind that you cannot fix this issue by using the [new keyword](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/new-modifier) or by marking the method in the base +class as `virtual` and overriding it in the `DerivedClass` because the parameter types are different. + ### Exceptions - + The rule is not raised when the two methods have the same parameter types. - + ## Resources - + ### Documentation - [Knowing diff --git a/docs/description/S4022.md b/docs/description/S4022.md index b745e98..e020190 100644 --- a/docs/description/S4022.md +++ b/docs/description/S4022.md @@ -1,7 +1,8 @@ ## Why is this an issue? - -By default the storage type of an `enum` is `Int32`. In most cases it is not necessary to change this. In particular you will not achieve any performance gain by using a smaller data type (e.g. `Byte`) and may limit future uses. - + +By default the storage type of an `enum` is `Int32`. In most cases it is not necessary to change this. In particular you will +not achieve any performance gain by using a smaller data type (e.g. `Byte`) and may limit future uses. + ### Noncompliant code example using System; diff --git a/docs/description/S4023.md b/docs/description/S4023.md index 356bdc3..c45d0ea 100644 --- a/docs/description/S4023.md +++ b/docs/description/S4023.md @@ -1,19 +1,20 @@ Empty interfaces should be avoided as they do not provide any functional requirements for implementing classes. - + ## Why is this an issue? - -Empty interfaces are either useless or used as a [marker](https://en.wikipedia.org/wiki/Marker_interface_pattern). [Custom attributes](https://learn.microsoft.com/en-us/dotnet/standard/attributes/writing-custom-attributes) are a better alternative to marker interfaces. See the *How to fix it* section for more information. - + +Empty interfaces are either useless or used as a [marker](https://en.wikipedia.org/wiki/Marker_interface_pattern). [Custom attributes](https://learn.microsoft.com/en-us/dotnet/standard/attributes/writing-custom-attributes) are a better alternative to marker +interfaces. See the *How to fix it* section for more information. + ### Exceptions - + This rule doesn’t raise in any of the following cases: - + #### Aggregation of multiple interfaces public interface IAggregate: IComparable, IFormattable { } // Compliant: Aggregates two interfaces #### Generic specialization - + An empty interface with a single base interface is compliant as long as the resulting interface binds a generic parameter or constrains it. // Compliant: Bound to a concrete type @@ -22,24 +23,24 @@ An empty interface with a single base interface is compliant as long as the resu public interface ICreateableEquatable: IEquatable where T: new() { } #### Custom attribute - + An empty interface is compliant if a custom attribute is applied to the interface. [Obsolete] public interface ISorted { } // Compliant: An attribute is applied to the interface declaration ## How to fix it - + Do any of the following to fix the issue: - + - Add members to the interface - Remove the useless interface - Replace the usage as a marker interface with custom attributes ### Code examples - + #### Noncompliant code example - + The empty interface does not add any functionality. public interface IFoo // Noncompliant @@ -48,7 +49,7 @@ The empty interface does not add any functionality. } #### Compliant solution - + Add members to the interface to be compliant. public interface IFoo @@ -57,9 +58,9 @@ Add members to the interface to be compliant. } #### Noncompliant code example - + A typical use case for marker interfaces is doing type inspection via [reflection](https://learn.microsoft.com/en-us/dotnet/framework/reflection-and-codedom/reflection) as shown below. - + The `IIncludeFields` marker interface is used to configure the JSON serialization of an object. // An example marker interface @@ -81,7 +82,8 @@ The `IIncludeFields` marker interface is used to configure the JSON serializatio }; } -The same example can be rewritten using custom attributes. This approach is preferable because it is more fine-grained, allows parameterization, and is more flexible in type hierarchies. +The same example can be rewritten using custom attributes. This approach is preferable because it is more fine-grained, allows parameterization, +and is more flexible in type hierarchies. // A custom attribute used as a marker [AttributeUsage(AttributeTargets.Class)] @@ -105,7 +107,7 @@ The same example can be rewritten using custom attributes. This approach is pref } ## Resources - + ### Documentation - Microsoft Learn - [Interfaces - define behavior for diff --git a/docs/description/S4025.md b/docs/description/S4025.md index c111780..3889484 100644 --- a/docs/description/S4025.md +++ b/docs/description/S4025.md @@ -1,7 +1,8 @@ ## Why is this an issue? - -Having a field in a child class with a name that differs from a parent class' field only by capitalization is sure to cause confusion. Such child class fields should be renamed. - + +Having a field in a child class with a name that differs from a parent class' field only by capitalization is sure to cause confusion. Such child +class fields should be renamed. + ### Noncompliant code example public class Fruit @@ -45,5 +46,6 @@ Or } ### Exceptions - -This rule ignores same-name fields that are `static` in both the parent and child classes. It also ignores `private` parent class fields, but in all other such cases, the child class field should be renamed. \ No newline at end of file + +This rule ignores same-name fields that are `static` in both the parent and child classes. It also ignores `private` parent +class fields, but in all other such cases, the child class field should be renamed. \ No newline at end of file diff --git a/docs/description/S4026.md b/docs/description/S4026.md index da24e05..449e4f5 100644 --- a/docs/description/S4026.md +++ b/docs/description/S4026.md @@ -1,9 +1,11 @@ ## Why is this an issue? - -It is important to inform the `ResourceManager` of the language used to display the resources of the neutral culture for an assembly. This improves lookup performance for the first resource loaded. - -This rule raises an issue when an assembly contains a `ResX`-based resource but does not have the `System.Resources.NeutralResourcesLanguageAttribute` applied to it. - + +It is important to inform the `ResourceManager` of the language used to display the resources of the neutral culture for an assembly. +This improves lookup performance for the first resource loaded. + +This rule raises an issue when an assembly contains a `ResX`-based resource but does not have the +`System.Resources.NeutralResourcesLanguageAttribute` applied to it. + ### Noncompliant code example using System; diff --git a/docs/description/S4027.md b/docs/description/S4027.md index 522b4fa..8b8fbab 100644 --- a/docs/description/S4027.md +++ b/docs/description/S4027.md @@ -1,17 +1,17 @@ ## Why is this an issue? - + Exceptions types should provide the following constructors: - + - `public MyException()` - `public MyException(string)` - `public MyException(string, Exception)` The absence of these constructors can complicate exception handling and limit the information that can be provided when an exception is thrown. - + ## How to fix it - + ### Code examples - + #### Noncompliant code example public class MyException : Exception // Noncompliant: several constructors are missing @@ -41,7 +41,7 @@ The absence of these constructors can complicate exception handling and limit th } ## Resources - + ### Documentation - Microsoft Learn: [How to create diff --git a/docs/description/S4035.md b/docs/description/S4035.md index e3ae986..9f217e2 100644 --- a/docs/description/S4035.md +++ b/docs/description/S4035.md @@ -1,11 +1,15 @@ ## Why is this an issue? - -When a class implements the `IEquatable` interface, it enters a contract that, in effect, states "I know how to compare two instances of type T or any type derived from T for equality.". However if that class is derived, it is very unlikely that the base class will know how to make a meaningful comparison. Therefore that implicit contract is now broken. - -Alternatively `IEqualityComparer` provides a safer interface and is used by collections or `Equals` could be made `virtual`. - -This rule raises an issue when an unsealed, `public` or `protected` class implements `IEquatable` and the `Equals` is neither `virtual` nor `abstract`. - + +When a class implements the `IEquatable` interface, it enters a contract that, in effect, states "I know how to compare two +instances of type T or any type derived from T for equality.". However if that class is derived, it is very unlikely that the base class will know how +to make a meaningful comparison. Therefore that implicit contract is now broken. + +Alternatively `IEqualityComparer` provides a safer interface and is used by collections or `Equals` could be made +`virtual`. + +This rule raises an issue when an unsealed, `public` or `protected` class implements `IEquatable` and the +`Equals` is neither `virtual` nor `abstract`. + ### Noncompliant code example using System; @@ -79,5 +83,5 @@ This rule raises an issue when an unsealed, `public` or `protected` class implem } ## Resources - + [IEqualityComparer<T> Interface](https://msdn.microsoft.com/en-us/library/ms132151%28v=vs.110%29.aspx) \ No newline at end of file diff --git a/docs/description/S4036.md b/docs/description/S4036.md index 4b687af..ba59d47 100644 --- a/docs/description/S4036.md +++ b/docs/description/S4036.md @@ -1,15 +1,17 @@ -When executing an OS command and unless you specify the full path to the executable, then the locations in your application’s `PATH` environment variable will be searched for the executable. That search could leave an opening for an attacker if one of the elements in `PATH` is a directory under his control. - +When executing an OS command and unless you specify the full path to the executable, then the locations in your application’s `PATH` +environment variable will be searched for the executable. That search could leave an opening for an attacker if one of the elements in +`PATH` is a directory under his control. + ## Ask Yourself Whether - + - The directories in the PATH environment variable may be defined by not trusted entities. There is a risk if you answered yes to this question. - + ## Recommended Secure Coding Practices - + Fully qualified/absolute path should be used to specify the OS command to execute. - + ## Sensitive Code Example Process p = new Process(); diff --git a/docs/description/S4039.md b/docs/description/S4039.md index 60a1b9f..df832a2 100644 --- a/docs/description/S4039.md +++ b/docs/description/S4039.md @@ -1,9 +1,12 @@ ## Why is this an issue? - -When a base type explicitly implements a public interface method, that method is only accessible in derived types through a reference to the current instance (namely `this`). If the derived type explicitly overrides that interface method, the base implementation becomes inaccessible. - -This rule raises an issue when an unsealed, externally visible type provides an explicit method implementation of a `public interface` and does not provide an alternate, externally visible method with the same name. - + +When a base type explicitly implements a public interface method, that method is only accessible in derived types through a reference to the +current instance (namely `this`). If the derived type explicitly overrides that interface method, the base implementation becomes +inaccessible. + +This rule raises an issue when an unsealed, externally visible type provides an explicit method implementation of a `public interface` +and does not provide an alternate, externally visible method with the same name. + ### Noncompliant code example public interface IMyInterface @@ -63,5 +66,6 @@ This rule raises an issue when an unsealed, externally visible type provides an } ### Exceptions - -This rule does not report a violation for an explicit implementation of `IDisposable.Dispose` when an externally visible `Close()` or `System.IDisposable.Dispose(Boolean)` method is provided. \ No newline at end of file + +This rule does not report a violation for an explicit implementation of `IDisposable.Dispose` when an externally visible +`Close()` or `System.IDisposable.Dispose(Boolean)` method is provided. \ No newline at end of file diff --git a/docs/description/S4040.md b/docs/description/S4040.md index 7c9db1f..5248df2 100644 --- a/docs/description/S4040.md +++ b/docs/description/S4040.md @@ -1,9 +1,10 @@ ## Why is this an issue? - -Certain characters, once normalized to lowercase, cannot make a round trip. That is, they can not be converted from one locale to another and then accurately restored to their original characters. - + +Certain characters, once normalized to lowercase, cannot make a round trip. That is, they can not be converted from one locale to another and then +accurately restored to their original characters. + It is therefore strongly recommended to normalize characters and strings to uppercase instead. - + ### Noncompliant code example Thread.CurrentThread.CurrentCulture = new CultureInfo("tr-TR"); @@ -20,7 +21,7 @@ It is therefore strongly recommended to normalize characters and strings to uppe var correctRoundtrip = "İ".ToUpperInvariant().ToLower() != "I".ToUpperInvariant().ToLower(); ## Resources - + - [Internationalization for Turkish](http://www.i18nguy.com/unicode/turkish-i18n.html) - [How to correctly normalize strings](https://gingter.org/2018/07/10/how-to-correctly-normalize-strings-and-how-to-compare-them-in-net/) diff --git a/docs/description/S4041.md b/docs/description/S4041.md index a3469f7..e25d987 100644 --- a/docs/description/S4041.md +++ b/docs/description/S4041.md @@ -1,9 +1,11 @@ ## Why is this an issue? - -When a type name matches the name of a publicly defined namespace, for instance one in the .NET framework class library, it leads to confusion and makes the library that much harder to use. - -This rule raises an issue when a name of a public type matches the name of a .NET Framework namespace, or a namespace of the project assembly, in a case-insensitive comparison. - + +When a type name matches the name of a publicly defined namespace, for instance one in the .NET framework class library, it leads to confusion and +makes the library that much harder to use. + +This rule raises an issue when a name of a public type matches the name of a .NET Framework namespace, or a namespace of the project assembly, in a +case-insensitive comparison. + ### Noncompliant code example using System; diff --git a/docs/description/S4047.md b/docs/description/S4047.md index 194e594..78f9d3e 100644 --- a/docs/description/S4047.md +++ b/docs/description/S4047.md @@ -1,9 +1,11 @@ ## Why is this an issue? - -When a reference parameter (keyword `ref`) is used, the passed argument type must exactly match the reference parameter type. This means that to be able to pass a derived type, it must be cast and assigned to a variable of the proper type. Use of generic methods eliminates that cumbersome down casting and should therefore be preferred. - + +When a reference parameter (keyword `ref`) is used, the passed argument type must exactly match the reference parameter type. This means +that to be able to pass a derived type, it must be cast and assigned to a variable of the proper type. Use of generic methods eliminates that +cumbersome down casting and should therefore be preferred. + This rule raises an issue when a method contains a `ref` parameter of type `System.Object`. - + ### Noncompliant code example using System; diff --git a/docs/description/S4049.md b/docs/description/S4049.md index 01ab621..cb15f26 100644 --- a/docs/description/S4049.md +++ b/docs/description/S4049.md @@ -1,9 +1,10 @@ ## Why is this an issue? - + Properties are accessed like fields which makes them easier to use. - -This rule raises an issue when the name of a `public` or `protected` method starts with `Get`, takes no parameter, and returns a value that is not an array. - + +This rule raises an issue when the name of a `public` or `protected` method starts with `Get`, takes no parameter, +and returns a value that is not an array. + ### Noncompliant code example using System; @@ -42,9 +43,9 @@ This rule raises an issue when the name of a `public` or `protected` method star } ### Exceptions - + The rule doesn’t raise an issue when the method: - + - Is a constructor - Is an `override` - Is an interface implementation diff --git a/docs/description/S4050.md b/docs/description/S4050.md index c9b78e4..2e5ca44 100644 --- a/docs/description/S4050.md +++ b/docs/description/S4050.md @@ -1,15 +1,16 @@ ## Why is this an issue? - -When implementing operator overloads, it is very important to make sure that all related operators and methods are consistent in their implementation. - + +When implementing operator overloads, it is very important to make sure that all related operators and methods are consistent in their +implementation. + The following guidelines should be followed: - + - When providing `operator ==` you should also provide `operator !=` and vice-versa. - When providing `operator ==` you should also provide `Equals(Object)` and `GetHashCode()`. - When providing `operator +, -, *, / or %` you should also provide `operator ==`, respecting previous guidelines. This rule raises an issue when any of these guidelines are not followed on publicly-visible type (public, protected or protected internal). - + ### Noncompliant code example using System; diff --git a/docs/description/S4052.md b/docs/description/S4052.md index 95635a7..487603d 100644 --- a/docs/description/S4052.md +++ b/docs/description/S4052.md @@ -1,11 +1,13 @@ ## Why is this an issue? - + With the advent of .NET framework version 2, certain practices have become obsolete. - -In particular, exceptions should now extend `System.Exception` instead of `System.ApplicationException`. Similarly, generic collections should be used instead of the older, non-generic, ones. Finally when creating an XML view, you should not extend `System.Xml.XmlDocument`. - + +In particular, exceptions should now extend `System.Exception` instead of `System.ApplicationException`. Similarly, generic +collections should be used instead of the older, non-generic, ones. Finally when creating an XML view, you should not extend +`System.Xml.XmlDocument`. + This rule raises an issue when an externally visible type extends one of these types: - + - `System.ApplicationException` - `System.Xml.XmlDocument` - `System.Collections.CollectionBase` diff --git a/docs/description/S4055.md b/docs/description/S4055.md index d5b7901..e89c419 100644 --- a/docs/description/S4055.md +++ b/docs/description/S4055.md @@ -1,9 +1,9 @@ ## Why is this an issue? - + String literals embedded in the source code will not be localized properly. - + This rule raises an issue when a literal string is passed as a parameter or property and one or more of the following cases is true: - + - The `LocalizableAttribute` attribute of the parameter or property is set to true. - The parameter or property name contains "Text", "Message", or "Caption". - The name of the string parameter that is passed to a `Console.Write` or `Console.WriteLine` method is either "value" or diff --git a/docs/description/S4056.md b/docs/description/S4056.md index cf3143e..ff7c32c 100644 --- a/docs/description/S4056.md +++ b/docs/description/S4056.md @@ -1,15 +1,19 @@ ## Why is this an issue? - -When a `System.Globalization.CultureInfo` or `IFormatProvider` object is not supplied, the default value that is supplied by the overloaded member might not have the effect that you want in all locales. - + +When a `System.Globalization.CultureInfo` or `IFormatProvider` object is not supplied, the default value that is supplied by +the overloaded member might not have the effect that you want in all locales. + You should supply culture-specific information according to the following guidelines: - + - If the value will be displayed to the user, use the current culture. See `CultureInfo.CurrentCulture`. - If the value will be stored and accessed by software (persisted to a file or database), use the invariant culture. See `CultureInfo.InvariantCulture`. - If you do not know the destination of the value, have the data consumer or provider specify the culture. -This rule raises an issue when a method or constructor calls one or more members that have overloads that accept a `System.IFormatProvider` parameter, and the method or constructor does not call the overload that takes the `IFormatProvider` parameter. This rule ignores calls to .NET Framework methods that are documented as ignoring the `IFormatProvider` parameter as well as the following methods: +This rule raises an issue when a method or constructor calls one or more members that have overloads that accept a +`System.IFormatProvider` parameter, and the method or constructor does not call the overload that takes the `IFormatProvider` +parameter. This rule ignores calls to .NET Framework methods that are documented as ignoring the `IFormatProvider` parameter as well as the +following methods: - `Activator.CreateInstance` - `ResourceManager.GetObject` @@ -54,5 +58,5 @@ This rule raises an issue when a method or constructor calls one or more members } ### Exceptions - + This rule will not raise an issue when the overload is marked as obsolete. \ No newline at end of file diff --git a/docs/description/S4057.md b/docs/description/S4057.md index f51b26e..1f1a5b4 100644 --- a/docs/description/S4057.md +++ b/docs/description/S4057.md @@ -1,9 +1,12 @@ ## Why is this an issue? - -When you create a `DataTable` or `DataSet`, you should set the locale explicitly. By default, the locale for these types is the current culture. For data that is stored in a database or file and is shared globally, the locale should ordinarily be set to the invariant culture (`CultureInfo.InvariantCulture`). - -This rule raises an issue when `System.Data.DataTable` or `System.Data.DataSet` instances are created without explicitly setting the locale property (`DataTable.Locale` or `DataSet.Locale`). - + +When you create a `DataTable` or `DataSet`, you should set the locale explicitly. By default, the locale for these types is +the current culture. For data that is stored in a database or file and is shared globally, the locale should ordinarily be set to the invariant +culture (`CultureInfo.InvariantCulture`). + +This rule raises an issue when `System.Data.DataTable` or `System.Data.DataSet` instances are created without explicitly +setting the locale property (`DataTable.Locale` or `DataSet.Locale`). + ### Noncompliant code example using System; diff --git a/docs/description/S4058.md b/docs/description/S4058.md index 7f3073a..7e56b40 100644 --- a/docs/description/S4058.md +++ b/docs/description/S4058.md @@ -1,9 +1,11 @@ ## Why is this an issue? - -Many string operations, the `Compare` and `Equals` methods in particular, provide an overload that accepts a `StringComparison` enumeration value as a parameter. Calling these overloads and explicitly providing this parameter makes your code clearer and easier to maintain. - + +Many string operations, the `Compare` and `Equals` methods in particular, provide an overload that accepts a +`StringComparison` enumeration value as a parameter. Calling these overloads and explicitly providing this parameter makes your code +clearer and easier to maintain. + This rule raises an issue when a string comparison operation doesn’t use the overload that takes a `StringComparison` parameter. - + ### Noncompliant code example using System; diff --git a/docs/description/S4059.md b/docs/description/S4059.md index 77f34ff..b881902 100644 --- a/docs/description/S4059.md +++ b/docs/description/S4059.md @@ -1,9 +1,10 @@ ## Why is this an issue? - + Properties and Get method should have names that makes them clearly distinguishable. - -This rule raises an issue when the name of a public or protected member starts with 'Get' and otherwise matches the name of a public or protected property. - + +This rule raises an issue when the name of a public or protected member starts with 'Get' and otherwise matches the name of a public or protected +property. + ### Noncompliant code example using System; diff --git a/docs/description/S4060.md b/docs/description/S4060.md index b63d8f7..3733b1a 100644 --- a/docs/description/S4060.md +++ b/docs/description/S4060.md @@ -1,9 +1,10 @@ ## Why is this an issue? - -The .NET framework class library provides methods for retrieving custom attributes. Sealing the attribute eliminates the search through the inheritance hierarchy, and can improve performance. - + +The .NET framework class library provides methods for retrieving custom attributes. Sealing the attribute eliminates the search through the +inheritance hierarchy, and can improve performance. + This rule raises an issue when a public type inherits from `System.Attribute`, is not abstract, and is not sealed. - + ### Noncompliant code example using System; diff --git a/docs/description/S4061.md b/docs/description/S4061.md index 614c479..b80d5b6 100644 --- a/docs/description/S4061.md +++ b/docs/description/S4061.md @@ -1,9 +1,11 @@ ## Why is this an issue? - -A method using the `VarArgs` calling convention is not Common Language Specification (CLS) compliant and might not be accessible across programming languages, while the `params` keyword works the same way and is CLS compliant. - -This rule raises an issue when a `public` or `protected` type contains a `public` or `protected` method that uses the `VarArgs` calling convention. - + +A method using the `VarArgs` calling convention is not Common Language Specification (CLS) compliant and might not be accessible across +programming languages, while the `params` keyword works the same way and is CLS compliant. + +This rule raises an issue when a `public` or `protected` type contains a `public` or `protected` method +that uses the `VarArgs` calling convention. + ### Noncompliant code example using System; @@ -44,7 +46,7 @@ This rule raises an issue when a `public` or `protected` type contains a `public } ### Exceptions - + Interop methods using `VarArgs` calling convention do not raise an issue. [DllImport("msvcrt40.dll")] diff --git a/docs/description/S4069.md b/docs/description/S4069.md index f234feb..f5131d9 100644 --- a/docs/description/S4069.md +++ b/docs/description/S4069.md @@ -1,6 +1,7 @@ ## Why is this an issue? - -Operator overloading is convenient but unfortunately not portable across languages. To be able to access the same functionality from another language you need to provide an alternate named method following the convention: + +Operator overloading is convenient but unfortunately not portable across languages. To be able to access the same functionality from another +language you need to provide an alternate named method following the convention: | Operator | Method Name | | --- | --- | @@ -24,7 +25,8 @@ Operator overloading is convenient but unfortunately not portable across languag | `+` (unary) | Plus | This rule raises an issue when there is an operator overload without the expected named alternative method. - + ### Exceptions - -This rule does not raise an issue when the class implementing the comparison operators `>`, `<`, `>=` and `<=` contains a method named `CompareTo`. \ No newline at end of file + +This rule does not raise an issue when the class implementing the comparison operators `>`, `<`, `>=` and +`<=` contains a method named `CompareTo`. \ No newline at end of file diff --git a/docs/description/S4070.md b/docs/description/S4070.md index 2bcc0b3..2108790 100644 --- a/docs/description/S4070.md +++ b/docs/description/S4070.md @@ -1,7 +1,8 @@ ## Why is this an issue? - -This rule raises an issue when an externally visible enumeration is marked with `FlagsAttribute` and one, or more, of its values is not a power of 2 or a combination of the other defined values. - + +This rule raises an issue when an externally visible enumeration is marked with `FlagsAttribute` and one, or more, of its values is not +a power of 2 or a combination of the other defined values. + ### Noncompliant code example using System; diff --git a/docs/description/S4136.md b/docs/description/S4136.md index cbfde4a..bd201f0 100644 --- a/docs/description/S4136.md +++ b/docs/description/S4136.md @@ -1,7 +1,8 @@ ## Why is this an issue? - -For clarity, all overloads of the same method should be grouped together. That lets both users and maintainers quickly understand all the current available options. - + +For clarity, all overloads of the same method should be grouped together. That lets both users and maintainers quickly understand all the current +available options. + ### Noncompliant code example interface IMyInterface @@ -21,11 +22,13 @@ For clarity, all overloads of the same method should be grouped together. That l } ### Exceptions - -As it is common practice to group method declarations by implemented interface, no issue will be raised for implicit and explicit interface implementations if grouped together with other members of that interface. - -As it is also a common practice to group method declarations by accessibility level, no issue will be raised for method overloads having different access modifiers. - + +As it is common practice to group method declarations by implemented interface, no issue will be raised for implicit and explicit interface +implementations if grouped together with other members of that interface. + +As it is also a common practice to group method declarations by accessibility level, no issue will be raised for method overloads having different +access modifiers. + Example: class MyClass diff --git a/docs/description/S4143.md b/docs/description/S4143.md index 3af9e99..adc6a77 100644 --- a/docs/description/S4143.md +++ b/docs/description/S4143.md @@ -1,6 +1,7 @@ ## Why is this an issue? - -Storing a value inside a collection at a given key or index and then unconditionally overwriting it without reading the initial value is a case of a "dead store". + +Storing a value inside a collection at a given key or index and then unconditionally overwriting it without reading the initial value is a case of +a "dead store". list[index] = "value 1"; list[index] = "value 2"; // Noncompliant @@ -8,4 +9,5 @@ Storing a value inside a collection at a given key or index and then uncondition dictionary.Add(key, "value 1"); dictionary[key] = "value 2"; // Noncompliant -This practice is redundant and will cause confusion for the reader. More importantly, it is often an error and not what the developer intended to do. \ No newline at end of file +This practice is redundant and will cause confusion for the reader. More importantly, it is often an error and not what the developer intended to +do. \ No newline at end of file diff --git a/docs/description/S4144.md b/docs/description/S4144.md index 75e3411..01904ce 100644 --- a/docs/description/S4144.md +++ b/docs/description/S4144.md @@ -1,6 +1,7 @@ ## Why is this an issue? - -Two methods having the same implementation are suspicious. It might be that something else was intended. Or the duplication is intentional, which becomes a maintenance burden. + +Two methods having the same implementation are suspicious. It might be that something else was intended. Or the duplication is intentional, which +becomes a maintenance burden. private const string CODE = "secret"; private int callCount = 0; @@ -17,7 +18,8 @@ Two methods having the same implementation are suspicious. It might be that some return CODE; } -If the identical logic is intentional, the code should be refactored to avoid duplication. For example, by having both methods call the same method or by having one implementation invoke the other. +If the identical logic is intentional, the code should be refactored to avoid duplication. For example, by having both methods call the same method +or by having one implementation invoke the other. private const string CODE = "secret"; private int callCount = 0; @@ -34,5 +36,5 @@ If the identical logic is intentional, the code should be refactored to avoid du } ### Exceptions - + Empty methods, methods with only one line of code and methods with the same name (overload) are ignored. \ No newline at end of file diff --git a/docs/description/S4158.md b/docs/description/S4158.md index e43598c..a1e9a4f 100644 --- a/docs/description/S4158.md +++ b/docs/description/S4158.md @@ -1,11 +1,12 @@ ## Why is this an issue? - -When a collection is empty, iterating it has no effect. Doing so anyway is likely a bug; either population was accidentally omitted, or the iteration needs to be revised. - + +When a collection is empty, iterating it has no effect. Doing so anyway is likely a bug; either population was accidentally omitted, or the +iteration needs to be revised. + ## How to fix it - + ### Code examples - + #### Noncompliant code example public void Method() diff --git a/docs/description/S4159.md b/docs/description/S4159.md index 05f8863..6f17978 100644 --- a/docs/description/S4159.md +++ b/docs/description/S4159.md @@ -1,26 +1,31 @@ ## Why is this an issue? - -The [Attributed Programming Model](https://learn.microsoft.com/en-us/dotnet/framework/mef/attributed-programming-model-overview-mef), also known as [Attribute-oriented programming (@OP)](https://en.wikipedia.org/wiki/Attribute-oriented_programming), is a programming model used to embed attributes within codes. - + +The [Attributed Programming Model](https://learn.microsoft.com/en-us/dotnet/framework/mef/attributed-programming-model-overview-mef), +also known as [Attribute-oriented programming (@OP)](https://en.wikipedia.org/wiki/Attribute-oriented_programming), is a programming model +used to embed attributes within codes. + In this model, objects are required to conform to a specific structure so that they can be used by the [Managed Extensibility Framework (MEF)](https://learn.microsoft.com/en-us/dotnet/framework/mef/). - -MEF provides a way to discover available components implicitly, via **composition**. A MEF component, called a **part**, declaratively specifies: - + +MEF provides a way to discover available components implicitly, via **composition**. A MEF component, called a **part**, +declaratively specifies: + - both its dependencies, known as **imports** - and what capabilities it makes available, known as **exports** -The [ExportAttribute](https://learn.microsoft.com/en-us/dotnet/api/system.composition.exportattribute) declares that a part "exports", or provides to the composition container, an object that fulfills a particular contract. - +The [ExportAttribute](https://learn.microsoft.com/en-us/dotnet/api/system.composition.exportattribute) declares that a part "exports", +or provides to the composition container, an object that fulfills a particular contract. + During composition, parts with imports that have matching contracts will have those dependencies filled by the exported object. - -If the type doesn’t implement the interface it is exporting there will be an issue at runtime (either a cast exception or just a container not filled with the exported type) leading to unexpected behaviors/crashes. - + +If the type doesn’t implement the interface it is exporting there will be an issue at runtime (either a cast exception or just a container not +filled with the exported type) leading to unexpected behaviors/crashes. + The rule raises an issue when a class doesn’t implement or inherit the type declared in the `ExportAttribute`. - + ## How to fix it - + ### Code examples - + #### Noncompliant code example [Export(typeof(ISomeType))] @@ -36,7 +41,7 @@ The rule raises an issue when a class doesn’t implement or inherit the type de } ## Resources - + ### Documentation - [Attribute-oriented programming (@OP)](https://en.wikipedia.org/wiki/Attribute-oriented_programming) diff --git a/docs/description/S4200.md b/docs/description/S4200.md index fb500bb..ba25ae5 100644 --- a/docs/description/S4200.md +++ b/docs/description/S4200.md @@ -1,9 +1,13 @@ ## Why is this an issue? - -Native methods are functions that reside in libraries outside the .NET runtime. Calling them is helpful for interoperability with applications and libraries written in other programming languages, mainly when performing platform-specific operations. However, doing so comes with additional risks since it means stepping out of the memory-safety model of the runtime. It is therefore highly recommended to take extra steps, like input validation, when invoking native methods. Making the native method `private` and providing a wrapper that performs these additional steps is the best way to do so. - + +Native methods are functions that reside in libraries outside the .NET runtime. Calling them is helpful for interoperability with applications and +libraries written in other programming languages, mainly when performing platform-specific operations. However, doing so comes with additional risks +since it means stepping out of the memory-safety model of the runtime. It is therefore highly recommended to take extra steps, like input validation, +when invoking native methods. Making the native method `private` and providing a wrapper that performs these additional steps is the best +way to do so. + This rule raises an issue when a native method is declared `public` or its wrapper is too trivial. - + ### Noncompliant code example using System; diff --git a/docs/description/S4201.md b/docs/description/S4201.md index ed90232..042c33d 100644 --- a/docs/description/S4201.md +++ b/docs/description/S4201.md @@ -1,7 +1,8 @@ ## Why is this an issue? - -There’s no need to null test in conjunction with an `is` test. `null` is not an instance of anything, so a null check is redundant. - + +There’s no need to null test in conjunction with an `is` test. `null` is not an instance of anything, so a null check is +redundant. + ### Noncompliant code example if (x != null && x is MyClass) { ... } // Noncompliant diff --git a/docs/description/S4210.md b/docs/description/S4210.md index f732539..5560d97 100644 --- a/docs/description/S4210.md +++ b/docs/description/S4210.md @@ -1,9 +1,11 @@ ## Why is this an issue? - -When an assembly uses Windows Forms (classes and interfaces from the `System.Windows.Forms` namespace) its entry point should be marked with the `STAThreadAttribute` to indicate that the threading model should be "Single-Threaded Apartment" (STA) which is the only one supported by Windows Forms. - + +When an assembly uses Windows Forms (classes and interfaces from the `System.Windows.Forms` namespace) its entry point should be marked +with the `STAThreadAttribute` to indicate that the threading model should be "Single-Threaded Apartment" (STA) which is the only one +supported by Windows Forms. + This rule raises an issue when the entry point (`static void Main` method) of an assembly using Windows Forms is not marked as STA. - + ### Noncompliant code example using System; diff --git a/docs/description/S4211.md b/docs/description/S4211.md index 16c45ba..bc56035 100644 --- a/docs/description/S4211.md +++ b/docs/description/S4211.md @@ -1,25 +1,30 @@ -Transparency attributes in the .NET Framework, designed to protect security-critical operations, can lead to ambiguities and vulnerabilities when declared at different levels such as both for the class and a method. - +Transparency attributes in the .NET Framework, designed to protect security-critical operations, can lead to ambiguities and vulnerabilities when +declared at different levels such as both for the class and a method. + ## Why is this an issue? - -Transparency attributes can be declared at several levels. If two different attributes are declared at two different levels, the attribute that prevails is the one in the highest level. For example, you can declare that a class is `SecuritySafeCritical` and that a method of this class is `SecurityCritical`. In this case, the method will be `SecuritySafeCritical` and the `SecurityCritical` attribute attached to it is ignored. - + +Transparency attributes can be declared at several levels. If two different attributes are declared at two different levels, the attribute that +prevails is the one in the highest level. For example, you can declare that a class is `SecuritySafeCritical` and that a method of this +class is `SecurityCritical`. In this case, the method will be `SecuritySafeCritical` and the `SecurityCritical` +attribute attached to it is ignored. + ### What is the potential impact? - + Below are some real-world scenarios that illustrate some impacts of an attacker exploiting the vulnerability. - + #### Elevation of Privileges - + An attacker could potentially exploit conflicting transparency attributes to perform actions with higher privileges than intended. - + #### Data Exposure - -If a member with conflicting attributes is involved in handling sensitive data, an attacker could exploit the vulnerability to gain unauthorized access to this data. This could lead to breaches of confidentiality and potential data loss. - + +If a member with conflicting attributes is involved in handling sensitive data, an attacker could exploit the vulnerability to gain unauthorized +access to this data. This could lead to breaches of confidentiality and potential data loss. + ## How to fix it - + ### Code examples - + #### Noncompliant code example using System; @@ -54,17 +59,18 @@ If a member with conflicting attributes is involved in handling sensitive data, } ### How does this work? - + #### Never set class-level annotations - -A class should never have class-level annotations if some functions have different permission levels. Instead, make sure every function has its own correct annotation. - + +A class should never have class-level annotations if some functions have different permission levels. Instead, make sure every function has its own +correct annotation. + If no function needs a particularly distinct security annotation in a class, just set a class-level `[SecurityCritical]`. - + ## Resources - + ### Articles & blog posts - + - Redgate Hub - [What’s New in Code Access Security in .NET Framework 4.0 – Part I](https://www.red-gate.com/simple-talk/development/dotnet-development/whats-new-in-code-access-security-in-net-framework-4-0-part-i/) diff --git a/docs/description/S4212.md b/docs/description/S4212.md index efd6b51..5de5b22 100644 --- a/docs/description/S4212.md +++ b/docs/description/S4212.md @@ -1,11 +1,16 @@ This rule is deprecated, and will eventually be removed. - + ## Why is this an issue? - -Because serialization constructors allocate and initialize objects, security checks that are present on regular constructors must also be present on a serialization constructor. Failure to do so would allow callers that could not otherwise create an instance to use the serialization constructor to do this. - -This rule raises an issue when a type implements the `System.Runtime.Serialization.ISerializable` interface, is not a delegate or interface, is declared in an assembly that allows partially trusted callers and has a constructor that takes a `System.Runtime.Serialization.SerializationInfo` object and a `System.Runtime.Serialization.StreamingContext` object which is not secured by a security check, but one or more of the regular constructors in the type is secured. - + +Because serialization constructors allocate and initialize objects, security checks that are present on regular constructors must also be present +on a serialization constructor. Failure to do so would allow callers that could not otherwise create an instance to use the serialization constructor +to do this. + +This rule raises an issue when a type implements the `System.Runtime.Serialization.ISerializable` interface, is not a delegate or +interface, is declared in an assembly that allows partially trusted callers and has a constructor that takes a +`System.Runtime.Serialization.SerializationInfo` object and a `System.Runtime.Serialization.StreamingContext` object which is +not secured by a security check, but one or more of the regular constructors in the type is secured. + ### Noncompliant code example using System; @@ -78,7 +83,7 @@ This rule raises an issue when a type implements the `System.Runtime.Serializati } ## Resources - + - OWASP - [Top 10 2021 Category A8 - Software and Data Integrity Failures](https://owasp.org/Top10/A08_2021-Software_and_Data_Integrity_Failures/) - OWASP - [Top 10 2017 Category A8 - Insecure diff --git a/docs/description/S4214.md b/docs/description/S4214.md index 3e6b048..b2e3a6f 100644 --- a/docs/description/S4214.md +++ b/docs/description/S4214.md @@ -1,11 +1,12 @@ This rule is deprecated; use {rule:csharpsquid:S4200} instead. - + ## Why is this an issue? - -Methods marked with the `System.Runtime.InteropServices.DllImportAttribute` attribute use Platform Invocation Services to access unmanaged code and should not be exposed. Keeping them private or internal makes sure that their access is controlled and properly managed. - + +Methods marked with the `System.Runtime.InteropServices.DllImportAttribute` attribute use Platform Invocation Services to access +unmanaged code and should not be exposed. Keeping them private or internal makes sure that their access is controlled and properly managed. + This rule raises an issue when a method declared with `DllImport` is public or protected. - + ### Noncompliant code example using System; diff --git a/docs/description/S4220.md b/docs/description/S4220.md index 0f7f7cf..87aaa5c 100644 --- a/docs/description/S4220.md +++ b/docs/description/S4220.md @@ -1,13 +1,14 @@ ## Why is this an issue? - -When raising an event, two arguments are expected by the `EventHandler` delegate: Sender and event-data. There are three guidelines regarding these parameters: - + +When raising an event, two arguments are expected by the `EventHandler` delegate: Sender and event-data. There are three guidelines +regarding these parameters: + - Do not pass `null` as the sender when raising a non-static event. - Do pass `null` as the sender when raising a static event. - Do not pass `null` as the event-data. If no data should be passed, then `EventArgs.Empty` should be used. This rule raises an issue when any of these guidelines is not met. - + ### Noncompliant code example using System; diff --git a/docs/description/S4225.md b/docs/description/S4225.md index 04eae73..584c615 100644 --- a/docs/description/S4225.md +++ b/docs/description/S4225.md @@ -1,7 +1,8 @@ ## Why is this an issue? - -Creating an extension method that extends `object` is not recommended because it makes the method available on *every* type. Extensions should be applied at the most specialized level possible, and that is very unlikely to be `object`. - + +Creating an extension method that extends `object` is not recommended because it makes the method available on *every* type. +Extensions should be applied at the most specialized level possible, and that is very unlikely to be `object`. + ### Noncompliant code example public static class MyExtensions diff --git a/docs/description/S4226.md b/docs/description/S4226.md index c8f69a8..6eea5ab 100644 --- a/docs/description/S4226.md +++ b/docs/description/S4226.md @@ -1,9 +1,9 @@ ## Why is this an issue? - + It makes little sense to create an extension method when it is possible to just add that method to the class itself. - + This rule raises an issue when an extension is declared in the same namespace as the class it is extending. - + ### Noncompliant code example namespace MyLibrary @@ -23,7 +23,7 @@ This rule raises an issue when an extension is declared in the same namespace as } ### Compliant solution - + Using separate namespace: namespace MyLibrary @@ -60,5 +60,5 @@ Merging the method in the class: } ### Exceptions - + - Extension methods added for clases decorated with `System.CodeDom.Compiler.GeneratedCodeAttribute` attribute. \ No newline at end of file diff --git a/docs/description/S4260.md b/docs/description/S4260.md index eedc3e2..469f25e 100644 --- a/docs/description/S4260.md +++ b/docs/description/S4260.md @@ -1,13 +1,16 @@ ## Why is this an issue? - -When creating a custom [Markup Extension](https://learn.microsoft.com/en-us/dotnet/desktop/wpf/advanced/markup-extensions-and-wpf-xaml) that accepts parameters in WPF, the [`ConstructorArgument`](https://learn.microsoft.com/en-us/dotnet/api/system.windows.markup.constructorargumentattribute) markup must be used to identify the discrete properties that match these parameters. However since this is done via a string, the compiler won’t give you any warning in case there are typos. - + +When creating a custom [Markup Extension](https://learn.microsoft.com/en-us/dotnet/desktop/wpf/advanced/markup-extensions-and-wpf-xaml) +that accepts parameters in WPF, the [`ConstructorArgument`](https://learn.microsoft.com/en-us/dotnet/api/system.windows.markup.constructorargumentattribute) markup +must be used to identify the discrete properties that match these parameters. However since this is done via a string, the compiler won’t give you any +warning in case there are typos. + This rule raises an issue when the string argument to `ConstructorArgumentAttribute` doesn’t match any parameter of any constructor. - + ## How to fix it - + ### Code examples - + #### Noncompliant code example using System; @@ -49,9 +52,9 @@ This rule raises an issue when the string argument to `ConstructorArgumentAttrib } ## Resources - + ### Documentation - + - Microsoft Learn - [Markup Extensions and WPF XAML](https://learn.microsoft.com/en-us/dotnet/desktop/wpf/advanced/markup-extensions-and-wpf-xaml) - Microsoft Learn - [MarkupExtension Class](https://learn.microsoft.com/en-us/dotnet/api/system.windows.markup.markupextension) diff --git a/docs/description/S4261.md b/docs/description/S4261.md index 98ccb4c..a9bc130 100644 --- a/docs/description/S4261.md +++ b/docs/description/S4261.md @@ -1,7 +1,9 @@ ## Why is this an issue? - -According to the Task-based Asynchronous Pattern (TAP), methods returning either a `System.Threading.Tasks.Task` or a `System.Threading.Tasks.Task` are considered "asynchronous". Such methods should use the `Async` suffix. Conversely methods which do not return such Tasks should not have an "Async" suffix in their names. - + +According to the Task-based Asynchronous Pattern (TAP), methods returning either a `System.Threading.Tasks.Task` or a +`System.Threading.Tasks.Task` are considered "asynchronous". Such methods should use the `Async` suffix. +Conversely methods which do not return such Tasks should not have an "Async" suffix in their names. + ### Noncompliant code example using System; @@ -32,10 +34,10 @@ According to the Task-based Asynchronous Pattern (TAP), methods returning either } ### Exceptions - + This rule doesn’t raise an issue when the method is an override or part of the implementation of an interface since it can not be renamed. - + ## Resources - + - [Task-based Asynchronous Pattern](https://docs.microsoft.com/en-us/dotnet/standard/asynchronous-programming-patterns/task-based-asynchronous-pattern-tap) \ No newline at end of file diff --git a/docs/description/S4275.md b/docs/description/S4275.md index a8321b8..4532a3c 100644 --- a/docs/description/S4275.md +++ b/docs/description/S4275.md @@ -1,6 +1,8 @@ ## Why is this an issue? - -Properties provide a way to enforce [encapsulation](https://en.wikipedia.org/wiki/Encapsulation_%28computer_programming%29) by providing accessors that give controlled access to `private` fields. However, in classes with multiple fields, it is not unusual that [copy-and-paste](https://en.wikipedia.org/wiki/Copy-and-paste_programming) is used to quickly create the needed properties, which can result in the wrong field being accessed by a getter or setter. + +Properties provide a way to enforce [encapsulation](https://en.wikipedia.org/wiki/Encapsulation_%28computer_programming%29) by providing +accessors that give controlled access to `private` fields. However, in classes with multiple fields, it is not unusual that [copy-and-paste](https://en.wikipedia.org/wiki/Copy-and-paste_programming) is used to quickly create the needed properties, which can result +in the wrong field being accessed by a getter or setter. class C { @@ -10,19 +12,19 @@ Properties provide a way to enforce [encapsulation](https://en.wikipedia.org/wik } This rule raises an issue in any of these cases: - + - A getter does not access the field with the corresponding name. - A setter does not update the field with the corresponding name. For simple properties, it is better to use [auto-implemented properties](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/auto-implemented-properties) (C# 3.0 or later). - + Field and property names are compared as case-insensitive. All underscore characters are ignored. - + ## How to fix it - + ### Code examples - + #### Noncompliant code example class A diff --git a/docs/description/S4277.md b/docs/description/S4277.md index 4f78269..8b8de32 100644 --- a/docs/description/S4277.md +++ b/docs/description/S4277.md @@ -1,13 +1,16 @@ ## Why is this an issue? - -Marking a class with [`PartCreationPolicy`](https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.composition.partcreationpolicyattribute)([`CreationPolicy.Shared`](https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.composition.creationpolicy)), which is part of [Managed Extensibility Framework (MEF)](https://learn.microsoft.com/en-us/dotnet/framework/mef), means that a single, shared instance of the exported object will be created. Therefore it doesn’t make sense to create new instances using the constructor and it will most likely result in unexpected behaviours. - + +Marking a class with [`PartCreationPolicy`](https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.composition.partcreationpolicyattribute)([`CreationPolicy.Shared`](https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.composition.creationpolicy)), which is +part of [Managed Extensibility Framework (MEF)](https://learn.microsoft.com/en-us/dotnet/framework/mef), means that a single, shared +instance of the exported object will be created. Therefore it doesn’t make sense to create new instances using the constructor and it will most likely +result in unexpected behaviours. + This rule raises an issue when a constructor of a class marked shared with a `PartCreationPolicyAttribute` is invoked. - + ## How to fix it - + ### Code examples - + #### Noncompliant code example [Export(typeof(IFooBar))] @@ -41,9 +44,9 @@ This rule raises an issue when a constructor of a class marked shared with a `Pa } ## Resources - + ### Documentation - + - [`PartCreationPolicy`](https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.composition.partcreationpolicyattribute) - [`CreationPolicy.Shared`](https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.composition.creationpolicy) - [Managed Extensibility Framework](https://learn.microsoft.com/en-us/dotnet/framework/mef) \ No newline at end of file diff --git a/docs/description/S4347.md b/docs/description/S4347.md new file mode 100644 index 0000000..8b5b8ad --- /dev/null +++ b/docs/description/S4347.md @@ -0,0 +1,177 @@ +Cryptographic operations often rely on unpredictable random numbers to enhance security. These random numbers are created by cryptographically +secure pseudo-random number generators (CSPRNG). It is important not to use a predictable seed with these random number generators otherwise the +random numbers will also become predictable. + +## Why is this an issue? + +Random number generators are often used to generate random values for cryptographic algorithms. When a random number generator is used for +cryptographic purposes, the generated numbers must be as random and unpredictable as possible. When the random number generator is improperly seeded +with a constant or a predictable value, its output will also be predictable. + +This can have severe security implications for cryptographic operations that rely on the randomness of the generated numbers. By using a +predictable seed, an attacker can potentially guess or deduce the generated numbers, compromising the security of whatever cryptographic algorithm +relies on the random number generator. + +### What is the potential impact? + +It is crucial to understand that the strength of cryptographic algorithms heavily relies on the quality of the random numbers used. By improperly +seeding a CSPRNG, we introduce a significant weakness that can be exploited by attackers. + +#### Insecure cryptographic keys + +One of the primary use cases for CSPRNGs is generating cryptographic keys. If an attacker can predict the seed used to initialize the random number +generator, they may be able to derive the same keys. Depending on the use case, this can lead to multiple severe outcomes, such as: + +- Being able to decrypt sensitive documents, leading to privacy breaches or identity theft. +- Gaining access to a private key used for signing, allowing an attacker to forge digital signatures and impersonate legitimate entities. +- Bypassing authentication mechanisms that rely on public-key infrastructure (PKI), which can be abused to gain unauthorized access to systems or + networks. + +#### Session hijacking and man-in-the-middle attack + +Another scenario where this vulnerability can be exploited is in the generation of session tokens or nonces for secure communication protocols. If +an attacker can predict the seed used to generate these tokens, they can impersonate legitimate users or intercept sensitive information. + +## How to fix it in BouncyCastle + +BouncyCastle provides several random number generators implementations. Most of these will automatically create unpredictable output. + +The remaining random number generators require seeding with an unpredictable value before they will produce unpredictable outputs. These should be +seeded with at least 16 bytes of random data to ensure unpredictable output and that the random seed cannot be guessed using a brute-force attack. + +### Code examples + +#### Noncompliant code example + +`SecureRandom` instances created with `GetInstance()` are seeded by default. Disabling seeding results in predictable +output. + + using Org.BouncyCastle.Security; + + byte[] random = new byte[8]; + + SecureRandom sr = SecureRandom.GetInstance("SHA256PRNG", false); + sr.NextBytes(random); // Noncompliant + +`DigestRandomGenerator` and `VmpcRandomGenerator` instances require seeding before use. Predictable seed values will result +in predictable outputs. + + using Org.BouncyCastle.Crypto.Digest; + using Org.BouncyCastle.Crypto.Prng; + + byte[] random = new byte[8]; + + IRandomGenerator digest = new DigestRandomGenerator(new Sha256Digest()); + digest.AddSeedMaterial(Encoding.UTF8.GetBytes("predictable seed value")); + digest.NextBytes(random); // Noncompliant + + IRandomGenerator vmpc = new VmpcRandomGenerator(); + vmpc.AddSeedMaterial(Convert.FromBase64String("2hq9pkyqLQJkrYTrEv1eNw==")); + vmpc.NextBytes(random); // Noncompliant + +When a `SecureRandom` is created using an unseeded `DigestRandomGenerator` and `VmpcRandomGenerator` instance, the +`SecureRandom` will create predictable outputs. + + using Org.BouncyCastle.Crypto.Digest; + using Org.BouncyCastle.Crypto.Prng; + using Org.BouncyCastle.Security; + + byte[] random = new byte[8]; + + IRandomGenerator digest = new DigestRandomGenerator(new Sha256Digest()); + SecureRandom sr = new SecureRandom(digest); + sr.NextBytes(random); // Noncompliant + +#### Compliant solution + +Allow `SecureRandom.GetInstance()` to automatically seed new `SecureRandom` instances. + + using Org.BouncyCastle.Security; + + byte[] random = new byte[8]; + + SecureRandom sr = SecureRandom.GetInstance("SHA256PRNG"); + sr.NextBytes(random); + +Use unpredictable values to seed `DigestRandomGenerator` and `VmpcRandomGenerator` instances. The +`SecureRandom.GenerateSeed()` method is designed for this purpose. + + using Org.BouncyCastle.Crypto.Digest; + using Org.BouncyCastle.Crypto.Prng; + using Org.BouncyCastle.Security; + + byte[] random = new byte[8]; + + IRandomGenerator digest = new DigestRandomGenerator(new Sha256Digest()); + digest.AddSeedMaterial(SecureRandom.GenerateSeed(16)); + digest.NextBytes(random); + + IRandomGenerator vmpc = new VmpcRandomGenerator(); + vmpc.AddSeedMaterial(SecureRandom.GenerateSeed(16)); + vmpc.NextBytes(random); + +An overload of the `SecureRandom` constructor will automatically seed the underlying `IRandomGenerator` with an unpredictable +value. + + using Org.BouncyCastle.Crypto.Digest; + using Org.BouncyCastle.Crypto.Prng; + using Org.BouncyCastle.Security; + + byte[] random = new byte[8]; + + IRandomGenerator digest = new DigestRandomGenerator(new Sha256Digest()); + SecureRandom sr = new SecureRandom(digest, 16); + sr.NextBytes(random); + +## Resources + +### Documentation + +- Bouncy Castle - [The BouncyCastle.NET User Guide](https://downloads.bouncycastle.org/csharp/docs/BC-CSharpDotNet-UserGuide.pdf) + +### Standards + +- OWASP - [Top 10 2021 Category A2 - Cryptographic Failures](https://owasp.org/Top10/A02_2021-Cryptographic_Failures/) +- OWASP - [Top 10 2017 Category A6 - Security + Misconfiguration](https://owasp.org/www-project-top-ten/2017/A6_2017-Security_Misconfiguration) +- CWE - [CWE-330 - Use of Insufficiently Random Values](https://cwe.mitre.org/data/definitions/330) +- CWE - [CWE-332 - Insufficient Entropy in PRNG](https://cwe.mitre.org/data/definitions/332) +- CWE - [CWE-336 - Same Seed in Pseudo-Random Number Generator (PRNG)](https://cwe.mitre.org/data/definitions/336) +- CWE - [CWE-337 - Predictable Seed in Pseudo-Random Number Generator (PRNG)](https://cwe.mitre.org/data/definitions/337) +- [CERT, MSC63J.](https://wiki.sei.cmu.edu/confluence/display/java/MSC63-J.+Ensure+that+SecureRandom+is+properly+seeded) - Ensure that + SecureRandom is properly seeded + +## Implementation Specification + +(visible only on this page) + +### Message + +When the random number generator’s output **is not** predictable by default: + +> +> +> Change this seed value to something unpredictable, or remove the seed. +> + +When the random number generator’s output **is** predictable by default: + +> +> +> Set an unpredictable seed before generating random values. +> + +### Highlighting + +When the random number generator’s output **is not** predictable by default: + +- The most recent function call that sets a seed. For example: + - The factory method that returns the RNG, where the seed is passed as a parameter. + - The RNG constructor, where the seed is a parameter. + - The function call on the RNG that sets the seed. + +When the random number generator’s output **is** predictable by default: + +- The function call on the RNG that returns a random value. + +If the factory method or constructor is not already highlighted, it should become a secondary highlight. \ No newline at end of file diff --git a/docs/description/S4423.md b/docs/description/S4423.md index 584a1d9..c31dba7 100644 --- a/docs/description/S4423.md +++ b/docs/description/S4423.md @@ -1,9 +1,10 @@ This vulnerability exposes encrypted data to a number of attacks whose goal is to recover the plaintext. - + ## Why is this an issue? - -Encryption algorithms are essential for protecting sensitive information and ensuring secure communications in a variety of domains. They are used for several important reasons: - + +Encryption algorithms are essential for protecting sensitive information and ensuring secure communications in a variety of domains. They are used +for several important reasons: + - Confidentiality, privacy, and intellectual property protection - Security during transmission or on storage devices - Data integrity, general trust, and authentication @@ -13,46 +14,55 @@ When selecting encryption algorithms, tools, or combinations, you should also co 1. No encryption is unbreakable. 2. The strength of an encryption algorithm is usually measured by the effort required to crack it within a reasonable time frame. -For these reasons, as soon as cryptography is included in a project, it is important to choose encryption algorithms that are considered strong and secure by the cryptography community. - -To provide communication security over a network, SSL and TLS are generally used. However, it is important to note that the following protocols are all considered weak by the cryptographic community, and are officially deprecated: +For these reasons, as soon as cryptography is included in a project, it is important to choose encryption algorithms that are considered strong and +secure by the cryptography community. + +To provide communication security over a network, SSL and TLS are generally used. However, it is important to note that the following protocols are +all considered weak by the cryptographic community, and are officially deprecated: - SSL versions 1.0, 2.0 and 3.0 - TLS versions 1.0 and 1.1 -When these unsecured protocols are used, it is best practice to expect a breach: that a user or organization with malicious intent will perform mathematical attacks on this data after obtaining it by other means. - +When these unsecured protocols are used, it is best practice to expect a breach: that a user or organization with malicious intent will perform +mathematical attacks on this data after obtaining it by other means. + ### What is the potential impact? - -After retrieving encrypted data and performing cryptographic attacks on it on a given timeframe, attackers can recover the plaintext that encryption was supposed to protect. - + +After retrieving encrypted data and performing cryptographic attacks on it on a given timeframe, attackers can recover the plaintext that +encryption was supposed to protect. + Depending on the recovered data, the impact may vary. - + Below are some real-world scenarios that illustrate the potential impact of an attacker exploiting the vulnerability. - + #### Additional attack surface - -By modifying the plaintext of the encrypted message, an attacker may be able to trigger additional vulnerabilities in the code. An attacker can further exploit a system to obtain more information. - Encrypted values are often considered trustworthy because it would not be possible for a third party to modify them under normal circumstances. - + +By modifying the plaintext of the encrypted message, an attacker may be able to trigger additional vulnerabilities in the code. An attacker can +further exploit a system to obtain more information. + Encrypted values are often considered trustworthy because it would not be possible for a +third party to modify them under normal circumstances. + #### Breach of confidentiality and privacy - -When encrypted data contains personal or sensitive information, its retrieval by an attacker can lead to privacy violations, identity theft, financial loss, reputational damage, or unauthorized access to confidential systems. - + +When encrypted data contains personal or sensitive information, its retrieval by an attacker can lead to privacy violations, identity theft, +financial loss, reputational damage, or unauthorized access to confidential systems. + In this scenario, the company, its employees, users, and partners could be seriously affected. - -The impact is twofold, as data breaches and exposure of encrypted data can undermine trust in the organization, as customers, clients and stakeholders may lose confidence in the organization’s ability to protect their sensitive data. - + +The impact is twofold, as data breaches and exposure of encrypted data can undermine trust in the organization, as customers, clients and +stakeholders may lose confidence in the organization’s ability to protect their sensitive data. + #### Legal and compliance issues - -In many industries and locations, there are legal and compliance requirements to protect sensitive data. If encrypted data is compromised and the plaintext can be recovered, companies face legal consequences, penalties, or violations of privacy laws. - + +In many industries and locations, there are legal and compliance requirements to protect sensitive data. If encrypted data is compromised and the +plaintext can be recovered, companies face legal consequences, penalties, or violations of privacy laws. + ## How to fix it in .NET - + ### Code examples - + #### Noncompliant code example - + These samples use TLSv1.0 as the default TLS algorithm, which is cryptographically weak. using System.Net; @@ -94,23 +104,27 @@ These samples use TLSv1.0 as the default TLS algorithm, which is cryptographical } ### How does this work? - -As a rule of thumb, by default you should use the cryptographic algorithms and mechanisms that are considered strong by the cryptographic community. - + +As a rule of thumb, by default you should use the cryptographic algorithms and mechanisms that are considered strong by the cryptographic +community. + The best choices at the moment are the following. - + #### Use TLS v1.2 or TLS v1.3 - -Even though TLS V1.3 is available, using TLS v1.2 is still considered good and secure practice by the cryptography community. - -The use of TLS v1.2 ensures compatibility with a wide range of platforms and enables seamless communication between different systems that do not yet have TLS v1.3 support. - -The only drawback depends on whether the framework used is outdated: its TLS v1.2 settings may enable older and insecure cipher suites that are deprecated as insecure. - -On the other hand, TLS v1.3 removes support for older and weaker cryptographic algorithms, eliminates known vulnerabilities from previous TLS versions, and improves performance. - + +Even though TLS V1.3 is available, using TLS v1.2 is still considered good and secure practice by the cryptography community. + +The use of TLS v1.2 ensures compatibility with a wide range of platforms and enables seamless communication between different systems that do not +yet have TLS v1.3 support. + +The only drawback depends on whether the framework used is outdated: its TLS v1.2 settings may enable older and insecure cipher suites that are +deprecated as insecure. + +On the other hand, TLS v1.3 removes support for older and weaker cryptographic algorithms, eliminates known vulnerabilities from previous TLS +versions, and improves performance. + ## Resources - + ### Articles & blog posts - [Wikipedia, Padding Oracle Attack](https://en.wikipedia.org/wiki/Padding_oracle_attack) diff --git a/docs/description/S4426.md b/docs/description/S4426.md index ca716d1..97dd231 100644 --- a/docs/description/S4426.md +++ b/docs/description/S4426.md @@ -1,9 +1,10 @@ This vulnerability exposes encrypted data to attacks whose goal is to recover the plaintext. - + ## Why is this an issue? - -Encryption algorithms are essential for protecting sensitive information and ensuring secure communications in a variety of domains. They are used for several important reasons: - + +Encryption algorithms are essential for protecting sensitive information and ensuring secure communications in a variety of domains. They are used +for several important reasons: + - Confidentiality, privacy, and intellectual property protection - Security during transmission or on storage devices - Data integrity, general trust, and authentication @@ -14,7 +15,7 @@ When selecting encryption algorithms, tools, or combinations, you should also co 2. The strength of an encryption algorithm is usually measured by the effort required to crack it within a reasonable time frame. In today’s cryptography, the length of the **key** directly affects the security level of cryptographic algorithms. - + Note that depending on the algorithm, the term **key** refers to a different mathematical property. For example: - For RSA, the key is the product of two large prime numbers, also called the **modulus**. @@ -22,46 +23,56 @@ Note that depending on the algorithm, the term **key** refers to a different mat - In some cases, AES keys are derived from a master key or a passphrase using a Key Derivation Function (KDF) like PBKDF2 (Password-Based Key Derivation Function 2) -If an application uses a key that is considered short and **insecure**, the encrypted data is exposed to attacks aimed at getting at the plaintext. - -In general, it is best practice to expect a breach: that a user or organization with malicious intent will perform cryptographic attacks on this data after obtaining it by other means. - +If an application uses a key that is considered short and **insecure**, the encrypted data is exposed to attacks aimed at getting at +the plaintext. + +In general, it is best practice to expect a breach: that a user or organization with malicious intent will perform cryptographic attacks on this +data after obtaining it by other means. + ### What is the potential impact? - -After retrieving encrypted data and performing cryptographic attacks on it on a given timeframe, attackers can recover the plaintext that encryption was supposed to protect. - + +After retrieving encrypted data and performing cryptographic attacks on it on a given timeframe, attackers can recover the plaintext that +encryption was supposed to protect. + Depending on the recovered data, the impact may vary. - + Below are some real-world scenarios that illustrate the potential impact of an attacker exploiting the vulnerability. - + #### Additional attack surface - -By modifying the plaintext of the encrypted message, an attacker may be able to trigger additional vulnerabilities in the code. An attacker can further exploit a system to obtain more information. - Encrypted values are often considered trustworthy because it would not be possible for a third party to modify them under normal circumstances. - + +By modifying the plaintext of the encrypted message, an attacker may be able to trigger additional vulnerabilities in the code. An attacker can +further exploit a system to obtain more information. + Encrypted values are often considered trustworthy because it would not be possible for a +third party to modify them under normal circumstances. + #### Breach of confidentiality and privacy - -When encrypted data contains personal or sensitive information, its retrieval by an attacker can lead to privacy violations, identity theft, financial loss, reputational damage, or unauthorized access to confidential systems. - + +When encrypted data contains personal or sensitive information, its retrieval by an attacker can lead to privacy violations, identity theft, +financial loss, reputational damage, or unauthorized access to confidential systems. + In this scenario, the company, its employees, users, and partners could be seriously affected. - -The impact is twofold, as data breaches and exposure of encrypted data can undermine trust in the organization, as customers, clients and stakeholders may lose confidence in the organization’s ability to protect their sensitive data. - + +The impact is twofold, as data breaches and exposure of encrypted data can undermine trust in the organization, as customers, clients and +stakeholders may lose confidence in the organization’s ability to protect their sensitive data. + #### Legal and compliance issues - -In many industries and locations, there are legal and compliance requirements to protect sensitive data. If encrypted data is compromised and the plaintext can be recovered, companies face legal consequences, penalties, or violations of privacy laws. - + +In many industries and locations, there are legal and compliance requirements to protect sensitive data. If encrypted data is compromised and the +plaintext can be recovered, companies face legal consequences, penalties, or violations of privacy laws. + ## How to fix it in .NET - + ### Code examples - -The following code examples either explicitly or implicitly generate keys. Note that there are differences in the size of the keys depending on the algorithm. - + +The following code examples either explicitly or implicitly generate keys. Note that there are differences in the size of the keys depending on the +algorithm. + Due to the mathematical properties of the algorithms, the security requirements for the key size vary depending on the algorithm. - For example, a 256-bit ECC key provides about the same level of security as a 3072-bit RSA key and a 128-bit symmetric key. - + For example, +a 256-bit ECC key provides about the same level of security as a 3072-bit RSA key and a 128-bit symmetric key. + #### Noncompliant code example - + Here is an example of a private key generation with RSA: using System; @@ -82,7 +93,8 @@ Here is an example of a key generation with the Digital Signature Algorithm (DSA var DsaCsp = new DSACryptoServiceProvider(); // Noncompliant } -Here is an example of an Elliptic Curve (EC) initialization. It implicitly generates a private key whose size is indicated in the elliptic curve name: +Here is an example of an Elliptic Curve (EC) initialization. It implicitly generates a private key whose size is indicated in the elliptic curve +name: using System; using System.Security.Cryptography; @@ -119,31 +131,37 @@ Here is an example of an Elliptic Curve (EC) initialization. It implicitly gener } ### How does this work? - + As a rule of thumb, use the cryptographic algorithms and mechanisms that are considered strong by the cryptography community. - + The appropriate choices are the following. - + #### RSA (Rivest-Shamir-Adleman) and DSA (Digital Signature Algorithm) - + The security of these algorithms depends on the difficulty of attacks attempting to solve their underlying mathematical problem. - -In general, a minimum key size of **2048** bits is recommended for both. It provides 112 bits of security. A key length of **3072** or **4092** should be preferred when possible. - + +In general, a minimum key size of **2048** bits is recommended for both. It provides 112 bits of security. A key length of +**3072** or **4092** should be preferred when possible. + #### AES (Advanced Encryption Standard) - -AES supports three key sizes: 128 bits, 192 bits and 256 bits. The security of the AES algorithm is based on the computational complexity of trying all possible keys. - A larger key size increases the number of possible keys and makes exhaustive search attacks computationally infeasible. Therefore, a 256-bit key provides a higher level of security than a 128-bit or 192-bit key. - + +AES supports three key sizes: 128 bits, 192 bits and 256 bits. The security of the AES algorithm is based on the computational complexity of trying +all possible keys. + A larger key size increases the number of possible keys and makes exhaustive search attacks computationally infeasible. +Therefore, a 256-bit key provides a higher level of security than a 128-bit or 192-bit key. + Currently, a minimum key size of **128 bits** is recommended for AES. - + #### Elliptic Curve Cryptography (ECC) - -Elliptic curve cryptography is also used in various algorithms, such as ECDSA, ECDH, or ECMQV. The length of keys generated with elliptic curve algorithms is mentioned directly in their names. For example, `secp256k1` generates a 256-bits long private key. - + +Elliptic curve cryptography is also used in various algorithms, such as ECDSA, ECDH, or ECMQV. The length of keys generated with elliptic curve +algorithms is mentioned directly in their names. For example, `secp256k1` generates a 256-bits long private key. + Currently, a minimum key size of **224 bits** is recommended for EC-based algorithms. - -Additionally, some curves that theoretically provide sufficiently long keys are still discouraged. This can be because of a flaw in the curve parameters, a bad overall design, or poor performance. It is generally advised to use a NIST-approved elliptic curve wherever possible. Such curves currently include: + +Additionally, some curves that theoretically provide sufficiently long keys are still discouraged. This can be because of a flaw in the curve +parameters, a bad overall design, or poor performance. It is generally advised to use a NIST-approved elliptic curve wherever possible. Such curves +currently include: - NIST P curves with a size of at least 224 bits, e.g. secp256r1. - Curve25519, generally known as ed25519 or x25519 depending on its application. @@ -151,9 +169,9 @@ Additionally, some curves that theoretically provide sufficiently long keys are - Brainpool curves with a size of at least 224 bits, e.g. brainpoolP224r1 ### Pitfalls - + #### The KeySize Property is not a setter - + The following code is invalid: ---- @@ -161,20 +179,24 @@ The following code is invalid: RsaCsp.KeySize = 2048; ---- -The KeySize property of CryptoServiceProviders cannot be updated because the setter simply does not exist. This means that this line will not perform any update on `KeySize`, and the compiler won’t raise an Exception when compiling it. This should not be considered a workaround. +The KeySize property of CryptoServiceProviders cannot be updated because the setter simply does not exist. This means that this line will not +perform any update on `KeySize`, and the compiler won’t raise an Exception when compiling it. This should not be considered a +workaround. To change the key size, use one of the overloaded constructors with the desired key size instead. - + ### Going the extra mile - + #### Pre-Quantum Cryptography - + Encrypted data and communications recorded today could be decrypted in the future by an attack from a quantum computer. - It is important to keep in mind that NIST-approved digital signature schemes, key agreement, and key transport may need to be replaced with secure quantum-resistant (or "post-quantum") counterpart. - + It is important to keep +in mind that NIST-approved digital signature schemes, key agreement, and key transport may need to be replaced with secure quantum-resistant (or +"post-quantum") counterpart. + Thus, if data is to remain secure beyond 2030, proactive measures should be taken now to ensure its safety. - + [Learn more here](https://www.enisa.europa.eu/publications/post-quantum-cryptography-current-state-and-quantum-mitigation). - + ## Resources - Documentation diff --git a/docs/description/S4428.md b/docs/description/S4428.md index a28455f..aa4254a 100644 --- a/docs/description/S4428.md +++ b/docs/description/S4428.md @@ -1,14 +1,17 @@ ## Why is this an issue? - + To customize the default behavior for an export in the [Managed Extensibility -Framework](https://learn.microsoft.com/en-us/dotnet/framework/mef/) (MEF), applying the [`PartCreationPolicyAttribute`](https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.composition.partcreationpolicyattribute) is necessary. For the [`PartCreationPolicyAttribute`](https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.composition.partcreationpolicyattribute) to be meaningful in the context of an export, the class must also be annotated with the [`ExportAttribute`](https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.composition.exportattribute). - -This rule raises an issue when a class is annotated with the `PartCreationPolicyAttribute` but not with the `ExportAttribute`. - +Framework](https://learn.microsoft.com/en-us/dotnet/framework/mef/) (MEF), applying the [`PartCreationPolicyAttribute`](https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.composition.partcreationpolicyattribute) +is necessary. For the [`PartCreationPolicyAttribute`](https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.composition.partcreationpolicyattribute) +to be meaningful in the context of an export, the class must also be annotated with the [`ExportAttribute`](https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.composition.exportattribute). + +This rule raises an issue when a class is annotated with the `PartCreationPolicyAttribute` but not with the +`ExportAttribute`. + ## How to fix it - + ### Code examples - + #### Noncompliant code example using System.ComponentModel.Composition; @@ -25,9 +28,9 @@ This rule raises an issue when a class is annotated with the `PartCreationPolicy public class FooBar : IFooBar { } ## Resources - + ### Documentation - + - Microsoft Learn - [Managed Extensibility Framework (MEF)](https://learn.microsoft.com/en-us/dotnet/framework/mef/) - Microsoft Learn - [Attributed programming model overview (MEF)](https://learn.microsoft.com/en-us/dotnet/framework/mef/attributed-programming-model-overview-mef) diff --git a/docs/description/S4433.md b/docs/description/S4433.md index ff42647..5053b1f 100644 --- a/docs/description/S4433.md +++ b/docs/description/S4433.md @@ -1,39 +1,50 @@ -Lightweight Directory Access Protocol (LDAP) servers provide two main authentication methods: the *SASL* and *Simple* ones. The *Simple Authentication* method also breaks down into three different mechanisms: - +Lightweight Directory Access Protocol (LDAP) servers provide two main authentication methods: the *SASL* and *Simple* ones. The +*Simple Authentication* method also breaks down into three different mechanisms: + - *Anonymous* Authentication - *Unauthenticated* Authentication - *Name/Password* Authentication -A server that accepts either the *Anonymous* or *Unauthenticated* mechanisms will accept connections from clients not providing credentials. - +A server that accepts either the *Anonymous* or *Unauthenticated* mechanisms will accept connections from clients not providing +credentials. + ## Why is this an issue? - -When configured to accept the Anonymous or Unauthenticated authentication mechanism, an LDAP server will accept connections from clients that do not provide a password or other authentication credentials. Such users will be able to read or modify part or all of the data contained in the hosted directory. - + +When configured to accept the Anonymous or Unauthenticated authentication mechanism, an LDAP server will accept connections from clients that do +not provide a password or other authentication credentials. Such users will be able to read or modify part or all of the data contained in the hosted +directory. + ### What is the potential impact? - -An attacker exploiting unauthenticated access to an LDAP server can access the data that is stored in the corresponding directory. The impact varies depending on the permission obtained on the directory and the type of data it stores. - + +An attacker exploiting unauthenticated access to an LDAP server can access the data that is stored in the corresponding directory. The impact +varies depending on the permission obtained on the directory and the type of data it stores. + #### Authentication bypass - -If attackers get write access to the directory, they will be able to alter most of the data it stores. This might include sensitive technical data such as user passwords or asset configurations. Such an attack can typically lead to an authentication bypass on applications and systems that use the affected directory as an identity provider. - + +If attackers get write access to the directory, they will be able to alter most of the data it stores. This might include sensitive technical data +such as user passwords or asset configurations. Such an attack can typically lead to an authentication bypass on applications and systems that use the +affected directory as an identity provider. + In such a case, all users configured in the directory might see their identity and privileges taken over. - + #### Sensitive information leak - -If attackers get read-only access to the directory, they will be able to read the data it stores. That data might include security-sensitive pieces of information. - -Typically, attackers might get access to user account lists that they can use in further intrusion steps. For example, they could use such lists to perform password spraying, or related attacks, on all systems that rely on the affected directory as an identity provider. - -If the directory contains some Personally Identifiable Information, an attacker accessing it might represent a violation of regulatory requirements in some countries. For example, this kind of security event would go against the European GDPR law. - + +If attackers get read-only access to the directory, they will be able to read the data it stores. That data might include security-sensitive pieces +of information. + +Typically, attackers might get access to user account lists that they can use in further intrusion steps. For example, they could use such lists to +perform password spraying, or related attacks, on all systems that rely on the affected directory as an identity provider. + +If the directory contains some Personally Identifiable Information, an attacker accessing it might represent a violation of regulatory requirements +in some countries. For example, this kind of security event would go against the European GDPR law. + ## How to fix it - + ### Code examples - -The following code indicates an anonymous LDAP authentication vulnerability because it binds to a remote server using an Anonymous Simple authentication mechanism. - + +The following code indicates an anonymous LDAP authentication vulnerability because it binds to a remote server using an Anonymous Simple +authentication mechanism. + #### Noncompliant code example DirectoryEntry myDirectoryEntry = new DirectoryEntry(adPath); @@ -48,7 +59,7 @@ The following code indicates an anonymous LDAP authentication vulnerability beca DirectoryEntry myDirectoryEntry = new DirectoryEntry(myADSPath, "u", "p", AuthenticationTypes.Secure); ## Resources - + ### Documentation - [RFC 4513 - Lightweight Directory Access Protocol (LDAP): Authentication diff --git a/docs/description/S4456.md b/docs/description/S4456.md index 01fe2a5..bdf4042 100644 --- a/docs/description/S4456.md +++ b/docs/description/S4456.md @@ -1,11 +1,14 @@ ## Why is this an issue? - -Because of the way `yield` methods are rewritten by the compiler (they become lazily evaluated state machines) any exceptions thrown during the parameters check will happen only when the collection is iterated over. That could happen far away from the source of the buggy code. - -Therefore it is recommended to split the method into two: an outer method handling the validation (no longer lazy) and an inner (lazy) method to handle the iteration. - -This rule raises an issue when a method throws any exception derived from `ArgumentException` and contains the `yield` keyword. - + +Because of the way `yield` methods are rewritten by the compiler (they become lazily evaluated state machines) any exceptions thrown +during the parameters check will happen only when the collection is iterated over. That could happen far away from the source of the buggy code. + +Therefore it is recommended to split the method into two: an outer method handling the validation (no longer lazy) and an inner (lazy) method to +handle the iteration. + +This rule raises an issue when a method throws any exception derived from `ArgumentException` and contains the `yield` +keyword. + ### Noncompliant code example public static IEnumerable TakeWhile(this IEnumerable source, Func predicate) // Noncompliant diff --git a/docs/description/S4457.md b/docs/description/S4457.md index 2d3572e..f4828b3 100644 --- a/docs/description/S4457.md +++ b/docs/description/S4457.md @@ -1,11 +1,14 @@ ## Why is this an issue? - -Because of the way `async/await` methods are rewritten by the compiler, any exceptions thrown during the parameters check will happen only when the task is observed. That could happen far away from the source of the buggy code or never happen for fire-and-forget tasks. - -Therefore it is recommended to split the method into two: an outer method handling the parameter checks (without being `async/await`) and an inner method to handle the iterator block with the `async/await` pattern. - -This rule raises an issue when an `async` method throws any exception derived from `ArgumentException` and contains `await` keyword. - + +Because of the way `async/await` methods are rewritten by the compiler, any exceptions thrown during the parameters check will happen +only when the task is observed. That could happen far away from the source of the buggy code or never happen for fire-and-forget tasks. + +Therefore it is recommended to split the method into two: an outer method handling the parameter checks (without being `async/await`) +and an inner method to handle the iterator block with the `async/await` pattern. + +This rule raises an issue when an `async` method throws any exception derived from `ArgumentException` and contains +`await` keyword. + ### Noncompliant code example public static async Task SkipLinesAsync(this TextReader reader, int linesToSkip) // Noncompliant diff --git a/docs/description/S4462.md b/docs/description/S4462.md index e523d38..7b0e1b9 100644 --- a/docs/description/S4462.md +++ b/docs/description/S4462.md @@ -1,10 +1,19 @@ ## Why is this an issue? - -Making blocking calls to `async` methods transforms code that was intended to be asynchronous into a blocking operation. Doing so can cause deadlocks and unexpected blocking of context threads. - + +Making blocking calls to `async` methods transforms code that was intended to be asynchronous into a blocking operation. Doing so can +cause deadlocks and unexpected blocking of context threads. + According to the MSDN documentation: -> The root cause of this deadlock is due to the way `await` handles contexts. By default, when an incomplete `Task` is awaited, the current “context” is captured and used to resume the method when the `Task` completes. This “context” is the current `SynchronizationContext` unless it’s null, in which case it’s the current `TaskScheduler`. GUI and ASP.NET applications have a `SynchronizationContext` that permits only one chunk of code to run at a time. When the `await` completes, it attempts to execute the remainder of the `async` method within the captured context. But that context already has a thread in it, which is (synchronously) waiting for the `async` method to complete. They’re each waiting for the other, causing a deadlock. +> +> +> The root cause of this deadlock is due to the way `await` handles contexts. By default, when an incomplete `Task` is +> awaited, the current “context” is captured and used to resume the method when the `Task` completes. This “context” is the current +> `SynchronizationContext` unless it’s null, in which case it’s the current `TaskScheduler`. GUI and ASP.NET applications have a +> `SynchronizationContext` that permits only one chunk of code to run at a time. When the `await` completes, it attempts to +> execute the remainder of the `async` method within the captured context. But that context already has a thread in it, which is +> (synchronously) waiting for the `async` method to complete. They’re each waiting for the other, causing a deadlock. +> | To Do This … | Instead of This … | Use This | | --- | --- | --- | @@ -51,7 +60,7 @@ According to the MSDN documentation: } ### Exceptions - + - Main methods of Console Applications are not subject to this deadlock issue and so are ignored by this rule. - `Thread.Sleep` is also ignored when it is used in a non-`async` method. - Calls chained after `Task.Run` or `Task.Factory.StartNew` are ignored because they don’t suffer from this deadlock issue diff --git a/docs/description/S4487.md b/docs/description/S4487.md index cf2215e..38dc1f3 100644 --- a/docs/description/S4487.md +++ b/docs/description/S4487.md @@ -1,6 +1,7 @@ ## Why is this an issue? - -Private fields which are written but never read are a case of "dead store". Changing the value of such a field is useless and most probably indicates an error in the code. + +Private fields which are written but never read are a case of "dead store". Changing the value of such a field is useless and most probably +indicates an error in the code. public class Rectangle { @@ -45,7 +46,7 @@ Remove this field if it doesn’t need to be read, or fix the code to read it. } ## Resources - + ### Standards - + - CWE - [CWE-563 - Assignment to Variable without Use ('Unused Variable')](https://cwe.mitre.org/data/definitions/563) \ No newline at end of file diff --git a/docs/description/S4502.md b/docs/description/S4502.md index 859da1d..cbc7641 100644 --- a/docs/description/S4502.md +++ b/docs/description/S4502.md @@ -1,15 +1,18 @@ -A cross-site request forgery (CSRF) attack occurs when a trusted user of a web application can be forced, by an attacker, to perform sensitive actions that he didn’t intend, such as updating his profile or sending a message, more generally anything that can change the state of the application. - -The attacker can trick the user/victim to click on a link, corresponding to the privileged action, or to visit a malicious web site that embeds a hidden web request and as web browsers automatically include cookies, the actions can be authenticated and sensitive. - +A cross-site request forgery (CSRF) attack occurs when a trusted user of a web application can be forced, by an attacker, to perform sensitive +actions that he didn’t intend, such as updating his profile or sending a message, more generally anything that can change the state of the +application. + +The attacker can trick the user/victim to click on a link, corresponding to the privileged action, or to visit a malicious web site that embeds a +hidden web request and as web browsers automatically include cookies, the actions can be authenticated and sensitive. + ## Ask Yourself Whether - + - The web application uses cookies to authenticate users. - There exist sensitive operations in the web application that can be performed when the user is authenticated. - The state / resources of the web application can be modified by doing HTTP POST or HTTP DELETE requests for example. There is a risk if you answered yes to any of those questions. - + ## Recommended Secure Coding Practices - Protection against CSRF attacks is strongly recommended: @@ -52,4 +55,6 @@ There is a risk if you answered yes to any of those questions. - CWE - [CWE-352 - Cross-Site Request Forgery (CSRF)](https://cwe.mitre.org/data/definitions/352) - OWASP - [Top 10 2017 Category A6 - Security Misconfiguration](https://owasp.org/www-project-top-ten/2017/A6_2017-Security_Misconfiguration) -- [OWASP: Cross-Site Request Forgery](https://owasp.org/www-community/attacks/csrf) \ No newline at end of file +- [OWASP: Cross-Site Request Forgery](https://owasp.org/www-community/attacks/csrf) +- STIG Viewer - [Application Security and + Development: V-222603](https://stigviewer.com/stig/application_security_and_development/2023-06-08/finding/V-222603) - The application must protect from Cross-Site Request Forgery (CSRF) vulnerabilities. \ No newline at end of file diff --git a/docs/description/S4507.md b/docs/description/S4507.md index 23a2c32..9424e20 100644 --- a/docs/description/S4507.md +++ b/docs/description/S4507.md @@ -1,23 +1,30 @@ -Development tools and frameworks usually have options to make debugging easier for developers. Although these features are useful during development, they should never be enabled for applications deployed in production. Debug instructions or error messages can leak detailed information about the system, like the application’s path or file names. - +Development tools and frameworks usually have options to make debugging easier for developers. Although these features are useful during +development, they should never be enabled for applications deployed in production. Debug instructions or error messages can leak detailed information +about the system, like the application’s path or file names. + ## Ask Yourself Whether - + - The code or configuration enabling the application debug features is deployed on production servers or distributed to end users. - The application runs by default with debug features activated. There is a risk if you answered yes to any of those questions. - + ## Recommended Secure Coding Practices - + Do not enable debugging features on production servers. - -The .Net Core framework offers multiple features which help during debug. `Microsoft.AspNetCore.Builder.IApplicationBuilder.UseDeveloperExceptionPage` and `Microsoft.AspNetCore.Builder.IApplicationBuilder.UseDatabaseErrorPage` are two of them. Make sure that those features are disabled in production. - + +The .Net Core framework offers multiple features which help during debug. +`Microsoft.AspNetCore.Builder.IApplicationBuilder.UseDeveloperExceptionPage` and +`Microsoft.AspNetCore.Builder.IApplicationBuilder.UseDatabaseErrorPage` are two of them. Make sure that those features are disabled in +production. + Use `if (env.IsDevelopment())` to disable debug code. - + ## Sensitive Code Example - -This rule raises issues when the following .Net Core methods are called: `Microsoft.AspNetCore.Builder.IApplicationBuilder.UseDeveloperExceptionPage`, `Microsoft.AspNetCore.Builder.IApplicationBuilder.UseDatabaseErrorPage`. + +This rule raises issues when the following .Net Core methods are called: +`Microsoft.AspNetCore.Builder.IApplicationBuilder.UseDeveloperExceptionPage`, +`Microsoft.AspNetCore.Builder.IApplicationBuilder.UseDatabaseErrorPage`. using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; @@ -57,9 +64,9 @@ This rule raises issues when the following .Net Core methods are called: `Micros } ## Exceptions - + This rule does not analyze configuration files. Make sure that debug mode is not enabled by default in those files. - + ## See - OWASP - [Top 10 2021 Category A5 - Security Misconfiguration](https://owasp.org/Top10/A05_2021-Security_Misconfiguration/) diff --git a/docs/description/S4524.md b/docs/description/S4524.md index 4ef2ffd..5c2490f 100644 --- a/docs/description/S4524.md +++ b/docs/description/S4524.md @@ -1,5 +1,5 @@ ## Why is this an issue? - + The [switch statement](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/selection-statements#the-switch-statement) is a conditional statement that executes a sequence of instructions based on patterns matching the provided value. @@ -19,7 +19,8 @@ statement](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/st break; } -The `switch` statement can optionally contain a `default` clause, executed when none of the `case` clauses are executed (or in presence of a `goto default;`). +The `switch` statement can optionally contain a `default` clause, executed when none of the `case` clauses are +executed (or in presence of a `goto default;`). switch (gradeLetter) { @@ -48,20 +49,21 @@ The `switch` statement can optionally contain a `default` clause, executed when } The `default` clause can be defined for various reasons: - + - to handle **unexpected values**, as shown in the example above - or to show that all the cases were properly considered, making the function explicitely **total** (as opposed to [partial](https://en.wikipedia.org/wiki/Partial_function)) -While C# allows the `default` clause to appear in any place within a `switch` statement, and while its position doesn’t alter its behavior, it is recommended to put the `default` clause either at the beginning or at the end of the `switch` statement. - +While C# allows the `default` clause to appear in any place within a `switch` statement, and while its position doesn’t alter +its behavior, it is recommended to put the `default` clause either at the beginning or at the end of the `switch` statement. + That improves readability and helps the developer to quickly find the default behavior of a `switch` statement. - + This rule raises an issue if the `default` clause is neither the first nor the last one of the `switch` statement. - + ## How to fix it - + ### Code examples - + #### Noncompliant code example switch (param) @@ -93,7 +95,7 @@ This rule raises an issue if the `default` clause is neither the first nor the l } ## Resources - + ### Documentation - [Switch diff --git a/docs/description/S4545.md b/docs/description/S4545.md index 4e86105..f21ed8e 100644 --- a/docs/description/S4545.md +++ b/docs/description/S4545.md @@ -1,13 +1,16 @@ ## Why is this an issue? - + The `DebuggerDisplayAttribute` is used to determine how an object is displayed in the debugger window. - -The `DebuggerDisplayAttribute` constructor takes a single mandatory argument: the string to be displayed in the value column for instances of the type. Any text within curly braces is evaluated as the name of a field or property, or any complex expression containing method calls and operators. - -Naming a non-existent member between curly braces will result in a CS0103 error in the debug window when debugging objects. Although there is no impact on the production code, providing a wrong value can lead to difficulties when debugging the application. - + +The `DebuggerDisplayAttribute` constructor takes a single mandatory argument: the string to be displayed in the value column for +instances of the type. Any text within curly braces is evaluated as the name of a field or property, or any complex expression containing method calls +and operators. + +Naming a non-existent member between curly braces will result in a CS0103 error in the debug window when debugging objects. Although there is no +impact on the production code, providing a wrong value can lead to difficulties when debugging the application. + This rule raises an issue when text specified between curly braces refers to members that don’t exist in the current context. - + ### Noncompliant code example [DebuggerDisplay("Name: {Name}")] // Noncompliant - Name doesn't exist in this context diff --git a/docs/description/S4581.md b/docs/description/S4581.md index 14fce77..b3d080d 100644 --- a/docs/description/S4581.md +++ b/docs/description/S4581.md @@ -1,13 +1,13 @@ ## Why is this an issue? - + When the syntax `new Guid()` (i.e. parameterless instantiation) is used, it must be that one of three things is wanted: - + 1. An empty GUID, in which case `Guid.Empty` is clearer. 2. A randomly-generated GUID, in which case `Guid.NewGuid()` should be used. 3. A new GUID with a specific initialization, in which case the initialization parameter is missing. This rule raises an issue when a parameterless instantiation of the `Guid` struct is found. - + ### Noncompliant code example public void Foo() diff --git a/docs/description/S4583.md b/docs/description/S4583.md index c22c697..173bf83 100644 --- a/docs/description/S4583.md +++ b/docs/description/S4583.md @@ -1,19 +1,21 @@ ## Why is this an issue? - -When calling the `BeginInvoke` method of a [delegate](https://learn.microsoft.com/en-us/dotnet/api/system.delegate), resources are allocated that are only freed up when `EndInvoke` is called. Failing to pair `BeginInvoke` with `EndInvoke` can lead to [resource leaks](https://en.wikipedia.org/wiki/Resource_leak) and incomplete asynchronous calls. - + +When calling the `BeginInvoke` method of a [delegate](https://learn.microsoft.com/en-us/dotnet/api/system.delegate), +resources are allocated that are only freed up when `EndInvoke` is called. Failing to pair `BeginInvoke` with +`EndInvoke` can lead to [resource leaks](https://en.wikipedia.org/wiki/Resource_leak) and incomplete asynchronous calls. + This rule raises an issue in the following scenarios: - + - The `BeginInvoke` method is called without any callback, and it is not paired with a call to `EndInvoke` in the same block. - A callback with a single parameter of type `IAsyncResult` does not contain a call to `EndInvoke` in the same block. ## How to fix it - + ### Code examples - + #### Noncompliant code example - + `BeginInvoke` without callback: public delegate string AsyncMethodCaller(); @@ -42,7 +44,7 @@ This rule raises an issue in the following scenarios: } #### Compliant solution - + `BeginInvoke` without callback: public delegate string AsyncMethodCaller(); @@ -75,7 +77,7 @@ This rule raises an issue in the following scenarios: } ## Resources - + ### Documentation - [Calling diff --git a/docs/description/S4586.md b/docs/description/S4586.md index d78a993..13025e5 100644 --- a/docs/description/S4586.md +++ b/docs/description/S4586.md @@ -1,6 +1,8 @@ ## Why is this an issue? - -Returning `null` from a non-`async` `Task`/`Task` method will cause a `NullReferenceException` at runtime if the method is awaited. This problem can be avoided by returning [`Task.CompletedTask`](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.completedtask) or [`Task.FromResult(null)`](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.fromresult) respectively. + +Returning `null` from a non-`async` `Task`/`Task` method will cause a +`NullReferenceException` at runtime if the method is awaited. This problem can be avoided by returning [`Task.CompletedTask`](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.completedtask) or [`Task.FromResult(null)`](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.fromresult) +respectively. public Task DoFooAsync() { @@ -13,13 +15,14 @@ Returning `null` from a non-`async` `Task`/`Task` method will cause a ` } ## How to fix it - -Instead of `null` [`Task.CompletedTask`](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.completedtask) or [`Task.FromResult(null)`](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.fromresult) should be returned. - + +Instead of `null` [`Task.CompletedTask`](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.completedtask) or [`Task.FromResult(null)`](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.fromresult) +should be returned. + ### Code examples - + A `Task` returning method can be fixed like so: - + #### Noncompliant code example public Task DoFooAsync() @@ -35,7 +38,7 @@ A `Task` returning method can be fixed like so: } A `Task` returning method can be fixed like so: - + #### Noncompliant code example public Task GetFooAsync() @@ -51,9 +54,9 @@ A `Task` returning method can be fixed like so: } ## Resources - + ### Documentation - + - Microsoft Learn - [`Task.CompletedTask` Property](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.completedtask) - Microsoft Learn - [`Task.FromResult(TResult)` Method](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.fromresult) diff --git a/docs/description/S4635.md b/docs/description/S4635.md index 7efd3a0..d0d4a48 100644 --- a/docs/description/S4635.md +++ b/docs/description/S4635.md @@ -1,5 +1,5 @@ ## Why is this an issue? - + It is important to be careful when searching for characters within a substring. Let’s consider the following example: if (str.SubString(startIndex).IndexOf(char1) == -1) // Noncompliant: a new string is going to be created by "Substring" @@ -7,18 +7,21 @@ It is important to be careful when searching for characters within a substring. // ... } -A new `string` object is created with every call to the [`Substring`](https://learn.microsoft.com/en-us/dotnet/api/system.string.substring) method. When chaining it with any of the following methods, it creates a new object for one-time use only: - +A new `string` object is created with every call to the [`Substring`](https://learn.microsoft.com/en-us/dotnet/api/system.string.substring) method. When chaining it with any of the +following methods, it creates a new object for one-time use only: + - [`IndexOf`](https://learn.microsoft.com/en-us/dotnet/api/system.string.indexof) - [`IndexOfAny`](https://learn.microsoft.com/en-us/dotnet/api/system.string.indexofany) - [`LastIndexOf`](https://learn.microsoft.com/en-us/dotnet/api/system.string.lastindexof) - [`LastIndexOfAny`](https://learn.microsoft.com/en-us/dotnet/api/system.string.lastindexofany) ### What is the potential impact? - -Creating a new object consumes significant [system resources](https://en.wikipedia.org/wiki/System_resource), especially CPU and memory. When using `Substring` repeatedly, such as in a loop, it can greatly impact the overall performance of the application or program. - -To mitigate the creation of new objects while searching for characters within a substring, it is possible to use an overload of the mentioned methods with a `startIndex` parameter: + +Creating a new object consumes significant [system resources](https://en.wikipedia.org/wiki/System_resource), especially CPU and memory. +When using `Substring` repeatedly, such as in a loop, it can greatly impact the overall performance of the application or program. + +To mitigate the creation of new objects while searching for characters within a substring, it is possible to use an overload of the mentioned +methods with a `startIndex` parameter: if (str.IndexOf(char1, startIndex) == -1) // Compliant: no new instance of string is created { @@ -26,9 +29,9 @@ To mitigate the creation of new objects while searching for characters within a } Using these methods gives the same result while avoiding the creation of additional `string` objects. - + ## Resources - + ### Documentation - [`String.Substring` Method](https://learn.microsoft.com/en-us/dotnet/api/system.string.substring) diff --git a/docs/description/S4663.md b/docs/description/S4663.md index 82eedf1..4853c6a 100644 --- a/docs/description/S4663.md +++ b/docs/description/S4663.md @@ -1,5 +1,5 @@ ## Why is this an issue? - + Empty comments, as shown in the example, hurt readability and might indicate an oversight. // diff --git a/docs/description/S4790.md b/docs/description/S4790.md index 28dd6b1..28de0da 100644 --- a/docs/description/S4790.md +++ b/docs/description/S4790.md @@ -1,19 +1,24 @@ -Cryptographic hash algorithms such as `MD2`, `MD4`, `MD5`, `MD6`, `HAVAL-128`, `HMAC-MD5`, `DSA` (which uses `SHA-1`), `RIPEMD`, `RIPEMD-128`, `RIPEMD-160`, `HMACRIPEMD160` and `SHA-1` are no longer considered secure, because it is possible to have `collisions` (little computational effort is enough to find two or more different inputs that produce the same hash). - +Cryptographic hash algorithms such as `MD2`, `MD4`, `MD5`, `MD6`, `HAVAL-128`, +`HMAC-MD5`, `DSA` (which uses `SHA-1`), `RIPEMD`, `RIPEMD-128`, `RIPEMD-160`, +`HMACRIPEMD160` and `SHA-1` are no longer considered secure, because it is possible to have `collisions` (little +computational effort is enough to find two or more different inputs that produce the same hash). + ## Ask Yourself Whether - + The hashed value is used in a security context like: - + - User-password storage. - Security token generation (used to confirm e-mail when registering on a website, reset password, etc …​). - To compute some message integrity. There is a risk if you answered yes to any of those questions. - + ## Recommended Secure Coding Practices - -Safer alternatives, such as `SHA-256`, `SHA-512`, `SHA-3` are recommended, and for password hashing, it’s even better to use algorithms that do not compute too "quickly", like `bcrypt`, `scrypt`, `argon2` or `pbkdf2` because it slows down `brute force attacks`. - + +Safer alternatives, such as `SHA-256`, `SHA-512`, `SHA-3` are recommended, and for password hashing, it’s even +better to use algorithms that do not compute too "quickly", like `bcrypt`, `scrypt`, `argon2` or `pbkdf2` +because it slows down `brute force attacks`. + ## Sensitive Code Example var hashProvider1 = new MD5CryptoServiceProvider(); // Sensitive diff --git a/docs/description/S4792.md b/docs/description/S4792.md index 54e2248..17c5234 100644 --- a/docs/description/S4792.md +++ b/docs/description/S4792.md @@ -1,7 +1,7 @@ This rule is deprecated, and will eventually be removed. - + Configuring loggers is security-sensitive. It has led in the past to the following vulnerabilities: - + - [CVE-2018-0285](http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-0285) - [CVE-2000-1127](http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2000-1127) - [CVE-2017-15113](http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-15113) @@ -13,10 +13,11 @@ Logs are useful before, during and after a security incident. is the first step to prevent an attack from ever happening. - In case of a successful attack, logs should contain enough information to understand what damage an attacker may have inflicted. -Logs are also a target for attackers because they might contain sensitive information. Configuring loggers has an impact on the type of information logged and how they are logged. - +Logs are also a target for attackers because they might contain sensitive information. Configuring loggers has an impact on the type of information +logged and how they are logged. + This rule flags for review code that initiates loggers configuration. The goal is to guide security code reviews. - + ## Ask Yourself Whether - unauthorized users might have access to the logs, either because they are stored in an insecure location or because the application gives @@ -29,7 +30,7 @@ This rule flags for review code that initiates loggers configuration. The goal i - the logs are only stored locally instead of being backuped or replicated. There is a risk if you answered yes to any of those questions. - + ## Recommended Secure Coding Practices - Check that your production deployment doesn’t have its loggers in "debug" mode as it might write sensitive information in logs. @@ -43,7 +44,8 @@ There is a risk if you answered yes to any of those questions. - Add limits to the size of the logs and make sure that no user can fill the disk with logs. This can happen even when the user does not control the logged information. An attacker could just repeat a logged action many times. -Remember that configuring loggers properly doesn’t make them bullet-proof. Here is a list of recommendations explaining on how to use your logs: +Remember that configuring loggers properly doesn’t make them bullet-proof. Here is a list of recommendations explaining on how to use your +logs: - Don’t log any sensitive information. This obviously includes passwords and credit card numbers but also any personal information such as user names, locations, etc…​ Usually any information which is protected by law is good candidate for removal. @@ -55,7 +57,7 @@ Remember that configuring loggers properly doesn’t make them bullet-proof. Her - Monitor the logs for any suspicious activity. ## Sensitive Code Example - + **.Net Core**: configure programmatically using System; diff --git a/docs/description/S4830.md b/docs/description/S4830.md index c19ddd3..4408fd6 100644 --- a/docs/description/S4830.md +++ b/docs/description/S4830.md @@ -1,31 +1,41 @@ This vulnerability makes it possible that an encrypted communication is intercepted. - + ## Why is this an issue? - -Transport Layer Security (TLS) provides secure communication between systems over the internet by encrypting the data sent between them. Certificate validation adds an extra layer of trust and security to this process to ensure that a system is indeed the one it claims to be. - -When certificate validation is disabled, the client skips a critical security check. This creates an opportunity for attackers to pose as a trusted entity and intercept, manipulate, or steal the data being transmitted. - + +Transport Layer Security (TLS) provides secure communication between systems over the internet by encrypting the data sent between them. +Certificate validation adds an extra layer of trust and security to this process to ensure that a system is indeed the one it claims to be. + +When certificate validation is disabled, the client skips a critical security check. This creates an opportunity for attackers to pose as a trusted +entity and intercept, manipulate, or steal the data being transmitted. + ### What is the potential impact? - -Establishing trust in a secure way is a non-trivial task. When you disable certificate validation, you are removing a key mechanism designed to build this trust in internet communication, opening your system up to a number of potential threats. - + +Establishing trust in a secure way is a non-trivial task. When you disable certificate validation, you are removing a key mechanism designed to +build this trust in internet communication, opening your system up to a number of potential threats. + #### Identity spoofing - -If a system does not validate certificates, it cannot confirm the identity of the other party involved in the communication. An attacker can exploit this by creating a fake server and masquerading as a legitimate one. For example, they might set up a server that looks like your bank’s server, tricking your system into thinking it is communicating with the bank. This scenario, called identity spoofing, allows the attacker to collect any data your system sends to them, potentially leading to significant data breaches. - + +If a system does not validate certificates, it cannot confirm the identity of the other party involved in the communication. An attacker can +exploit this by creating a fake server and masquerading as a legitimate one. For example, they might set up a server that looks like your bank’s +server, tricking your system into thinking it is communicating with the bank. This scenario, called identity spoofing, allows the attacker to collect +any data your system sends to them, potentially leading to significant data breaches. + #### Loss of data integrity - -When TLS certificate validation is disabled, the integrity of the data you send and receive cannot be guaranteed. An attacker could modify the data in transit, and you would have no way of knowing. This could range from subtle manipulations of the data you receive to the injection of malicious code or malware into your system. The consequences of such breaches of data integrity can be severe, depending on the nature of the data and the system. - + +When TLS certificate validation is disabled, the integrity of the data you send and receive cannot be guaranteed. An attacker could modify the data +in transit, and you would have no way of knowing. This could range from subtle manipulations of the data you receive to the injection of malicious +code or malware into your system. The consequences of such breaches of data integrity can be severe, depending on the nature of the data and the +system. + ## How to fix it in .NET - + ### Code examples - + In the following example, the callback change impacts the entirety of HTTP requests made by the application. - -The certificate validation gets disabled by overriding `ServerCertificateValidationCallback` with an empty implementation. It is highly recommended to use the original implementation. - + +The certificate validation gets disabled by overriding `ServerCertificateValidationCallback` with an empty implementation. It is highly +recommended to use the original implementation. + #### Noncompliant code example using System.Net; @@ -41,23 +51,26 @@ The certificate validation gets disabled by overriding `ServerCertificateValidat } ### How does this work? - + Addressing the vulnerability of disabled TLS certificate validation primarily involves re-enabling the default validation. - + To avoid running into problems with invalid certificates, consider the following sections. - + #### Using trusted certificates - -If possible, always use a certificate issued by a well-known, trusted CA for your server. Most programming environments come with a predefined list of trusted root CAs, and certificates issued by these authorities are validated automatically. This is the best practice, and it requires no additional code or configuration. - + +If possible, always use a certificate issued by a well-known, trusted CA for your server. Most programming environments come with a predefined list +of trusted root CAs, and certificates issued by these authorities are validated automatically. This is the best practice, and it requires no +additional code or configuration. + #### Working with self-signed certificates or non-standard CAs - -In some cases, you might need to work with a server using a self-signed certificate, or a certificate issued by a CA not included in your trusted roots. Rather than disabling certificate validation in your code, you can add the necessary certificates to your trust store. - + +In some cases, you might need to work with a server using a self-signed certificate, or a certificate issued by a CA not included in your trusted +roots. Rather than disabling certificate validation in your code, you can add the necessary certificates to your trust store. + ## Resources - + ### Standards - + - OWASP - [Top 10 2021 Category A2 - Cryptographic Failures](https://owasp.org/Top10/A02_2021-Cryptographic_Failures/) - OWASP - [Top 10 2021 Category A5 - Security Misconfiguration](https://owasp.org/Top10/A05_2021-Security_Misconfiguration/) - OWASP - [Top 10 2021 Category A7 - Identification and @@ -70,4 +83,6 @@ In some cases, you might need to work with a server using a self-signed certific Communication](https://owasp.org/www-project-mobile-top-10/2016-risks/m3-insecure-communication) - OWASP - [Mobile AppSec Verification Standard - Network Communication Requirements](https://mobile-security.gitbook.io/masvs/security-requirements/0x10-v5-network_communication_requirements) -- CWE - [CWE-295 - Improper Certificate Validation](https://cwe.mitre.org/data/definitions/295) \ No newline at end of file +- CWE - [CWE-295 - Improper Certificate Validation](https://cwe.mitre.org/data/definitions/295) +- STIG Viewer - [Application Security and + Development: V-222550](https://stigviewer.com/stig/application_security_and_development/2023-06-08/finding/V-222550) - The application must validate certificates by constructing a certification path to an accepted trust anchor. \ No newline at end of file diff --git a/docs/description/S5034.md b/docs/description/S5034.md index aafadfb..e16a13c 100644 --- a/docs/description/S5034.md +++ b/docs/description/S5034.md @@ -1,10 +1,12 @@ ## Why is this an issue? - -`ValueTask` provides a value type that wraps a [Task<TResult>](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task-1) and the corresponding `TResult`. It was introduced in .NET Core 2.0 [to optimize + +`ValueTask` provides a value type that wraps a [Task<TResult>](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task-1) and the corresponding `TResult`. +It was introduced in .NET Core 2.0 [to optimize memory allocation](https://devblogs.microsoft.com/dotnet/understanding-the-whys-whats-and-whens-of-valuetask) when functions return their results synchronously. - -Using `ValueTask` and `ValueTask` in the following ways is discouraged as it could result in a race condition: - + +Using `ValueTask` and `ValueTask` in the following ways is discouraged as it could result in a race +condition: + - Calling `await` multiple times on a `ValueTask`/`ValueTask`. The wrapped object may have been reused by another operation. This differs from `Task`/`Task`, on which you can await multiple times and always get the same result. @@ -15,9 +17,11 @@ Using `ValueTask` and `ValueTask` in the following ways is discouraged `IValueTaskSource`/`IValueTaskSource` implementations are not required to block until the operation completes. On the other hand, `Task`/`Task` blocks the call until the task completes. -It is recommended to use `ValueTask`/`ValueTask` either by calling `await` on the function returning it, optionally calling `ConfigureAwait(false)` on it, or by calling `.AsTask()` on it. - -This rule raises an issue when the following operations are performed on a `ValueTask`/`ValueTask` instance unless it happens in a loop: +It is recommended to use `ValueTask`/`ValueTask` either by calling `await` on the function +returning it, optionally calling `ConfigureAwait(false)` on it, or by calling `.AsTask()` on it. + +This rule raises an issue when the following operations are performed on a `ValueTask`/`ValueTask` instance +unless it happens in a loop: - Awaiting the instance multiple times. - Calling `AsTask` multiple times. @@ -26,9 +30,9 @@ This rule raises an issue when the following operations are performed on a `Valu - Using of these ways to consume the instance multiple times. ## How to fix it - + ### Code examples - + #### Noncompliant code example ValueTask vt = ComputeAsync(); @@ -45,10 +49,15 @@ This rule raises an issue when the following operations are performed on a `Valu int value = await ComputeAsync().AsTask(); ## Resources - + ### Documentation - [ValueTask](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.valuetask) - [ValueTask<TResult>](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.valuetask-1) - [Understanding the Whys, Whats, - and Whens of ValueTask](https://blogs.msdn.microsoft.com/dotnet/2018/11/07/understanding-the-whys-whats-and-whens-of-valuetask) \ No newline at end of file + and Whens of ValueTask](https://blogs.msdn.microsoft.com/dotnet/2018/11/07/understanding-the-whys-whats-and-whens-of-valuetask) + +### Standards + +- STIG Viewer - [Application Security and + Development: V-222567](https://stigviewer.com/stig/application_security_and_development/2023-06-08/finding/V-222567) - The application must not be vulnerable to race conditions. \ No newline at end of file diff --git a/docs/description/S5042.md b/docs/description/S5042.md index 9557332..43934d3 100644 --- a/docs/description/S5042.md +++ b/docs/description/S5042.md @@ -1,15 +1,18 @@ -Successful Zip Bomb attacks occur when an application expands untrusted archive files without controlling the size of the expanded data, which can lead to denial of service. A Zip bomb is usually a malicious archive file of a few kilobytes of compressed data but turned into gigabytes of uncompressed data. To achieve this extreme [compression ratio](https://en.wikipedia.org/wiki/Data_compression_ratio), attackers will compress irrelevant data (eg: a long string of repeated bytes). - +Successful Zip Bomb attacks occur when an application expands untrusted archive files without controlling the size of the expanded data, which can +lead to denial of service. A Zip bomb is usually a malicious archive file of a few kilobytes of compressed data but turned into gigabytes of +uncompressed data. To achieve this extreme [compression ratio](https://en.wikipedia.org/wiki/Data_compression_ratio), attackers will +compress irrelevant data (eg: a long string of repeated bytes). + ## Ask Yourself Whether - + Archives to expand are untrusted and: - + - There is no validation of the number of entries in the archive. - There is no validation of the total size of the uncompressed data. - There is no validation of the ratio between the compressed and uncompressed archive entry. There is a risk if you answered yes to any of those questions. - + ## Recommended Secure Coding Practices - Define and control the ratio between compressed and uncompressed data, in general the data compression ratio for most of the legit archives is diff --git a/docs/description/S5122.md b/docs/description/S5122.md index 8241034..5c4e5f0 100644 --- a/docs/description/S5122.md +++ b/docs/description/S5122.md @@ -1,10 +1,13 @@ Having a permissive Cross-Origin Resource Sharing policy is security-sensitive. It has led in the past to the following vulnerabilities: - + - [CVE-2018-0269](http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-0269) - [CVE-2017-14460](http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-14460) -[Same origin policy](https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy) in browsers prevents, by default and for security-reasons, a javascript frontend to perform a cross-origin HTTP request to a resource that has a different origin (domain, protocol, or port) from its own. The requested target can append additional HTTP headers in response, called [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS), that act like directives for the browser and change the access control policy / relax the same origin policy. - +[Same origin policy](https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy) in browsers prevents, by default and for +security-reasons, a javascript frontend to perform a cross-origin HTTP request to a resource that has a different origin (domain, protocol, or port) +from its own. The requested target can append additional HTTP headers in response, called [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS), that act like directives for the browser and change the access control policy +/ relax the same origin policy. + ## Ask Yourself Whether - You don’t trust the origin specified, example: `Access-Control-Allow-Origin: untrustedwebsite.com`. @@ -12,7 +15,7 @@ Having a permissive Cross-Origin Resource Sharing policy is security-sensitive. - Your access control policy is dynamically defined by a user-controlled input like [`origin`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Origin) header. There is a risk if you answered yes to any of those questions. - + ## Recommended Secure Coding Practices - The `Access-Control-Allow-Origin` header should be set only for a trusted origin and for specific resources. @@ -20,7 +23,7 @@ There is a risk if you answered yes to any of those questions. allowing any domain (do not use \* wildcard nor blindly return the `Origin` header content without any checks). ## Sensitive Code Example - + ASP.NET Core MVC: [HttpGet] @@ -79,7 +82,7 @@ User-controlled origin: Response.Headers.Add("Access-Control-Allow-Origin", origin); // Sensitive ## Compliant Solution - + ASP.NET Core MVC: [HttpGet] diff --git a/docs/description/S5332.md b/docs/description/S5332.md index ae613a4..6c8a56e 100644 --- a/docs/description/S5332.md +++ b/docs/description/S5332.md @@ -1,23 +1,28 @@ -Clear-text protocols such as `ftp`, `telnet`, or `http` lack encryption of transported data, as well as the capability to build an authenticated connection. It means that an attacker able to sniff traffic from the network can read, modify, or corrupt the transported content. These protocols are not secure as they expose applications to an extensive range of risks: - +Clear-text protocols such as `ftp`, `telnet`, or `http` lack encryption of transported data, as well as the +capability to build an authenticated connection. It means that an attacker able to sniff traffic from the network can read, modify, or corrupt the +transported content. These protocols are not secure as they expose applications to an extensive range of risks: + - sensitive data exposure - traffic redirected to a malicious endpoint - malware-infected software update or installer - execution of client-side code - corruption of critical information -Even in the context of isolated networks like offline environments or segmented cloud environments, the insider threat exists. Thus, attacks involving communications being sniffed or tampered with can still happen. - +Even in the context of isolated networks like offline environments or segmented cloud environments, the insider threat exists. Thus, attacks +involving communications being sniffed or tampered with can still happen. + For example, attackers could successfully compromise prior security layers by: - bypassing isolation mechanisms - compromising a component of the network - getting the credentials of an internal IAM account (either from a service account or an actual person) -In such cases, encrypting communications would decrease the chances of attackers to successfully leak data or steal credentials from other network components. By layering various security practices (segmentation and encryption, for example), the application will follow the *defense-in-depth* principle. - +In such cases, encrypting communications would decrease the chances of attackers to successfully leak data or steal credentials from other network +components. By layering various security practices (segmentation and encryption, for example), the application will follow the +*defense-in-depth* principle. + Note that using the `http` protocol is being deprecated by [major web browsers](https://blog.mozilla.org/security/2015/04/30/deprecating-non-secure-http). - + In the past, it has led to the following vulnerabilities: - [CVE-2019-6169](https://nvd.nist.gov/vuln/detail/CVE-2019-6169) @@ -33,7 +38,7 @@ In the past, it has led to the following vulnerabilities: - OS-level protections against clear-text traffic are deactivated. There is a risk if you answered yes to any of those questions. - + ## Recommended Secure Coding Practices - Make application data transit over a secure, authenticated and encrypted protocol like TLS or SSH. Here are a few alternatives to the most @@ -46,8 +51,9 @@ There is a risk if you answered yes to any of those questions. - Configure your application to block mixed content when rendering web pages. - If available, enforce OS-level deactivation of all clear-text traffic. -It is recommended to secure all transport channels, even on local networks, as it can take a single non-secure connection to compromise an entire application or system. - +It is recommended to secure all transport channels, even on local networks, as it can take a single non-secure connection to compromise an entire +application or system. + ## Sensitive Code Example var urlHttp = "http://example.com"; // Noncompliant @@ -67,24 +73,53 @@ It is recommended to secure all transport channels, even on local networks, as i using var ssh = new MySsh.Client("host", port); ## Exceptions - + No issue is reported for the following cases because they are not considered sensitive: - Insecure protocol scheme followed by loopback addresses like 127.0.0.1 or `localhost`. ## See +### Documentation + +- AWS Documentation - [Listeners for + your Application Load Balancers](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-listeners.html) +- AWS Documentation - [Stream Encryption](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kinesis-stream-streamencryption.html) + +### Articles & blog posts + +- Google - [Moving towards more secure web](https://security.googleblog.com/2016/09/moving-towards-more-secure-web.html) +- Mozilla - [Deprecating non secure http](https://blog.mozilla.org/security/2015/04/30/deprecating-non-secure-http/) + +### Standards + +- OWASP - [Top 10 2017 Category A3 - Sensitive Data + Exposure](https://owasp.org/www-project-top-ten/2017/A3_2017-Sensitive_Data_Exposure) - OWASP - [Top 10 2021 Category A2 - Cryptographic Failures](https://owasp.org/Top10/A02_2021-Cryptographic_Failures/) -- OWASP - [Top 10 2017 Category A3 - Sensitive Data Exposure](https://owasp.org/www-project-top-ten/2017/A3_2017-Sensitive_Data_Exposure) - OWASP - [Mobile AppSec Verification Standard - Network Communication Requirements](https://mobile-security.gitbook.io/masvs/security-requirements/0x10-v5-network_communication_requirements) - OWASP - [Mobile Top 10 2016 Category M3 - Insecure Communication](https://owasp.org/www-project-mobile-top-10/2016-risks/m3-insecure-communication) - CWE - [CWE-200 - Exposure of Sensitive Information to an Unauthorized Actor](https://cwe.mitre.org/data/definitions/200) - CWE - [CWE-319 - Cleartext Transmission of Sensitive Information](https://cwe.mitre.org/data/definitions/319) -- [Google, Moving towards more secure web](https://security.googleblog.com/2016/09/moving-towards-more-secure-web.html) -- [Mozilla, Deprecating non secure http](https://blog.mozilla.org/security/2015/04/30/deprecating-non-secure-http/) -- [AWS Documentation](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-listeners.html) - Listeners - for your Application Load Balancers -- [AWS - Documentation](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kinesis-stream-streamencryption.html) - Stream Encryption \ No newline at end of file +- STIG Viewer - [Application Security and + Development: V-222397](https://stigviewer.com/stig/application_security_and_development/2023-06-08/finding/V-222397) - The application must implement cryptographic mechanisms to protect the integrity of remote access sessions. +- STIG Viewer - [Application Security and + Development: V-222534](https://stigviewer.com/stig/application_security_and_development/2023-06-08/finding/V-222534) - Service-Oriented Applications handling non-releasable data must authenticate endpoint devices via mutual SSL/TLS. +- STIG Viewer - [Application Security and + Development: V-222562](https://stigviewer.com/stig/application_security_and_development/2023-06-08/finding/V-222562) - Applications used for non-local maintenance must implement cryptographic mechanisms to protect the integrity of + maintenance and diagnostic communications. +- STIG Viewer - [Application Security and + Development: V-222563](https://stigviewer.com/stig/application_security_and_development/2023-06-08/finding/V-222563) - Applications used for non-local maintenance must implement cryptographic mechanisms to protect the confidentiality of + maintenance and diagnostic communications. +- STIG Viewer - [Application Security and + Development: V-222577](https://stigviewer.com/stig/application_security_and_development/2023-06-08/finding/V-222577) - The application must not expose session IDs. +- STIG Viewer - [Application Security and + Development: V-222596](https://stigviewer.com/stig/application_security_and_development/2023-06-08/finding/V-222596) - The application must protect the confidentiality and integrity of transmitted information. +- STIG Viewer - [Application Security and + Development: V-222597](https://stigviewer.com/stig/application_security_and_development/2023-06-08/finding/V-222597) - The application must implement cryptographic mechanisms to prevent unauthorized disclosure of information and/or detect + changes to information during transmission. +- STIG Viewer - [Application Security and + Development: V-222598](https://stigviewer.com/stig/application_security_and_development/2023-06-08/finding/V-222598) - The application must maintain the confidentiality and integrity of information during preparation for transmission. +- STIG Viewer - [Application Security and + Development: V-222599](https://stigviewer.com/stig/application_security_and_development/2023-06-08/finding/V-222599) - The application must maintain the confidentiality and integrity of information during reception. \ No newline at end of file diff --git a/docs/description/S5344.md b/docs/description/S5344.md new file mode 100644 index 0000000..1b0fce9 --- /dev/null +++ b/docs/description/S5344.md @@ -0,0 +1,344 @@ +The improper storage of passwords poses a significant security risk to software applications. This vulnerability arises when passwords are stored +in plaintext or with a fast hashing algorithm. To exploit this vulnerability, an attacker typically requires access to the stored passwords. + +## Why is this an issue? + +Attackers who would get access to the stored passwords could reuse them without further attacks or with little additional effort. + Obtaining the +plaintext passwords, they could then gain unauthorized access to user accounts, potentially leading to various malicious activities. + +### What is the potential impact? + +Plaintext or weakly hashed password storage poses a significant security risk to software applications. + +#### Unauthorized Access + +When passwords are stored in plaintext or with weak hashing algorithms, an attacker who gains access to the password database can easily retrieve +and use the passwords to gain unauthorized access to user accounts. This can lead to various malicious activities, such as unauthorized data access, +identity theft, or even financial fraud. + +#### Credential Reuse + +Many users tend to reuse passwords across multiple platforms. If an attacker obtains plaintext or weakly hashed passwords, they can potentially use +these credentials to gain unauthorized access to other accounts held by the same user. This can have far-reaching consequences, as sensitive personal +information or critical systems may be compromised. + +#### Regulatory Compliance + +Many industries and jurisdictions have specific regulations and standards to protect user data and ensure its confidentiality. Storing passwords in +plaintext or with weak hashing algorithms can lead to non-compliance with these regulations, potentially resulting in legal consequences, financial +penalties, and damage to the reputation of the software application and its developers. + +## How to fix it in ASP.NET Core + +### Code examples + +#### Noncompliant code example + +Using `Microsoft.AspNetCore.Cryptography.KeyDerivation`: + + using Microsoft.AspNetCore.Cryptography.KeyDerivation; + using System.Security.Cryptography; + + string password = Request.Query["password"]; + byte[] salt = RandomNumberGenerator.GetBytes(128 / 8); + + string hashed = Convert.ToBase64String(KeyDerivation.Pbkdf2( + password: password!, + salt: salt, + prf: KeyDerivationPrf.HMACSHA256, + iterationCount: 1, // Noncompliant + numBytesRequested: 256 / 8)); + +Using `System.Security.Cryptography`: + + using System.Security.Cryptography; + + string password = Request.Query["password"]; + byte[] salt = RandomNumberGenerator.GetBytes(128 / 8); + Rfc2898DeriveBytes kdf = new Rfc2898DeriveBytes(password, 128/8); // Noncompliant + string hashed = Convert.ToBase64String(kdf.GetBytes(256 / 8)); + +Using `Microsoft.AspNetCore.Identity`: + + using Microsoft.AspNetCore.Identity; + using Microsoft.Extensions.Options; + + string password = Request.Query["password"]; + IOptions options = Options.Create(new PasswordHasherOptions() { + IterationCount = 1 // Noncompliant + }); + PasswordHasher hasher = new PasswordHasher(options); + string hash = hasher.HashPassword(new User("test"), password); + +#### Compliant solution + +Using `Microsoft.AspNetCore.Cryptography.KeyDerivation`: + + using Microsoft.AspNetCore.Cryptography.KeyDerivation; + using System.Security.Cryptography; + + string password = Request.Query["password"]; + byte[] salt = RandomNumberGenerator.GetBytes(128 / 8); + + string hashed = Convert.ToBase64String(KeyDerivation.Pbkdf2( + password: password!, + salt: salt, + prf: KeyDerivationPrf.HMACSHA256, + iterationCount: 100_000, + numBytesRequested: 256 / 8)); + +Using `System.Security.Cryptography` + + using System.Security.Cryptography; + + string password = Request.Query["password"]; + byte[] salt = RandomNumberGenerator.GetBytes(128 / 8); + Rfc2898DeriveBytes kdf = new Rfc2898DeriveBytes(password, salt, 100_000, HashAlgorithmName.SHA256); + string hashed = Convert.ToBase64String(kdf.GetBytes(256 / 8)); + +Using `Microsoft.AspNetCore.Identity`: + + using Microsoft.AspNetCore.Identity; + using Microsoft.Extensions.Options; + + string password = Request.Query["password"]; + PasswordHasher hasher = new PasswordHasher(); + string hash = hasher.HashPassword(new User("test"), password); + +### How does this work? + +#### Select the correct PBKDF2 parameters + +If PBKDF2 must be used, be aware that default values might not be considered secure. + Depending on the algorithm used, the number of iterations +should be adjusted to ensure that the derived key is secure. The following are the recommended number of iterations for PBKDF2: + +- PBKDF2-HMAC-SHA1: 1,300,000 iterations +- PBKDF2-HMAC-SHA256: 600,000 iterations +- PBKDF2-HMAC-SHA512: 210,000 iterations + +Note that PBKDF2-HMAC-SHA256 is recommended by NIST. + Iterations are also called "rounds" depending on the library used. + +When recommended cost factors are too high in the context of the application or if the performance cost is unacceptable, a cost factor reduction +might be considered. In that case, it should not be chosen under 100,000. + +### Going the extra mile + +#### Pepper + +In a defense-in-depth security approach, **peppering** can also be used. This is a security technique where an external secret value +is added to a password before it is hashed. + This makes it more difficult for an attacker to crack the hashed passwords, as they would need to know +the secret value to generate the correct hash. + [Learn more here](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#peppering). + +## How to fix it in ASP.NET + +### Code examples + +#### Noncompliant code example + + using System.Security.Cryptography; + + RNGCryptoServiceProvider rngCsp = new RNGCryptoServiceProvider(); + byte[] salt = new byte[32]; + rngCsp.GetBytes(salt); + Rfc2898DeriveBytes kdf = new Rfc2898DeriveBytes(password, salt, 100, HashAlgorithmName.SHA256); // Noncompliant + string hashed = Convert.ToBase64String(kdf.GetBytes(256 / 8)); + +Using `using Microsoft.AspNet.Identity`: + + using Microsoft.AspNet.Identity; + + string password = "NotSoSecure"; + PasswordHasher hasher = new PasswordHasher(); + string hash = hasher.HashPassword(password); // Noncompliant + +#### Compliant solution + + using System.Security.Cryptography; + + RNGCryptoServiceProvider rngCsp = new RNGCryptoServiceProvider(); + byte[] salt = new byte[32]; + rngCsp.GetBytes(salt); + Rfc2898DeriveBytes kdf = new Rfc2898DeriveBytes(password, salt, 100_000, HashAlgorithmName.SHA256); // Compliant + string hashed = Convert.ToBase64String(kdf.GetBytes(256 / 8)); + +### How does this work? + +#### Select the correct PBKDF2 parameters + +If PBKDF2 must be used, be aware that default values might not be considered secure. + Depending on the algorithm used, the number of iterations +should be adjusted to ensure that the derived key is secure. The following are the recommended number of iterations for PBKDF2: + +- PBKDF2-HMAC-SHA1: 1,300,000 iterations +- PBKDF2-HMAC-SHA256: 600,000 iterations +- PBKDF2-HMAC-SHA512: 210,000 iterations + +Note that PBKDF2-HMAC-SHA256 is recommended by NIST. + Iterations are also called "rounds" depending on the library used. + +When recommended cost factors are too high in the context of the application or if the performance cost is unacceptable, a cost factor reduction +might be considered. In that case, it should not be chosen under 100,000. + +### Going the extra mile + +#### Pepper + +In a defense-in-depth security approach, **peppering** can also be used. This is a security technique where an external secret value +is added to a password before it is hashed. + This makes it more difficult for an attacker to crack the hashed passwords, as they would need to know +the secret value to generate the correct hash. + [Learn more here](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#peppering). + +## How to fix it in BouncyCastle + +### Code examples + +#### Noncompliant code example + +Using SCrypt: + + using Org.BouncyCastle.Crypto.Generators; + + string password = Request.Query["password"]; + byte[] salt = RandomNumberGenerator.GetBytes(128 / 8); // divide by 8 to convert bits to bytes + + string hashed = Convert.ToBase64String(SCrypt.Generate(Encoding.Unicode.GetBytes(password), salt, 4, 2, 1, 32)); // Noncompliant + +Using BCrypt: + + using Org.BouncyCastle.Crypto.Generators; + using Org.BouncyCastle.Crypto.Parameters; + + string password = Request.Query["password"]; + byte[] salt = RandomNumberGenerator.GetBytes(128 / 8); + + string hashed = OpenBsdBCrypt.Generate(password.ToCharArray(), salt, 4); // Noncompliant + +Using PBKDF2: + + using Org.BouncyCastle.Crypto.Generators; + using Org.BouncyCastle.Crypto.Parameters; + using System.Security.Cryptography; + + string password = Request.Query["password"]; + byte[] salt = RandomNumberGenerator.GetBytes(128 / 8); + Pkcs5S2ParametersGenerator gen = new Pkcs5S2ParametersGenerator(); + gen.Init(Encoding.Unicode.GetBytes(password), salt, 100); // Noncompliant + KeyParameter keyParam = (KeyParameter) gen.GenerateDerivedMacParameters(256); + string hashed = Convert.ToBase64String(keyParam.GetKey()); + +#### Compliant solution + +Using SCrypt: + + using Org.BouncyCastle.Crypto.Generators; + + string password = Request.Query["password"]; + byte[] salt = RandomNumberGenerator.GetBytes(128 / 8); // divide by 8 to convert bits to bytes + + string hashed = Convert.ToBase64String(SCrypt.Generate(Encoding.Unicode.GetBytes(password), salt, 1<<12, 8, 1, 32)); // Noncompliant + +Using BCrypt: + + using Org.BouncyCastle.Crypto.Generators; + using Org.BouncyCastle.Crypto.Parameters; + + string password = Request.Query["password"]; + byte[] salt = RandomNumberGenerator.GetBytes(128 / 8); + + string hashed = OpenBsdBCrypt.Generate(password.ToCharArray(), salt, 14); // Noncompliant + +Using PBKDF2: + + using Org.BouncyCastle.Crypto.Generators; + using Org.BouncyCastle.Crypto.Parameters; + using System.Security.Cryptography; + + string password = Request.Query["password"]; + byte[] salt = RandomNumberGenerator.GetBytes(128 / 8); + Pkcs5S2ParametersGenerator gen = new Pkcs5S2ParametersGenerator(); + gen.Init(Encoding.Unicode.GetBytes(password), salt, 100_000); // Noncompliant + KeyParameter keyParam = (KeyParameter) gen.GenerateDerivedMacParameters(256); + string hashed = Convert.ToBase64String(keyParam.GetKey()); + +### How does this work? + +#### Select the correct Bcrypt parameters + +When bcrypt’s hashing function is used, it is important to select a round count that is high enough to make the function slow enough to prevent +brute force: More than 12 rounds. + +For bcrypt’s key derivation function, the number of rounds should likewise be high enough to make the function slow enough to prevent brute force: +More than 4096 rounds `(2^12)`. + This number is not the same coefficient as the first one because it uses a different algorithm. + +#### Select the correct Scrypt parameters + +If scrypt must be used, the default values of scrypt are considered secure. + +Like Argon2id, scrypt has three different parameters that can be configured. N is the CPU/memory cost parameter and must be a power of two. r is +the block size and p is the parallelization factor. + +All three parameters affect the memory and CPU usage of the algorithm. Higher values of N, r and p result in safer hashes, but come at the cost of +higher resource usage. + +For scrypt, OWASP recommends to have a hash length of at least 64 bytes, and to set N, p and r to the values of one of the following rows: + +| N (cost parameter) | p (parallelization factor) | r (block size) | +| --- | --- | --- | +| 2^17^ (`1 << 17`) | 1 | 8 | +| 2^16^ (`1 << 16`) | 2 | 8 | +| 2^15^ (`1 << 15`) | 3 | 8 | +| 2^14^ (`1 << 14`) | 5 | 8 | +| 2^13^ (`1 << 13`) | 10 | 8 | + +Every row provides the same level of defense. They only differ in the amount of CPU and RAM used: the top row has low CPU usage and high memory +usage, while the bottom row has high CPU usage and low memory usage. + +#### Select the correct PBKDF2 parameters + +If PBKDF2 must be used, be aware that default values might not be considered secure. + Depending on the algorithm used, the number of iterations +should be adjusted to ensure that the derived key is secure. The following are the recommended number of iterations for PBKDF2: + +- PBKDF2-HMAC-SHA1: 1,300,000 iterations +- PBKDF2-HMAC-SHA256: 600,000 iterations +- PBKDF2-HMAC-SHA512: 210,000 iterations + +Note that PBKDF2-HMAC-SHA256 is recommended by NIST. + Iterations are also called "rounds" depending on the library used. + +When recommended cost factors are too high in the context of the application or if the performance cost is unacceptable, a cost factor reduction +might be considered. In that case, it should not be chosen under 100,000. + +### Going the extra mile + +#### Pepper + +In a defense-in-depth security approach, **peppering** can also be used. This is a security technique where an external secret value +is added to a password before it is hashed. + This makes it more difficult for an attacker to crack the hashed passwords, as they would need to know +the secret value to generate the correct hash. + [Learn more here](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#peppering). + +## Resources + +### Documentation + +- OWASP CheatSheet - [Password Storage Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html) + +### Standards + +- OWASP - [Top 10 2021 Category A2 - Cryptographic Failures](https://owasp.org/Top10/A02_2021-Cryptographic_Failures/) +- OWASP - [Top 10 2021 Category A4 - Insecure Design](https://owasp.org/Top10/A04_2021-Insecure_Design/) +- OWASP - [Top 10 2017 Category A3 - Sensitive Data + Exposure](https://owasp.org/www-project-top-ten/2017/A3_2017-Sensitive_Data_Exposure) +- CWE - [CWE-256 - Plaintext Storage of a Password](https://cwe.mitre.org/data/definitions/256) +- CWE - [CWE-916 - Use of Password Hash With Insufficient Computational Effort](https://cwe.mitre.org/data/definitions/916) +- STIG Viewer - [Application Security and + Development: V-222542](https://stigviewer.com/stig/application_security_and_development/2023-06-08/finding/V-222542) - The application must only store cryptographic representations of passwords. \ No newline at end of file diff --git a/docs/description/S5443.md b/docs/description/S5443.md index df4ec2b..a200309 100644 --- a/docs/description/S5443.md +++ b/docs/description/S5443.md @@ -1,11 +1,16 @@ -Operating systems have global directories where any user has write access. Those folders are mostly used as temporary storage areas like `/tmp` in Linux based systems. An application manipulating files from these folders is exposed to race conditions on filenames: a malicious user can try to create a file with a predictable name before the application does. A successful attack can result in other files being accessed, modified, corrupted or deleted. This risk is even higher if the application runs with elevated permissions. - +Operating systems have global directories where any user has write access. Those folders are mostly used as temporary storage areas like +`/tmp` in Linux based systems. An application manipulating files from these folders is exposed to race conditions on filenames: a malicious +user can try to create a file with a predictable name before the application does. A successful attack can result in other files being accessed, +modified, corrupted or deleted. This risk is even higher if the application runs with elevated permissions. + In the past, it has led to the following vulnerabilities: - + - [CVE-2012-2451](https://nvd.nist.gov/vuln/detail/CVE-2012-2451) - [CVE-2015-1838](https://nvd.nist.gov/vuln/detail/CVE-2015-1838) -This rule raises an issue whenever it detects a hard-coded path to a publicly writable directory like `/tmp` (see examples bellow). It also detects access to environment variables that point to publicly writable directories, e.g., `TMP`, `TMPDIR` and `TEMP`. +This rule raises an issue whenever it detects a hard-coded path to a publicly writable directory like `/tmp` (see examples bellow). It +also detects access to environment variables that point to publicly writable directories, e.g., `TMP`, `TMPDIR` and +`TEMP`. - `/tmp` - `/var/tmp` @@ -29,9 +34,9 @@ This rule raises an issue whenever it detects a hard-coded path to a publicly wr - The application creates files with predictable names into a publicly writable folder There is a risk if you answered yes to any of those questions. - + ## Recommended Secure Coding Practices - + Out of the box, .NET is missing secure-by-design APIs to create temporary files. To overcome this, one of the following options can be used: - Use a dedicated sub-folder with tightly controlled permissions @@ -63,4 +68,6 @@ Out of the box, .NET is missing secure-by-design APIs to create temporary files. Exposure](https://owasp.org/www-project-top-ten/2017/A3_2017-Sensitive_Data_Exposure) - CWE - [CWE-377 - Insecure Temporary File](https://cwe.mitre.org/data/definitions/377) - CWE - [CWE-379 - Creation of Temporary File in Directory with Incorrect Permissions](https://cwe.mitre.org/data/definitions/379) -- [OWASP, Insecure Temporary File](https://owasp.org/www-community/vulnerabilities/Insecure_Temporary_File) \ No newline at end of file +- [OWASP, Insecure Temporary File](https://owasp.org/www-community/vulnerabilities/Insecure_Temporary_File) +- STIG Viewer - [Application Security and + Development: V-222567](https://stigviewer.com/stig/application_security_and_development/2023-06-08/finding/V-222567) - The application must not be vulnerable to race conditions. \ No newline at end of file diff --git a/docs/description/S5445.md b/docs/description/S5445.md index ad3b231..87cb639 100644 --- a/docs/description/S5445.md +++ b/docs/description/S5445.md @@ -1,35 +1,48 @@ -Temporary files are considered insecurely created when the file existence check is performed separately from the actual file creation. Such a situation can occur when creating temporary files using normal file handling functions or when using dedicated temporary file handling functions that are not atomic. - +Temporary files are considered insecurely created when the file existence check is performed separately from the actual file creation. Such a +situation can occur when creating temporary files using normal file handling functions or when using dedicated temporary file handling functions that +are not atomic. + ## Why is this an issue? - -Creating temporary files in a non-atomic way introduces race condition issues in the application’s behavior. Indeed, a third party can create a given file between when the application chooses its name and when it creates it. - -In such a situation, the application might use a temporary file that it does not entirely control. In particular, this file’s permissions might be different than expected. This can lead to trust boundary issues. - + +Creating temporary files in a non-atomic way introduces race condition issues in the application’s behavior. Indeed, a third party can create a +given file between when the application chooses its name and when it creates it. + +In such a situation, the application might use a temporary file that it does not entirely control. In particular, this file’s permissions might be +different than expected. This can lead to trust boundary issues. + ### What is the potential impact? - -Attackers with control over a temporary file used by a vulnerable application will be able to modify it in a way that will affect the application’s logic. By changing this file’s Access Control List or other operating system-level properties, they could prevent the file from being deleted or emptied. They may also alter the file’s content before or while the application uses it. - -Depending on why and how the affected temporary files are used, the exploitation of a race condition in an application can have various consequences. They can range from sensitive information disclosure to more serious application or hosting infrastructure compromise. - + +Attackers with control over a temporary file used by a vulnerable application will be able to modify it in a way that will affect the application’s +logic. By changing this file’s Access Control List or other operating system-level properties, they could prevent the file from being deleted or +emptied. They may also alter the file’s content before or while the application uses it. + +Depending on why and how the affected temporary files are used, the exploitation of a race condition in an application can have various +consequences. They can range from sensitive information disclosure to more serious application or hosting infrastructure compromise. + #### Information disclosure - -Because attackers can control the permissions set on temporary files and prevent their removal, they can read what the application stores in them. This might be especially critical if this information is sensitive. - -For example, an application might use temporary files to store users' session-related information. In such a case, attackers controlling those files can access session-stored information. This might allow them to take over authenticated users' identities and entitlements. - + +Because attackers can control the permissions set on temporary files and prevent their removal, they can read what the application stores in them. +This might be especially critical if this information is sensitive. + +For example, an application might use temporary files to store users' session-related information. In such a case, attackers controlling those +files can access session-stored information. This might allow them to take over authenticated users' identities and entitlements. + #### Attack surface extension - -An application might use temporary files to store technical data for further reuse or as a communication channel between multiple components. In that case, it might consider those files part of the trust boundaries and use their content without additional security validation or sanitation. In such a case, an attacker controlling the file content might use it as an attack vector for further compromise. - -For example, an application might store serialized data in temporary files for later use. In such a case, attackers controlling those files' content can change it in a way that will lead to an insecure deserialization exploitation. It might allow them to execute arbitrary code on the application hosting server and take it over. - + +An application might use temporary files to store technical data for further reuse or as a communication channel between multiple components. In +that case, it might consider those files part of the trust boundaries and use their content without additional security validation or sanitation. In +such a case, an attacker controlling the file content might use it as an attack vector for further compromise. + +For example, an application might store serialized data in temporary files for later use. In such a case, attackers controlling those files' +content can change it in a way that will lead to an insecure deserialization exploitation. It might allow them to execute arbitrary code on the +application hosting server and take it over. + ## How to fix it - + ### Code examples - + The following code example is vulnerable to a race condition attack because it creates a temporary file using an unsafe API function. - + #### Noncompliant code example using System.IO; @@ -60,26 +73,32 @@ The following code example is vulnerable to a race condition attack because it c } ### How does this work? - -Applications should create temporary files so that no third party can read or modify their content. It requires that the files' name, location, and permissions are carefully chosen and set. This can be achieved in multiple ways depending on the applications' technology stacks. - + +Applications should create temporary files so that no third party can read or modify their content. It requires that the files' name, location, and +permissions are carefully chosen and set. This can be achieved in multiple ways depending on the applications' technology stacks. + #### Strong security controls - -Temporary files can be created using unsafe functions and API as long as strong security controls are applied. Non-temporary file-handling functions and APIs can also be used for that purpose. - -In general, applications should ensure that attackers can not create a file before them. This turns into the following requirements when creating the files: - + +Temporary files can be created using unsafe functions and API as long as strong security controls are applied. Non-temporary file-handling +functions and APIs can also be used for that purpose. + +In general, applications should ensure that attackers can not create a file before them. This turns into the following requirements when creating +the files: + - Files should be created in a non-public directory. - File names should be unique. - File names should be unpredictable. They should be generated using a cryptographically secure random generator. - File creation should fail if a target file already exists. Moreover, when possible, it is recommended that applications destroy temporary files after they have finished using them. - -Here the example compliant code uses the `Path.GetTempPath` and `Path.GetRandomFileName` functions to generate a unique random file name. The file is then open with the `FileMode.CreateNew` option that will ensure the creation fails if the file already exists. The `FileShare.None` option will additionally prevent the file from being opened again by any process. To finish, this code ensures the file will get destroyed once the application has finished using it with the `FileOptions.DeleteOnClose` option. - + +Here the example compliant code uses the `Path.GetTempPath` and `Path.GetRandomFileName` functions to generate a unique +random file name. The file is then open with the `FileMode.CreateNew` option that will ensure the creation fails if the file already +exists. The `FileShare.None` option will additionally prevent the file from being opened again by any process. To finish, this code ensures +the file will get destroyed once the application has finished using it with the `FileOptions.DeleteOnClose` option. + ## Resources - + ### Documentation - [OWASP](https://owasp.org/www-community/vulnerabilities/Insecure_Temporary_File) - Insecure Temporary File @@ -90,4 +109,6 @@ Here the example compliant code uses the `Path.GetTempPath` and `Path.GetRandomF - OWASP - [Top 10 2017 Category A9 - Using Components with Known Vulnerabilities](https://owasp.org/www-project-top-ten/2017/A9_2017-Using_Components_with_Known_Vulnerabilities) - CWE - [CWE-377 - Insecure Temporary File](https://cwe.mitre.org/data/definitions/377) -- CWE - [CWE-379 - Creation of Temporary File in Directory with Incorrect Permissions](https://cwe.mitre.org/data/definitions/379) \ No newline at end of file +- CWE - [CWE-379 - Creation of Temporary File in Directory with Incorrect Permissions](https://cwe.mitre.org/data/definitions/379) +- STIG Viewer - [Application Security and + Development: V-222567](https://stigviewer.com/stig/application_security_and_development/2023-06-08/finding/V-222567) - The application must not be vulnerable to race conditions. \ No newline at end of file diff --git a/docs/description/S5542.md b/docs/description/S5542.md index 2d77b75..15d35b6 100644 --- a/docs/description/S5542.md +++ b/docs/description/S5542.md @@ -1,9 +1,10 @@ This vulnerability exposes encrypted data to a number of attacks whose goal is to recover the plaintext. - + ## Why is this an issue? - -Encryption algorithms are essential for protecting sensitive information and ensuring secure communications in a variety of domains. They are used for several important reasons: - + +Encryption algorithms are essential for protecting sensitive information and ensuring secure communications in a variety of domains. They are used +for several important reasons: + - Confidentiality, privacy, and intellectual property protection - Security during transmission or on storage devices - Data integrity, general trust, and authentication @@ -13,36 +14,40 @@ When selecting encryption algorithms, tools, or combinations, you should also co 1. No encryption is unbreakable. 2. The strength of an encryption algorithm is usually measured by the effort required to crack it within a reasonable time frame. -For these reasons, as soon as cryptography is included in a project, it is important to choose encryption algorithms that are considered strong and secure by the cryptography community. - -For AES, the weakest mode is ECB (Electronic Codebook). Repeated blocks of data are encrypted to the same value, making them easy to identify and reducing the difficulty of recovering the original cleartext. - -Unauthenticated modes such as CBC (Cipher Block Chaining) may be used but are prone to attacks that manipulate the ciphertext. They must be used with caution. - +For these reasons, as soon as cryptography is included in a project, it is important to choose encryption algorithms that are considered strong and +secure by the cryptography community. + +For AES, the weakest mode is ECB (Electronic Codebook). Repeated blocks of data are encrypted to the same value, making them easy to identify and +reducing the difficulty of recovering the original cleartext. + +Unauthenticated modes such as CBC (Cipher Block Chaining) may be used but are prone to attacks that manipulate the ciphertext. They must be used +with caution. + For RSA, the weakest algorithms are either using it without padding or using the PKCS1v1.5 padding scheme. - + ### What is the potential impact? - + The cleartext of an encrypted message might be recoverable. Additionally, it might be possible to modify the cleartext of an encrypted message. - + Below are some real-world scenarios that illustrate possible impacts of an attacker exploiting the vulnerability. - + #### Theft of sensitive data - + The encrypted message might contain data that is considered sensitive and should not be known to third parties. - + By using a weak algorithm the likelihood that an attacker might be able to recover the cleartext drastically increases. - + #### Additional attack surface - -By modifying the cleartext of the encrypted message it might be possible for an attacker to trigger other vulnerabilities in the code. Encrypted values are often considered trusted, since under normal circumstances it would not be possible for a third party to modify them. - + +By modifying the cleartext of the encrypted message it might be possible for an attacker to trigger other vulnerabilities in the code. Encrypted +values are often considered trusted, since under normal circumstances it would not be possible for a third party to modify them. + ## How to fix it in .NET - + ### Code examples - + #### Noncompliant code example - + Example with a symmetric cipher, AES: using System.Security.Cryptography; @@ -59,7 +64,7 @@ Example with a symmetric cipher, AES: } Note that Microsoft has marked derived cryptographic types like `AesManaged` as no longer recommended for use. - + Example with an asymmetric cipher, RSA: using System.Security.Cryptography; @@ -71,7 +76,7 @@ Example with an asymmetric cipher, RSA: } #### Compliant solution - + For the AES symmetric cipher, use the GCM mode: using System.Security.Cryptography; @@ -92,17 +97,18 @@ For the RSA asymmetric cipher, use the Optimal Asymmetric Encryption Padding (OA } ### How does this work? - + As a rule of thumb, use the cryptographic algorithms and mechanisms that are considered strong by the cryptographic community. - + Appropriate choices are currently the following. - + #### For AES: use authenticated encryption modes - + The best-known authenticated encryption mode for AES is Galois/Counter mode (GCM). - -GCM mode combines encryption with authentication and integrity checks using a cryptographic hash function and provides both confidentiality and authenticity of data. - + +GCM mode combines encryption with authentication and integrity checks using a cryptographic hash function and provides both confidentiality and +authenticity of data. + Other similar modes are: - CCM: `Counter with CBC-MAC` @@ -111,14 +117,16 @@ Other similar modes are: - IAPM: `Integer Authenticated Parallelizable Mode` - OCB: `Offset Codebook Mode` -It is also possible to use AES-CBC with HMAC for integrity checks. However, it is considered more straightforward to use AES-GCM directly instead. - +It is also possible to use AES-CBC with HMAC for integrity checks. However, it is considered more straightforward to use AES-GCM directly +instead. + #### For RSA: use the OAEP scheme - -The Optimal Asymmetric Encryption Padding scheme (OAEP) adds randomness and a secure hash function that strengthens the regular inner workings of RSA. - + +The Optimal Asymmetric Encryption Padding scheme (OAEP) adds randomness and a secure hash function that strengthens the regular inner workings of +RSA. + ## Resources - + ### Articles & blog posts - [Microsoft, Timing vulnerabilities with CBC-mode diff --git a/docs/description/S5547.md b/docs/description/S5547.md index f8e4f84..29854e9 100644 --- a/docs/description/S5547.md +++ b/docs/description/S5547.md @@ -1,9 +1,10 @@ This vulnerability makes it possible that the cleartext of the encrypted message might be recoverable without prior knowledge of the key. - + ## Why is this an issue? - -Encryption algorithms are essential for protecting sensitive information and ensuring secure communication in various domains. They are used for several important reasons: - + +Encryption algorithms are essential for protecting sensitive information and ensuring secure communication in various domains. They are used for +several important reasons: + - Confidentiality, privacy, and intellectual property protection - Security during transmission or on storage devices - Data integrity, general trust, and authentication @@ -13,30 +14,32 @@ When selecting encryption algorithms, tools, or combinations, you should also co 1. No encryption is unbreakable. 2. The strength of an encryption algorithm is usually measured by the effort required to crack it within a reasonable time frame. -For these reasons, as soon as cryptography is included in a project, it is important to choose encryption algorithms that are considered strong and secure by the cryptography community. - +For these reasons, as soon as cryptography is included in a project, it is important to choose encryption algorithms that are considered strong and +secure by the cryptography community. + ### What is the potential impact? - + The cleartext of an encrypted message might be recoverable. Additionally, it might be possible to modify the cleartext of an encrypted message. - + Below are some real-world scenarios that illustrate some impacts of an attacker exploiting the vulnerability. - + #### Theft of sensitive data - + The encrypted message might contain data that is considered sensitive and should not be known to third parties. - + By using a weak algorithm the likelihood that an attacker might be able to recover the cleartext drastically increases. - + #### Additional attack surface - -By modifying the cleartext of the encrypted message it might be possible for an attacker to trigger other vulnerabilities in the code. Encrypted values are often considered trusted, since under normal circumstances it would not be possible for a third party to modify them. - + +By modifying the cleartext of the encrypted message it might be possible for an attacker to trigger other vulnerabilities in the code. Encrypted +values are often considered trusted, since under normal circumstances it would not be possible for a third party to modify them. + ## How to fix it in .NET - + ### Code examples - + The following code contains examples of algorithms that are not considered highly resistant to cryptanalysis and thus should be avoided. - + #### Noncompliant code example using System.Security.Cryptography; @@ -59,19 +62,20 @@ The following code contains examples of algorithms that are not considered highl } ### How does this work? - + #### Use a secure algorithm - -It is highly recommended to use an algorithm that is currently considered secure by the cryptographic community. A common choice for such an algorithm is the Advanced Encryption Standard (AES). - + +It is highly recommended to use an algorithm that is currently considered secure by the cryptographic community. A common choice for such an +algorithm is the Advanced Encryption Standard (AES). + For block ciphers, it is not recommended to use algorithms with a block size that is smaller than 128 bits. - + ## How to fix it in BouncyCastle - + ### Code examples - + The following code contains examples of algorithms that are not considered highly resistant to cryptanalysis and thus should be avoided. - + #### Noncompliant code example using Org.BouncyCastle.Crypto.Engines; @@ -93,15 +97,16 @@ The following code contains examples of algorithms that are not considered highl } ### How does this work? - + #### Use a secure algorithm - -It is highly recommended to use an algorithm that is currently considered secure by the cryptographic community. A common choice for such an algorithm is the Advanced Encryption Standard (AES). - + +It is highly recommended to use an algorithm that is currently considered secure by the cryptographic community. A common choice for such an +algorithm is the Advanced Encryption Standard (AES). + For block ciphers, it is not recommended to use algorithms with a block size that is smaller than 128 bits. - + ## Resources - + ### Standards - OWASP - [Top 10 2021 Category A2 - Cryptographic Failures](https://owasp.org/Top10/A02_2021-Cryptographic_Failures/) @@ -109,4 +114,6 @@ For block ciphers, it is not recommended to use algorithms with a block size tha Exposure](https://owasp.org/www-project-top-ten/2017/A3_2017-Sensitive_Data_Exposure) - OWASP - [Top 10 2017 Category A6 - Security Misconfiguration](https://owasp.org/www-project-top-ten/2017/A6_2017-Security_Misconfiguration) -- CWE - [CWE-327 - Use of a Broken or Risky Cryptographic Algorithm](https://cwe.mitre.org/data/definitions/327) \ No newline at end of file +- CWE - [CWE-327 - Use of a Broken or Risky Cryptographic Algorithm](https://cwe.mitre.org/data/definitions/327) +- STIG Viewer - [Application Security and + Development: V-222396](https://stigviewer.com/stig/application_security_and_development/2023-06-08/finding/V-222396) - The application must implement DoD-approved encryption to protect the confidentiality of remote access sessions. \ No newline at end of file diff --git a/docs/description/S5659.md b/docs/description/S5659.md index 5edb127..0598478 100644 --- a/docs/description/S5659.md +++ b/docs/description/S5659.md @@ -1,27 +1,35 @@ This vulnerability allows forging of JSON Web Tokens to impersonate other users. - + ## Why is this an issue? - -JSON Web Tokens (JWTs), a popular method of securely transmitting information between parties as a JSON object, can become a significant security risk when they are not properly signed with a robust cipher algorithm, left unsigned altogether, or if the signature is not verified. This vulnerability class allows malicious actors to craft fraudulent tokens, effectively impersonating user identities. In essence, the integrity of a JWT hinges on the strength and presence of its signature. - + +JSON Web Tokens (JWTs), a popular method of securely transmitting information between parties as a JSON object, can become a significant security +risk when they are not properly signed with a robust cipher algorithm, left unsigned altogether, or if the signature is not verified. This +vulnerability class allows malicious actors to craft fraudulent tokens, effectively impersonating user identities. In essence, the integrity of a JWT +hinges on the strength and presence of its signature. + ### What is the potential impact? - -When a JSON Web Token is not appropriately signed with a strong cipher algorithm or if the signature is not verified, it becomes a significant threat to data security and the privacy of user identities. - + +When a JSON Web Token is not appropriately signed with a strong cipher algorithm or if the signature is not verified, it becomes a significant +threat to data security and the privacy of user identities. + #### Impersonation of users - -JWTs are commonly used to represent user authorization claims. They contain information about the user’s identity, user roles, and access rights. When these tokens are not securely signed, it allows an attacker to forge them. In essence, a weak or missing signature gives an attacker the power to craft a token that could impersonate any user. For instance, they could create a token for an administrator account, gaining access to high-level permissions and sensitive data. - + +JWTs are commonly used to represent user authorization claims. They contain information about the user’s identity, user roles, and access rights. +When these tokens are not securely signed, it allows an attacker to forge them. In essence, a weak or missing signature gives an attacker the power to +craft a token that could impersonate any user. For instance, they could create a token for an administrator account, gaining access to high-level +permissions and sensitive data. + #### Unauthorized data access - -When a JWT is not securely signed, it can be tampered with by an attacker, and the integrity of the data it carries cannot be trusted. An attacker can manipulate the content of the token and grant themselves permissions they should not have, leading to unauthorized data access. - + +When a JWT is not securely signed, it can be tampered with by an attacker, and the integrity of the data it carries cannot be trusted. An attacker +can manipulate the content of the token and grant themselves permissions they should not have, leading to unauthorized data access. + ## How to fix it in Jwt.Net - + ### Code examples - + The following code contains an example of JWT decoding without verification of the signature. - + #### Noncompliant code example using JWT; @@ -62,15 +70,18 @@ When using `JwtBuilder`, make sure to call `MustVerifySignature()`. } ### How does this work? - + #### Verify the signature of your tokens - -Resolving a vulnerability concerning the validation of JWT token signatures is mainly about incorporating a critical step into your process: validating the signature every time a token is decoded. Just having a signed token using a secure algorithm is not enough. If you are not validating signatures, they are not serving their purpose. - -Every time your application receives a JWT, it needs to decode the token to extract the information contained within. It is during this decoding process that the signature of the JWT should also be checked. - + +Resolving a vulnerability concerning the validation of JWT token signatures is mainly about incorporating a critical step into your process: +validating the signature every time a token is decoded. Just having a signed token using a secure algorithm is not enough. If you are not validating +signatures, they are not serving their purpose. + +Every time your application receives a JWT, it needs to decode the token to extract the information contained within. It is during this decoding +process that the signature of the JWT should also be checked. + To resolve the issue, follow these instructions: - + 1. Use framework-specific functions for signature verification: Most programming frameworks that support JWTs provide specific functions to not only decode a token but also validate its signature simultaneously. Make sure to use these functions when handling incoming tokens. 2. Handle invalid signatures appropriately: If a JWT’s signature does not validate correctly, it means the token is not trustworthy, indicating @@ -79,20 +90,24 @@ To resolve the issue, follow these instructions: 3. Incorporate signature validation in your tests: When you are writing tests for your application, include tests that check the signature validation functionality. This can help you catch any instances where signature verification might be unintentionally skipped or bypassed. -By following these practices, you can ensure the security of your application’s JWT handling process, making it resistant to attacks that rely on tampering with tokens. Validation of the signature needs to be an integral and non-negotiable part of your token handling process. - +By following these practices, you can ensure the security of your application’s JWT handling process, making it resistant to attacks that rely on +tampering with tokens. Validation of the signature needs to be an integral and non-negotiable part of your token handling process. + ### Going the extra mile - + #### Securely store your secret keys - -Ensure that your secret keys are stored securely. They should not be hard-coded into your application code or checked into your version control system. Instead, consider using environment variables, secure key management systems, or vault services. - + +Ensure that your secret keys are stored securely. They should not be hard-coded into your application code or checked into your version control +system. Instead, consider using environment variables, secure key management systems, or vault services. + #### Rotate your secret keys - -Even with the strongest cipher algorithms, there is a risk that your secret keys may be compromised. Therefore, it is a good practice to periodically rotate your secret keys. By doing so, you limit the amount of time that an attacker can misuse a stolen key. When you rotate keys, be sure to allow a grace period where tokens signed with the old key are still accepted to prevent service disruptions. - + +Even with the strongest cipher algorithms, there is a risk that your secret keys may be compromised. Therefore, it is a good practice to +periodically rotate your secret keys. By doing so, you limit the amount of time that an attacker can misuse a stolen key. When you rotate keys, be +sure to allow a grace period where tokens signed with the old key are still accepted to prevent service disruptions. + ## Resources - + ### Standards - OWASP - [Top 10 2021 Category A2 - Cryptographic Failures](https://owasp.org/Top10/A02_2021-Cryptographic_Failures/) diff --git a/docs/description/S5693.md b/docs/description/S5693.md index b0e771f..5ce52a5 100644 --- a/docs/description/S5693.md +++ b/docs/description/S5693.md @@ -1,13 +1,14 @@ -Rejecting requests with significant content length is a good practice to control the network traffic intensity and thus resource consumption in order to prevent DoS attacks. - +Rejecting requests with significant content length is a good practice to control the network traffic intensity and thus resource consumption in +order to prevent DoS attacks. + ## Ask Yourself Whether - + - size limits are not defined for the different resources of the web application. - the web application is not protected by [rate limiting](https://en.wikipedia.org/wiki/Rate_limiting) features. - the web application infrastructure has limited resources. There is a risk if you answered yes to any of those questions. - + ## Recommended Secure Coding Practices - For most of the features of an application, it is recommended to limit the size of requests to: @@ -15,7 +16,7 @@ There is a risk if you answered yes to any of those questions. - lower or equal to 2mb for other requests. It is recommended to customize the rule with the limit values that correspond to the web application. - + ## Sensitive Code Example using Microsoft.AspNetCore.Mvc; diff --git a/docs/description/S5753.md b/docs/description/S5753.md index 1460684..5ff678e 100644 --- a/docs/description/S5753.md +++ b/docs/description/S5753.md @@ -1,24 +1,26 @@ -ASP.NET 1.1+ comes with a feature called *Request Validation*, preventing the server to accept content containing un-encoded HTML. This feature comes as a first protection layer against Cross-Site Scripting (XSS) attacks and act as a simple Web Application Firewall (WAF) rejecting requests potentially containing malicious content. - +ASP.NET 1.1+ comes with a feature called *Request Validation*, preventing the server to accept content containing un-encoded HTML. This +feature comes as a first protection layer against Cross-Site Scripting (XSS) attacks and act as a simple Web Application Firewall (WAF) rejecting +requests potentially containing malicious content. + While this feature is not a silver bullet to prevent all XSS attacks, it helps to catch basic ones. It will for example prevent `