
ãã®èšäºã§ã¯ãPVS-Studioéçã¢ãã©ã€ã¶ãŒã䜿çšããŠOpenRAãããžã§ã¯ãã確èªããæ¹æ³ã«ã€ããŠèª¬æããŸããOpenRAãšã¯äœã§ããïŒããã¯ããªã¢ã«ã¿ã€ã ã®æŠç¥ã²ãŒã ãäœæããããã®ãªãŒãã³ãœãŒã¹ã®ã²ãŒã ãšã³ãžã³ã§ãããã®èšäºã§ã¯ãåæãã©ã®ããã«å®è¡ããããããããžã§ã¯ãèªäœã®ã©ã®æ©èœãçºèŠãããããPVS-Studioãã©ã®ãããªè峿·±ãããªã¬ãŒãæäŸãããã«ã€ããŠèª¬æããŸãããããŠãã¡ãããããã§ã¯ããããžã§ã¯ãã®æ€èšŒããã»ã¹ãããå¿«é©ã«ããã¢ãã©ã€ã¶ãŒã®æ©èœã®ããã€ããæ€èšããŸãã
OpenRA

ã¬ãã¥ãŒçšã«éžæããããããžã§ã¯ãã¯ãCommandïŒConquerïŒRedAlertã®ãããªã²ãŒã ã¹ã¿ã€ã«ã®RTSã²ãŒã ãšã³ãžã³ã§ãã詳现ã«ã€ããŠã¯ããŠã§ããµã€ããã芧ãã ããããœãŒã¹ã³ãŒãã¯CïŒã§èšè¿°ãããŠããããªããžããªã§è¡šç€ºããã³äœ¿çšã§ããŸãã
OpenRAã¯ã3ã€ã®çç±ã§ã¬ãã¥ãŒã®ããã«éžæãããŸããããŸããå€ãã®äººãèå³ãæã£ãŠããããã§ãããããã«ããããªããžããªã¯8000ãè¶ ããæãåéããŠãããããããã¯GitHubã®äœæ°ã«é©çšãããŸããæ¬¡ã«ãOpenRAã³ãŒãããŒã¹ã«ã¯1285åã®ãã¡ã€ã«ãå«ãŸããŠããŸããéåžžããã®éã¯ãããŸãããã°ããããã®äžã§è峿·±ãããªã¬ãŒãèŠã€ããã®ã«ååã§ãããããŠç¬¬äžã«...ã²ãŒã ãšã³ãžã³ã¯ãã£ãããã§ãã
äœåãªããžãã£ã
ç§ã¯PVS-Studioã䜿çšããŠOpenRAãåæããæåã¯ãã®çµæã«è§ŠçºãããŸããã

éåžžã«å€ãã®é«èŠåã®äžã§ãç§ã¯ç¢ºãã«éåžžã«ç°ãªãå¿çãããããèŠã€ããããšãã§ãããšæ±ºããŸããããããŠãã¡ããã圌ãã«åºã¥ããŠãç§ã¯æãã¯ãŒã«ã§æãè峿·±ãèšäºãæžããŸããããããããã¯ãããŸããã§ããïŒ
èŠåèªäœãèŠãã ãã§ããã¹ãŠãããã«å®è¡ãããŸããã 1306ã®é«èŠåã®ãã¡ã1,277ãV3144蚺æã«é¢é£ä»ããããŠããŸããã ããã®ãã¡ã€ã«ã¯copyleftã©ã€ã»ã³ã¹ã§ããŒã¯ãããŠãããããæŽŸçãœãŒã¹ã³ãŒããéãå¿ èŠããããŸãããªã©ã®ã¡ãã»ãŒãžã衚瀺ãããŸãããã®èšºæã«ã€ããŠã¯ããã¡ãã§è©³ãã説æããŠããŸãã
OpenRAã¯ãã§ã«ãªãŒãã³ãœãŒã¹ãããžã§ã¯ãã§ãããããæããã«ããã®ãããªèšç»ã®ä»çµã¿ã¯ç§ã«ã¯ãŸã£ããèå³ããããŸããã§ããããããã£ãŠããã°ã®æ®ãã®éšåã®è¡šç€ºã劚ããªãããã«ãé衚瀺ã«ããå¿ èŠããããŸãããVisual Studioã®ãã©ã°ã€ã³ã䜿çšããŠããã®ã§ãç°¡åã«è¡ããŸãããV3144ã¢ã©ãŒãã®1ã€ãå³ã¯ãªãã¯ããéããã¡ãã¥ãŒã§[ãã¹ãŠã®V3144ãšã©ãŒãé衚瀺]ãéžæããå¿ èŠããããŸããã

ã¢ãã©ã€ã¶ãŒãªãã·ã§ã³ã®[æ€åºå¯èœãªãšã©ãŒïŒCïŒïŒ]ã»ã¯ã·ã§ã³ã«ç§»åããŠããã°ã«è¡šç€ºããèŠåãéžæããããšãã§ããŸãã

Visual Studio 2019ã®ãã©ã°ã€ã³ã䜿çšããŠãããã«ç§»åããã«ã¯ããããã¡ãã¥ãŒã®[æ¡åŒµæ©èœ]-> [PVS-ã¹ã¿ãžãª]-> [ãªãã·ã§ã³]ãã¯ãªãã¯ããå¿ èŠããããŸãã
詊éšçµæ
V3144ããªã¬ãŒããã£ã«ã¿ãŒã§é€å€ããã åŸããã°ã«èšé²ãããèŠåã¯å€§å¹ ã«å°ãªããªããŸãã

ããã«ãããããããç§ãã¡ã¯ãããã®äžã§è峿·±ãç¬éãèŠã€ããããšãã§ããŸããã
ç¡æå³ãªæ¡ä»¶
ããªãã®æ°ã®ããªã¬ãŒãäžèŠãªãã§ãã¯ã瀺ããŠããŸãããéåžžã人ã ã¯ãã®ãããªã³ãŒããæå³çã«èšè¿°ããªããããããã¯ãšã©ãŒã瀺ããŠããå¯èœæ§ããããŸãããã ããOpenRAã§ã¯ããããã®äžèŠãªæ¡ä»¶ãæå³çã«è¿œå ãããããã«èŠããããšããããããŸããäŸãã°ïŒ
public virtual void Tick()
{
....
Active = !Disabled && Instances.Any(i => !i.IsTraitPaused);
if (!Active)
return;
if (Active)
{
....
}
}
ã¢ãã©ã€ã¶ãŒã®èŠåïŒV3022åŒãã¢ã¯ãã£ããã¯åžžã«çã§ãã SupportPowerManager.cs 206
PVS-Studioã¯ãActiveãfalseã®å Žåãå®è¡ãå°éããªãããã2çªç®ã®ãã§ãã¯ã¯ç¡æå³ã§ãããšæ£ããææããŠããŸããããã¯ééããããããŸãããããããšæžãããã®ã ãšæããŸããäœã®ããã«ïŒããŠããªãã§ããïŒ
ãããããç§ãã¡ã®åã«ããçš®ã®äžæçãªè§£æ±ºçãããããã®æ¹èšã¯ãåŸã§ãæ®ãããŠããŸãããã®ãããªå Žåãã¢ãã©ã€ã¶ãŒãéçºè ã«ãã®ãããªæ¬ é¥ãæãåºãããã®ã¯éåžžã«äŸ¿å©ã§ãã
ãäžãäžã«åããŠããã1ã€ã®ãã§ãã¯ãèŠãŠã¿ãŸãããã
Pair<string, bool>[] MakeComponents(string text)
{
....
if (highlightStart > 0 && highlightEnd > highlightStart) // <=
{
if (highlightStart > 0) // <=
{
// Normal line segment before highlight
var lineNormal = line.Substring(0, highlightStart);
components.Add(Pair.New(lineNormal, false));
}
// Highlight line segment
var lineHighlight = line.Substring(
highlightStart + 1,
highlightEnd - highlightStart â 1
);
components.Add(Pair.New(lineHighlight, true));
line = line.Substring(highlightEnd + 1);
}
else
{
// Final normal line segment
components.Add(Pair.New(line, false));
break;
}
....
}
ã¢ãã©ã€ã¶ãŒã®èŠåïŒV3022åŒ 'highlightStart> 0'ã¯åžžã«trueã§ãã LabelWithHighlightWidget.cs 54
ç¹°ãè¿ããŸãããåãã§ãã¯ãå®å šã«ç¡æå³ã§ããããšã¯æããã§ãããã€ã©ã€ãã¹ã¿ãŒãå€ã¯2åãã§ãã¯ããã飿¥ããè¡ã§ãã§ãã¯ãããŸãããšã©ãŒïŒæ¡ä»¶ã®1ã€ã§ããã¹ãçšã«ééã£ã倿°ãéžæãããå¯èœæ§ããããŸãããããã«ããããããäœã§ãããã確å®ã«èšãã®ã¯é£ããã§ãã 1ã€æãããªããšã¯ãã³ãŒãã調æ»ããŠä¿®æ£ããå¿ èŠãããããäœããã®çç±ã§è¿œå ã®æ€èšŒãå¿ èŠãªå Žåã¯èª¬æãæ®ãå¿ èŠããããšããããšã§ãã
å¥ã®åæ§ã®ãã€ã³ãããããŸãïŒ
public static void ButtonPrompt(....)
{
....
var cancelButton = prompt.GetOrNull<ButtonWidget>(
"CANCEL_BUTTON"
);
....
if (onCancel != null && cancelButton != null)
{
cancelButton.Visible = true;
cancelButton.Bounds.Y += headerHeight;
cancelButton.OnClick = () =>
{
Ui.CloseWindow();
if (onCancel != null)
onCancel();
};
if (!string.IsNullOrEmpty(cancelText) && cancelButton != null)
cancelButton.GetText = () => cancelText;
}
....
}
ã¢ãã©ã€ã¶ãŒã®èŠåïŒV3063æ¡ä»¶åŒã®äžéšã¯ãè©äŸ¡ããããšåžžã«trueã«ãªããŸãïŒcancelButtonïŒ= NullãGetOrNullã¡ãœããã«ãã£ãŠè¿ãããå€ããã®å€æ°ã«æžã蟌ãŸãããããConfirmationDialogs.cs
78cancelButtonã¯å®éã«nullã«ãªãå¯èœæ§ããããŸãããã ããæ¡ä»¶ã¹ããŒãã¡ã³ãã®æ¬æã§cancelButtonãnullã«å€ããããšã¯ãªããšèããã®ã¯è«ççã§ããããã«ããããããããŸã ãã§ãã¯ããããŸããå€éšæ¡ä»¶ã«æ³šæãæããªããšãäžè¬ã«å¥åŠãªç¶æ³ãçºçããŸããæåã«å€æ°ã®ããããã£ã«ã¢ã¯ã»ã¹ããæ¬¡ã«éçºè ã確èªããããšã«ããŸãã-ããã¯ãŸã nullãã©ããïŒ
æåã¯ããããžã§ã¯ããã== "æŒç®åãã®ãªãŒããŒããŒãã«é¢é£ããç¹å®ã®ããžãã¯ã䜿çšããŠããå¯èœæ§ããããšæ³å®ããŸãããç§ã®æèŠã§ã¯ããããžã§ã¯ãã®åç §ã¿ã€ãã«é¡äŒŒãããã®ãå®è£ ããããšã¯ç©è°ãéžãã¢ã€ãã¢ã§ããããã§ããç°åžžãªåäœã«ãããä»ã®éçºè ãã³ãŒããçè§£ããã®ãé£ãããªããŸããåæã«ããã®ãããªããªãã¯ãå ããªãç¶æ³ãæ³åããã®ã¯é£ããã§ããå Žåã«ãã£ãŠã¯ãããã䟿å©ãªè§£æ±ºçã«ãªãå¯èœæ§ããããŸãã
ããšãã°ãUnityã²ãŒã ãšã³ãžã³ã§ã¯ãã== "ãæŒç®åãUnityEngine.Objectã¯ã©ã¹ã«å¯ŸããŠåå®çŸ©ãããŸãããªã³ã¯ã§å ¥æå¯èœãªå ¬åŒããã¥ã¡ã³ãã¯ããã®ã¯ã©ã¹ã®ã€ã³ã¹ã¿ã³ã¹ãnullãšæ¯èŒããããšã瀺ããŠããŸãéåžžã©ããåäœããŸããããŸãã確ãã«éçºè ã¯ãã®ãããªçããããžãã¯ãå®è£ ããçç±ããããŸããã
OpenRAã§ãã®ãããªãã®ã¯èŠã€ãããŸããã§ãã:)ããããã£ãŠã以åã«æ€èšãããnullã®ãã§ãã¯ã«æå³ãããå Žåãããã¯å¥ã®ãã®ã§æ§æãããŸãã
PVS-Studioã¯ãããã«ããã€ãã®åæ§ã®ç¬éãæ€åºã§ããŸããããããã«ãã¹ãŠããªã¹ãããå¿ èŠã¯ãããŸãããåãããžãã£ããèŠãã®ã¯ãŸã éå±ã§ãã幞ããªããšã«ïŒãŸãã¯ããã§ã¯ãªãïŒãã¢ãã©ã€ã¶ãŒã¯ä»ã®å¥åŠãªããšãèŠã€ããããšãã§ããŸããã
å°éäžèœãªã³ãŒã
void IResolveOrder.ResolveOrder(Actor self, Order order)
{
....
if (!order.Queued || currentTransform == null)
return;
if (!order.Queued && currentTransform.NextActivity != null)
currentTransform.NextActivity.Cancel(self);
....
}
ã¢ãã©ã€ã¶ãŒã®èŠåïŒV3022åŒ 'ïŒOrder.Queued && currentTransform.NextActivityïŒ= Null'ã¯åžžã«falseã§ãã TransformsIntoTransforms.cs44
ããã§ãç¡æå³ãªãã§ãã¯ããããŸãããã ããåã®ãã®ãšã¯ç°ãªããããã§ã¯è¿œå ã®æ¡ä»¶ã ãã§ãªããå®éã«éæã§ããªãã³ãŒãã瀺ããŸãã以åã«èããããŠããåžžã«çã®ãã§ãã¯ã¯ãå®éã«ã¯ããã°ã©ã ã®åäœã«åœ±é¿ãäžããŸããã§ããããããã¯ã³ãŒãããåé€ããããšããæ®ãããšãã§ããŸã-äœã倿ŽãããŸããã
ããã§ãå¥åŠãªãã§ãã¯ã¯ãã³ãŒãã®äžéšãå®è¡ãããŠããªããšããäºå®ã«ã€ãªãããŸããåæã«ãããã§ä¿®æ£ãšããŠã©ã®ãããªå€æŽãè¡ãã¹ãããæšæž¬ããããšã¯å°é£ã§ããæãåçŽã§æãå¿«é©ãªã±ãŒã¹ã§ã¯ãå°éäžèœãªã³ãŒãã¯åã«å®è¡ãããã¹ãã§ã¯ãããŸãããããããã°ééãã¯ãããŸãããããããããã°ã©ããŒãçŸã®ããã ãã«æå³çã«ãã®è¡ãæžããã®ã§ã¯ãªãããšæããŸãã
ã³ã³ã¹ãã©ã¯ã¿ãŒã®åæåãããŠããªã倿°
public class CursorSequence
{
....
public readonly ISpriteFrame[] Frames;
public CursorSequence(
FrameCache cache,
string name,
string cursorSrc,
string palette,
MiniYaml info
)
{
var d = info.ToDictionary();
Start = Exts.ParseIntegerInvariant(d["Start"].Value);
Palette = palette;
Name = name;
if (
(d.ContainsKey("Length") && d["Length"].Value == "*") ||
(d.ContainsKey("End") && d["End"].Value == "*")
)
Length = Frames.Length - Start;
else if (d.ContainsKey("Length"))
Length = Exts.ParseIntegerInvariant(d["Length"].Value);
else if (d.ContainsKey("End"))
Length = Exts.ParseIntegerInvariant(d["End"].Value) - Start;
else
Length = 1;
Frames = cache[cursorSrc]
.Skip(Start)
.Take(Length)
.ToArray();
....
}
}
ã¢ãã©ã€ã¶ãŒã®èŠåïŒV3128ããã¬ãŒã ããã£ãŒã«ãã¯ãã³ã³ã¹ãã©ã¯ã¿ãŒã§åæåãããåã«äœ¿çšãããŸããCursorSequence.cs35
éåžžã«äžå¿«ãªç¬éãåæåãããŠããªã倿°ããLengthããããã£ã®å€ãååŸããããšãããšãå¿ ç¶çã«NullReferenceExceptionãã¹ããŒãããŸããéåžžã®ç¶æ³ã§ã¯ããã®ãããªãšã©ãŒãèŠéããããããšã¯ã»ãšãã©ãããŸããããã¯ã©ã¹ã®ã€ã³ã¹ã¿ã³ã¹ãäœæã§ããªãããšã¯ç°¡åã«æããã«ãªããŸãããã ããããã§ã¯ãæ¡ä»¶ã次ã®å Žåã«ã®ã¿äŸå€ãã¹ããŒãããŸã
(d.ContainsKey("Length") && d["Length"].Value == "*") ||
(d.ContainsKey("End") && d["End"].Value == "*")
æ¬åœã«ãªããŸãã
ãã¹ãŠãããŸãæ©èœããããã«ã³ãŒããä¿®æ£ããå¿ èŠããããã©ããã倿ããã®ã¯é£ããã§ãã颿°ã¯æ¬¡ã®ããã«ãªã£ãŠããã¯ãã§ãã
public CursorSequence(....)
{
var d = info.ToDictionary();
Start = Exts.ParseIntegerInvariant(d["Start"].Value);
Palette = palette;
Name = name;
ISpriteFrame[] currentCache = cache[cursorSrc];
if (
(d.ContainsKey("Length") && d["Length"].Value == "*") ||
(d.ContainsKey("End") && d["End"].Value == "*")
)
Length = currentCache.Length - Start;
else if (d.ContainsKey("Length"))
Length = Exts.ParseIntegerInvariant(d["Length"].Value);
else if (d.ContainsKey("End"))
Length = Exts.ParseIntegerInvariant(d["End"].Value) - Start;
else
Length = 1;
Frames = currentCache
.Skip(Start)
.Take(Length)
.ToArray();
....
}
ãã®ããŒãžã§ã³ã§ã¯ãæå®ãããåé¡ã¯ãããŸããããéçºè ã ããå ã®ã¢ã€ãã¢ã«ã©ãã ã察å¿ããŠããããèšãããšãã§ããŸãã
æœåšçãªã¿ã€ããã¹
public void Resize(int width, int height)
{
var oldMapTiles = Tiles;
var oldMapResources = Resources;
var oldMapHeight = Height;
var oldMapRamp = Ramp;
var newSize = new Size(width, height);
....
Tiles = CellLayer.Resize(oldMapTiles, newSize, oldMapTiles[MPos.Zero]);
Resources = CellLayer.Resize(
oldMapResources,
newSize,
oldMapResources[MPos.Zero]
);
Height = CellLayer.Resize(oldMapHeight, newSize, oldMapHeight[MPos.Zero]);
Ramp = CellLayer.Resize(oldMapRamp, newSize, oldMapHeight[MPos.Zero]);
....
}
ã¢ãã©ã€ã¶ãŒã®èŠåïŒV31272ã€ã®é¡äŒŒããã³ãŒããã©ã°ã¡ã³ããèŠã€ãããŸãããããããããã¯ã¿ã€ããã¹ã§ããããoldMapHeightãã®ä»£ããã«ãoldMapRampã倿°ã䜿çšããå¿ èŠããããŸããMap.cs964
ã¢ãã©ã€ã¶ãŒã¯ã颿°ãžã®åŒæ°ã®åãæž¡ãã«é¢é£ããçãããç¬éãæ€åºããŸãããåŒã³åºããåå¥ã«èŠãŠã¿ãŸãããã
CellLayer.Resize(oldMapTiles, newSize, oldMapTiles[MPos.Zero]);
CellLayer.Resize(oldMapResources, newSize, oldMapResources[MPos.Zero]);
CellLayer.Resize(oldMapHeight, newSize, oldMapHeight[MPos.Zero]);
CellLayer.Resize(oldMapRamp, newSize, oldMapHeight[MPos.Zero]);
å¥åŠãªããšã«ãæåŸã®åŒã³åºãã¯oldMapRampã§ã¯ãªãoldMapHeightãæž¡ããŸãããã¡ããããã®ãããªãã¹ãŠã®ã±ãŒã¹ãå®éã«ãšã©ãŒã§ããããã§ã¯ãããŸãããããã«ãã¹ãŠãæ£ããæžãããŠããå¯èœæ§ã¯ååã«ãããŸããããããããªãã¯ãã®å Žæãçããããã«èŠããããšãèªããªããã°ãªããŸãããç§ã¯ããã§ééããå®éã«è¡ããããšä¿¡ããåŸåããããŸãã
ååããã®ã¡ã¢-AndreyKarpovããããŠãç§ã¯ãã®ã³ãŒãã«å¥åŠãªããšã¯äœãèŠãŠããŸãããããã¯å€å žçãªæåŸã®è¡ã®ãšã©ãŒã§ãïŒ
ããã§ãããã«ãšã©ãŒããªãå Žåã¯ã説æã远å ãã䟡å€ããããŸããçµå±ã®ãšãããç¬éãééãã®ããã«èŠããå Žåã誰ããééããªããããä¿®æ£ããããšæãã§ãããã
çå®ãçå®ããããŠçå®ä»¥å€ã®äœç©ã§ããªã
ãããžã§ã¯ãã«ã¯éåžžã«ç¹æ®ãªã¡ãœãããå«ãŸããŠããããã®æ»ãå€ã¯boolã¿ã€ãã§ãããããã®ç¹åŸŽã¯ãã©ã®ãããªæ¡ä»¶äžã§ãçã«æ»ããšããäºå®ã«ãããŸããäŸãã°ïŒ
static bool State(
S server,
Connection conn,
Session.Client client,
string s
)
{
var state = Session.ClientState.Invalid;
if (!Enum<Session.ClientState>.TryParse(s, false, out state))
{
server.SendOrderTo(conn, "Message", "Malformed state command");
return true;
}
client.State = state;
Log.Write(
"server",
"Player @{0} is {1}",
conn.Socket.RemoteEndPoint,
client.State
);
server.SyncLobbyClients();
CheckAutoStart(server);
return true;
}
ã¢ãã©ã€ã¶ãŒã®èŠåïŒV3009ãã®ã¡ãœãããåžžã«åãå€ã®ãtrueããè¿ãã®ã¯å¥åŠãªããšã§ããLobbyCommands.cs 123
ãã®ã³ãŒãã¯å€§äžå€«ã§ããïŒééãã¯ãããŸããïŒãšãŠãå¥åŠã«èŠããŸããéçºè ãvoidã䜿çšããªãã£ãã®ã¯ãªãã§ããïŒ
ã¢ãã©ã€ã¶ãŒããã®ãããªå Žæãå¥åŠã ãšèŠãªãããšã¯é©ãã¹ãããšã§ã¯ãããŸããããããã§ãããã°ã©ããŒãå®éã«ãã®ããã«æžãçç±ããã£ãããšãèªããªããã°ãªããŸãããã©ãïŒ
ãã®ã¡ãœãããã©ãã§åŒã³åºãããåžžã«çã®æ»ãå€ã䜿çšãããŠãããã確èªããããšã«ããŸãããåãã¯ã©ã¹å ã«ãããžã®åç §ã1ã€ãããªãããšã倿ããŸãã-commandHandlersèŸæžã«ã¯ã¿ã€ãããããŸã
IDictionary<string, Func<S, Connection, Session.Client, string, bool>>
åæåäžã«ãå€ã远å ãããŸã
{"state", State},
{"startgame", StartGame},
{"slot", Slot},
{"allow_spectators", AllowSpectators}
ç
éçåä»ãã«ãã£ãŠåé¡ãçºçãããšãããŸããªïŒä¿¡ãããïŒã±ãŒã¹ã衚瀺ãããŸããçµå±ã®ãšãããå€ãç°ãªã眲åãæã€é¢æ°ã«ãªãèŸæžãäœæããããšã¯...å°ãªããšãåé¡ããããŸããcommandHandlersã¯ãInterpretCommandã¡ãœããã§ã®ã¿äœ¿çšãããŸãã
public bool InterpretCommand(
S server, Connection conn, Session.Client client, string cmd
)
{
if (
server == null ||
conn == null ||
client == null ||
!ValidateCommand(server, conn, client, cmd)
) return false;
var cmdName = cmd.Split(' ').First();
var cmdValue = cmd.Split(' ').Skip(1).JoinWith(" ");
Func<S, Connection, Session.Client, string, bool> a;
if (!commandHandlers.TryGetValue(cmdName, out a))
return false;
return a(server, conn, client, cmdValue);
}
ã©ããããéçºè ã®ç®æšã¯ãå®è¡ãããç¹å®ã®æäœã®æååãäžèŽãããæ®éçãªèœåã§ããã圌ãéžãã æ¹æ³ã¯ããã ãã§ã¯ãªããšæããŸããããã®ãããªç¶æ³ã§ãã£ãšäŸ¿å©ã§æ£ãããã®ãæäŸããã®ã¯ããã»ã©ç°¡åã§ã¯ãããŸãããç¹ã«ãããçš®ã®ãã€ãããã¯ãŸãã¯é¡äŒŒã®ãã®ã䜿çšããªãå Žåããã®ããŒãã«ã€ããŠäœãã¢ã€ãã¢ãããã°ãã³ã¡ã³ããæ®ããŠãã ããããã®åé¡ã解決ããããã®ããŸããŸãªãªãã·ã§ã³ãæ€èšããããšã¯ç§ã«ãšã£ãŠè峿·±ãããšã§ãããã®ã¯ã©ã¹ã®åžžã«trueã®ã¡ãœããã«
é¢é£ä»ããããŠããèŠåã¯ãããããfalseã§ããããšãããããŸããããã§ã...ããªããæããããã®ã¯ãã®ãæãå¯èœæ§ãé«ããããšã§ãããã®äžã«ã¯ç¢ºãã«ééãããããããããªãã®ã§ãããªãã¯ãã®ãããªããšã«æ³šæããå¿ èŠããããŸãã
ãã®ãããªãã¹ãŠã®éœæ§ã¯æ³šææ·±ããã§ãã¯ããå¿ èŠã«å¿ããŠåœãšããŠããŒã¯ããå¿ èŠããããŸããããã¯éåžžã«ç°¡åã«è¡ãããŸããã¢ãã©ã€ã¶ãŒã«ãã£ãŠç€ºãããå Žæã«ç¹å¥ãªã³ã¡ã³ããæ®ãå¿ èŠããããŸãã
static bool State(....) //-V3009
å¥ã®æ¹æ³ããããŸããfalseãšããŠããŒã¯ããå¿ èŠãããããžãã£ããéžæããã³ã³ããã¹ãã¡ãã¥ãŒã§[éžæããã¡ãã»ãŒãžãFalseã¢ã©ãŒã ãšããŠããŒã¯ãã]ãã¯ãªãã¯ããŸãã

ãã®ãããã¯ã®è©³çްã«ã€ããŠã¯ãããã¥ã¡ã³ããã芧ãã ããã
nullã®è¿œå ãã§ãã¯ïŒ
static bool SyncLobby(....)
{
if (!client.IsAdmin)
{
server.SendOrderTo(conn, "Message", "Only the host can set lobby info");
return true;
}
var lobbyInfo = Session.Deserialize(s);
if (lobbyInfo == null) // <=
{
server.SendOrderTo(conn, "Message", "Invalid Lobby Info Sent");
return true;
}
server.LobbyInfo = lobbyInfo;
server.SyncLobbyInfo();
return true;
}
ã¢ãã©ã€ã¶ãŒã®èŠåïŒV3022åŒ 'lobbyInfo == null'ã¯åžžã«falseã§ãã LobbyCommands.cs851
åžžã«trueãè¿ãå¥ã®ã¡ãœããããã ããä»åã¯å¥ã®ã¿ã€ãã®ããªã¬ãŒã調ã¹ãŠããŸãããããåãªãåé·ãªã³ãŒãã§ãããšããäºå®ããã¯ã»ã©é ãã®ã§ããã®ãããªããšãååã«æ³šææ·±ãç ç©¶ããå¿ èŠããããŸãããããããŸãæåã«ãDeserialize
ã¡ãœãããnullãè¿ãããšã¯ãããŸãããã³ãŒãã確èªããããšã§ããããç°¡åã«ç¢ºèªã§ããŸãã
public static Session Deserialize(string data)
{
try
{
var session = new Session();
....
return session;
}
catch (YamlException)
{
throw new YamlException(....);
}
catch (InvalidOperationException)
{
throw new YamlException(....);
}
}
èªã¿ãããããããã«ãã¡ãœããã®ãœãŒã¹ã³ãŒããçãããŸããããªã³ã¯ããã©ããšå®å šã«èŠãããšãã§ããŸããããŠããŸãã¯ç§ã®èšèãåããã°ãããã®ã»ãã·ã§ã³å€æ°ã¯ãããªãç¶æ³ã§ãnullã«ãªããŸããã
äžçªäžã«äœãèŠããŸããïŒDeserializeã¯nullãè¿ããŸãããäœãåé¡ãçºçããå ŽåãäŸå€ãã¹ããŒãããŸããåŒã³åºãåŸã«nullã®ãã§ãã¯ãäœæããéçºè ã¯ãèãæ¹ãç°ãªãããã§ãããã»ãšãã©ã®å ŽåãäŸå€çãªç¶æ³ã§ã¯ãSyncLobbyã¡ãœããã¯çŸåšå®è¡ãããŠããã³ãŒããå®è¡ããå¿ èŠããããŸã...ã¯ããlobbyInfoãnullã«ãªãããšã¯ãªããããå®è¡ãããããšã¯ãããŸããã
if (lobbyInfo == null)
{
server.SendOrderTo(conn, "Message", "Invalid Lobby Info Sent");
return true;
}
ç§ã®ä»£ããã«ããã®ãäœåãã®ãã§ãã¯ããããªãã¯ãŸã 䜿çšããå¿ èŠããããšä¿¡ããŠããã®try -ãã£ããããŸãã¯ãå察åŽããè¡ã£ãŠãTryDeserializeãèšè¿°ããŸããããã¯ãäŸå€ã®å Žåã«nullãè¿ããŸãã
èããããNullReferenceException
public ConnectionSwitchModLogic(....)
{
....
var logo = panel.GetOrNull<RGBASpriteWidget>("MOD_ICON");
if (logo != null)
{
logo.GetSprite = () =>
{
....
};
}
if (logo != null && mod.Icon == null) // <=
{
// Hide the logo and center just the text
if (title != null)
title.Bounds.X = logo.Bounds.Left;
if (version != null)
version.Bounds.X = logo.Bounds.X;
width -= logo.Bounds.Width;
}
else
{
// Add an equal logo margin on the right of the text
width += logo.Bounds.Width; // <=
}
....
}
ã¢ãã©ã€ã¶ãŒã®èŠåïŒV3125'logo 'ãªããžã§ã¯ãã¯ãnullã«å¯ŸããŠæ€èšŒãããåŸã«äœ¿çšãããŸããããã§ãã¯è¡ïŒ236ã222ãConnectionLogic.cs 236
ããã«100ïŒ ã®ãšã©ãŒããããšäœããæããŠãããŸããGetOrNullã¡ãœããã¯ãããããå®éã«nullåç §ãè¿ãå¯èœæ§ããããããç§ãã¡ã®åã«ãäœåãªããã§ãã¯ã¯çµ¶å¯Ÿã«ãããŸãããããŽãnullã®å Žåã¯ã©ããªããŸããïŒBoundsããããã£ãåŒã³åºããšäŸå€ãã¹ããŒãããŸãããããã¯æããã«éçºè ã®èšç»ã«ã¯å«ãŸããŠããŸããã§ããã
ããããããã©ã°ã¡ã³ãã¯æ¬¡ã®ããã«æžãçŽãå¿ èŠããããŸãã
if (logo != null)
{
if (mod.Icon == null)
{
// Hide the logo and center just the text
if (title != null)
title.Bounds.X = logo.Bounds.Left;
if (version != null)
version.Bounds.X = logo.Bounds.X;
width -= logo.Bounds.Width;
}
else
{
// Add an equal logo margin on the right of the text
width += logo.Bounds.Width;
}
}
ãã®ãªãã·ã§ã³ã¯çè§£ããã®ã«ååç°¡åã§ããã远å ã®ãã¹ãã¯ããŸãã¯ãŒã«ã«èŠããŸããããã容éã®å€§ãããœãªã¥ãŒã·ã§ã³ãšããŠãnullæ¡ä»¶æŒç®åã䜿çšã§ããŸãã
// Add an equal logo margin on the right of the text
width += logo?.Bounds.Width ?? 0; // <=
ç§ã¯ããããã£ãã¯ã¹ã®æ¹ã奜ãã ãšããããšã«æ³šæããŠãã ããããããèªãã®ã¯æ¥œããã§ãããçåã¯çããŸãããããããäžéšã®éçºè ã¯ç°¡æœããé«ãè©äŸ¡ããŠããã®ã§ã2çªç®ã®ãªãã·ã§ã³ãäžããããšã«ããŸãã:)ã
å€åããã¯çµå±OrDefaultã§ããïŒ
public MapEditorLogic(....)
{
var editorViewport = widget.Get<EditorViewportControllerWidget>("MAP_EDITOR");
var gridButton = widget.GetOrNull<ButtonWidget>("GRID_BUTTON");
var terrainGeometryTrait = world.WorldActor.Trait<TerrainGeometryOverlay>();
if (gridButton != null && terrainGeometryTrait != null) // <=
{
....
}
var copypasteButton = widget.GetOrNull<ButtonWidget>("COPYPASTE_BUTTON");
if (copypasteButton != null)
{
....
}
var copyFilterDropdown = widget.Get<DropDownButtonWidget>(....);
copyFilterDropdown.OnMouseDown = _ =>
{
copyFilterDropdown.RemovePanel();
copyFilterDropdown.AttachPanel(CreateCategoriesPanel());
};
var coordinateLabel = widget.GetOrNull<LabelWidget>("COORDINATE_LABEL");
if (coordinateLabel != null)
{
....
}
....
}
ã¢ãã©ã€ã¶ãŒã®èŠåïŒV3063æ¡ä»¶åŒã®äžéšã¯ãè©äŸ¡ããããšåžžã«trueã«ãªããŸãïŒterrainGeometryTraitïŒ= Nullã MapEditorLogic.cs35
ãã®ã¹ãããããåæããŠã¿ãŸããããWidgetã¯ã©ã¹ã®GetOrNullã¡ãœããã䜿çšããããã³ã«ãnullããã§ãã¯ãããããšã«æ³šæããŠãã ããããã ããGetã䜿çšãããŠããå Žåãæ€èšŒã¯è¡ãããŸãããããã¯è«ççã§ã-Getã¡ãœããã¯nullãè¿ããŸããïŒ
public T Get<T>(string id) where T : Widget
{
var t = GetOrNull<T>(id);
if (t == null)
throw new InvalidOperationException(....);
return t;
}
èŠçŽ ãèŠã€ãããªãå Žåã¯ãäŸå€ãã¹ããŒãããŸããããã¯åŠ¥åœãªåäœã§ããåæã«ãè«ççãªãªãã·ã§ã³ã¯ãGetOrNullã¡ãœããã«ãã£ãŠè¿ãããå€ãnullåç §ãšçãããã©ããã確èªããããšã§ãã
äžèšã®ã³ãŒãã§ã¯ãTraitã¡ãœããã«ãã£ãŠè¿ãããå€ãnullã§ãããã©ããããã§ãã¯ãããŸããå®éãTraitã¡ãœããå ã§ã¯ãGetã¯TraitDictionaryã¯ã©ã¹ããåŒã³åºãããŸãã
public T Trait<T>()
{
return World.TraitDict.Get<T>(this);
}
ãã®Getã®åäœã¯ãåã«èª¬æãããã®ãšã¯ç°ãªãå¯èœæ§ããããŸããïŒããããã¯ã©ã¹ã¯ç°ãªããŸãã確èªãããïŒ
public T Get<T>(Actor actor)
{
CheckDestroyed(actor);
return InnerGet<T>().Get(actor);
}
InnerGet ã¡ãœããã¯ãTraitContainer <T>ã®ã€ã³ã¹ã¿ã³ã¹ãè¿ããŸãããã®ã¯ã©ã¹ã§ã®Getã®å®è£ ã¯ãWidgetã¯ã©ã¹ã®Getãšéåžžã«ãã䌌ãŠããŸãã
public T Get(Actor actor)
{
var result = GetOrDefault(actor);
if (result == null)
throw new InvalidOperationException(....);
return result;
}
äž»ãªé¡äŒŒç¹ã¯ãããã§ãnullãè¿ãããªãããšã§ããäœãåé¡ãçºçããå ŽåãInvalidOperationExceptionãåæ§ã«ã¹ããŒãããŸãããããã£ãŠãTraitã¡ãœããã¯åãããã«åäœããŸãã
ã¯ããããã«è¿œå ã®ãã§ãã¯ãããã ãã§ãäœã®åœ±é¿ããããŸãããå¥åŠã«èŠãããããããŸãããããã®ãããªã³ãŒããèªè ã倧ãã«æ··ä¹±ããããšã¯èšããŸããããã ããããã§ãã§ãã¯ãå¿ èŠãªå Žåã¯ãäºæããäŸå€ãã¹ããŒãããããšããããŸããæ²ããã§ãã
ãã®æç¹ã§ãTraitOrNullãåŒã³åºãæ¹ãé©åãªããã§ãããã ãããã®ãããªæ¹æ³ã¯ãããŸãã:)ãããããGetOrNullã«é¡äŒŒããTraitOrDefaultããããŸããã®å ŽåãGet
ã¡ãœããã«é¢é£ããå¥ã®åæ§ã®ãã€ã³ãããããŸãïŒ
public AssetBrowserLogic(....)
{
....
frameSlider = panel.Get<SliderWidget>("FRAME_SLIDER");
if (frameSlider != null)
{
....
}
....
}
ã¢ãã©ã€ã¶ãŒã®èŠåïŒV3022åŒ 'frameSliderïŒ= Null'ã¯åžžã«trueã§ããAssetBrowserLogic.cs 128äžèš
ã®ã³ãŒããšåæ§ã«ãããã§åé¡ãçºçããŠããŸãããã§ãã¯ã¯æ¬åœã«äžèŠã§ããããGetã®ä»£ããã«GetOrNullãåŒã³åºãå¿ èŠããããŸãã
å²ãåœãŠã倱ã£ã
public SpawnSelectorTooltipLogic(....)
{
....
var textWidth = ownerFont.Measure(labelText).X;
if (textWidth != cachedWidth)
{
label.Bounds.Width = textWidth;
widget.Bounds.Width = 2 * label.Bounds.X + textWidth; // <=
}
widget.Bounds.Width = Math.Max( // <=
teamWidth + 2 * labelMargin,
label.Bounds.Right + labelMargin
);
team.Bounds.Width = widget.Bounds.Width;
....
}
ã¢ãã©ã€ã¶ãŒã®èŠåïŒV3008'widget.Bounds.Width '倿°ã«ã¯ã2åé£ç¶ããŠå€ãå²ãåœãŠãããŸããããããããã¯ééãã§ãããã§ãã¯ã©ã€ã³ïŒ78ã75 SpawnSelectorTooltipLogic.cs 78ã¯ã
ããã°ãšããããšãããïŒtextWidth = CachedWidthæ¡ä»¶ãããçã®ãããã€ãã®ç¹å®ã®å€ãæžã蟌ãŸãããŸã§widget.Bounds.Widthããã ãããã®æ¡ä»¶ãçã§ãããã©ããã«é¢ä¿ãªãã以äžã®å²ãåœãŠã¯æååã奪ããŸã
widget.Bounds.Width = 2 * label.Bounds.X + textWidth;
ããããæå³ã§ã圌ãã¯åã«ä»ã®ãã®ãããã«çœ®ãã®ãå¿ããå¯èœæ§ããããŸãïŒ
if (textWidth != cachedWidth)
{
label.Bounds.Width = textWidth;
widget.Bounds.Width = 2 * label.Bounds.X + textWidth;
}
else
{
widget.Bounds.Width = Math.Max(
teamWidth + 2 * labelMargin,
label.Bounds.Right + labelMargin
);
}
ããã©ã«ãå€ã®ç¢ºèª
public void DisguiseAs(Actor target)
{
....
var tooltip = target.TraitsImplementing<ITooltip>().FirstOrDefault();
AsPlayer = tooltip.Owner;
AsActor = target.Info;
AsTooltipInfo = tooltip.TooltipInfo;
....
}
ã¢ãã©ã€ã¶ãŒã®èŠåïŒV3146ãtooltipãã®nulléåç §ã®å¯èœæ§ã 'FirstOrDefault'ã¯ãããã©ã«ãã®nullå€ãè¿ãããšãã§ããŸãã Disguise.cs 192 Firstã®ä»£ããã«FirstOrDefaultã
äžè¬çã«äœ¿çšãããã®ã¯ãã€ã§ããïŒéžæã空ã®å ŽåãFirstã¯InvalidOperationExceptionãã¹ããŒããŸããFirstOrDefaultã¯äŸå€ãã¹ããŒããŸããããåç §ã¿ã€ãã«å¯ŸããŠnullãè¿ããŸãã ãããžã§ã¯ãã§ã¯ãITooltipã€ã³ã¿ãŒãã§ã€ã¹ã¯ããŸããŸãªã¯ã©ã¹ã«ãã£ãŠå®è£ ãããŸãããããã£ãŠãtarget.TraitsImplementing <ITooltip>ïŒïŒã空ã®éžæãè¿ãå Žåãnullãtooltipã«æžã蟌ãŸããŸãã
..ããã®ãªããžã§ã¯ãã®ããããã£ã«ããã«ã¢ã¯ã»ã¹ãããšãNullReferenceExceptionãçºçããŸãã
éçºè ãéžæç¯å²ã空ã«ãªããªãããšã確å®ãªå Žåã¯ãFirstã䜿çšããæ¹ãé©åã§ããããããããªãå Žåã¯ãFirstOrDefaultã«ãã£ãŠè¿ãããå€ã確èªããå¿ èŠããããŸãããããããã«ãªãã®ã¯ããªãå¥åŠã§ããçµå±ã®ãšãããåè¿°ã®GetOrNullã¡ãœããã«ãã£ãŠè¿ãããå€ã¯åžžã«ãã§ãã¯ãããŠããŸããããªã圌ãã¯ããã§ãããããªãã£ãã®ã§ããïŒ
誰ãç¥ã£ãŠãã...ããããŸãã«ïŒç¢ºãã«ãéçºè ã¯ãããã®è³ªåã«çããããšãã§ããŸããæåŸã«ã圌ã¯ãã®ã³ãŒããç·šéããå¿ èŠããããŸãã
çµè«
OpenRAã¯ã©ããããããããã§ãã¯ããã®ã楜ãããŠé¢çœããããžã§ã¯ãã§ããããšãããããŸãããéçºè ã¯çŽ æŽãããä»äºãããåæã«ãœãŒã¹ãç°¡åã«ç¿åŸã§ããã¯ãã§ããããšãå¿ããŸããã§ããããã¡ãããããã«ã¯ããŸããŸãª...ç©è°ãéžããã€ã³ãããããŸããããããããªãå Žåã
åæã«ããã¹ãŠã®åªåãããŠããéçºè ïŒalasïŒã¯äººéã®ãŸãŸã§ããèããããããžãã£ãã®ããã€ãã¯ãã¢ãã©ã€ã¶ãŒã䜿çšããã«æ°ä»ãããšã¯éåžžã«å°é£ã§ããæžã蟌ãã çŽåŸã§ããšã©ãŒãèŠã€ããã®ãé£ããå ŽåããããŸããä¹ ãã¶ãã«èŠã€ãããšã¯ã©ãããããšãã
æããã«ããã®çµââæãããééããæ€åºããæ¹ãã¯ããã«åªããŠããŸãããã®ããã«ãèšå€§ãªæ°ã®æ°ãããœãŒã¹ãæåã§åãã§ãã¯ããã®ã«äœæéãè²»ããããšãã§ããŸããããŠãå€ããã®ã¯åæã«èŠããŸã-çªç¶ã以åã«ééãã«æ°ã¥ããªãã£ãã®ã§ããïŒã¯ããã¬ãã¥ãŒã¯æ¬åœã«äŸ¿å©ã§ãããå€ãã®ã³ãŒãã調ã¹ãå¿ èŠãããå Žåã¯ãæéã®çµéãšãšãã«ããã€ãã®ããšã«æ°ä»ããªããªããŸãããããŠãããã«å€ãã®æéãšåŽåãè²»ããããŠããŸãã

éçåæã¯ãã³ãŒãã¬ãã¥ãŒãªã©ããœãŒã¹ã³ãŒãã®å質ããã§ãã¯ããä»ã®æ¹æ³ãžã®äŸ¿å©ãªè¿œå ã§ãã PVS-Studioã¯ãéçºè ã§ã¯ãªããåçŽãªãïŒå Žåã«ãã£ãŠã¯ããã ãã§ã¯ãªãïŒãšã©ãŒãæ€åºãã人ã ãããæ·±å»ãªåé¡ã«éäžã§ããããã«ããŸãã
ã¯ããã¢ãã©ã€ã¶ãŒã¯èª€æ€ç¥ãçæããããšãããããã¹ãŠã®ãšã©ãŒããŸã£ããèŠã€ããããšãã§ããŸãããããããããã䜿çšãããšãå€ãã®æéãšç¥çµãç¯çŽã§ããŸããã¯ãã圌ã¯å®ç§ã§ã¯ãªããæã«ã¯èªåã§ééããç¯ããŸãããã ããäžè¬çã«ãPVS-Studioã䜿çšãããšãéçºããã»ã¹ãã¯ããã«ç°¡åã«ãªããå¿«é©ã«ãªããããã«ïŒäºæ³å€ã«ïŒïŒå®äŸ¡ã«ãªããŸãã
å®éãç§ã®èšèãä¿¡ããå¿ èŠã¯ãããŸãããäžèšã®çå®ãèªåã§ç¢ºèªããæ¹ãã¯ããã«è¯ãã§ãããããªã³ã¯ããã©ã£ãŠã¢ãã©ã€ã¶ãŒãããŠã³ããŒããããã©ã€ã¢ã«ããŒãå ¥æããŠãã ãããã©ãã ãç°¡åã§ããïŒ
ãŸããããã ãã§ããæž èŽããããšãããããŸããïŒã³ãŒããšåãã¯ãªãŒã³ãšã©ãŒãã°ãã¯ãªãŒã³ã¢ããããŠãã ããã

ãã®èšäºãè±èªã話ãèŽè¡ãšå ±æãããå Žåã¯ã翻蚳ãªã³ã¯ã䜿çšããŠãã ããïŒNikitaLipilinããŠãã³ãŒã³ã¯RTSã«äŸµå ¥ããŸãïŒOpenRAãœãŒã¹ã³ãŒãã®åæã