{"id":387467,"date":"2024-06-29T07:19:51","date_gmt":"2024-06-29T07:19:51","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=387467"},"modified":"-0001-11-30T00:00:00","modified_gmt":"2024-06-29T07:19:51","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=387467","title":{"rendered":"<span>Amnesia: The Dark Descent or How to Forget to Fix Copy Paste<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-1\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/post_images\/bc8\/fa6\/790\/bc8fa67904591e4e15c5b7d4e6c26e08.png\" alt=\"image1.png\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/bc8\/fa6\/790\/bc8fa67904591e4e15c5b7d4e6c26e08.png\"\/><\/div>\n<p>  Just before the release of the &#171;Amnesia: Rebirth&#187; game, the vendor &#171;Fractional Games&#187; opened the source code of the legendary &#171;Amnesia: The Dark Descent&#187; and its sequel &#171;Amnesia: A Machine For Pigs&#187;. Why not use the static analysis tool to see what dreadful mistakes are hidden in the inside of these cult horror games?<br \/>  <a name=\"habracut\"><\/a><br \/>  After seeing the news on Reddit that the source code of the games &#171;<a href=\"https:\/\/github.com\/FrictionalGames\/AmnesiaTheDarkDescent\">Amnesia: The Dark Descent<\/a>&#187; and &#171;<a href=\"https:\/\/github.com\/FrictionalGames\/AmnesiaAMachineForPigs\">Amnesia: A Machine for Pigs<\/a>&#187; was released, I couldn&#8217;t pass by and not check this code using PVS-Studio, and at the same time write an article about it. Especially since the new part of this game-series \u2014 &#171;<a href=\"https:\/\/store.steampowered.com\/app\/999220\/Amnesia_Rebirth\/\">Amnesia: Rebirth<\/a>&#187; is released on the 20th of October (and at the moment of posting this article the game is already released).<\/p>\n<p>  &#171;Amnesia: The Dark Descent&#187; was released in 2010 and became a cult game in the survival horror genre. Frankly speaking, I have never been able to play through it, even a bit. The reason is that in horror games I play by one algorithm: install, run for five minutes, exit by &#171;alt+f4&#187; at the first creepy moment and delete the game. But I liked watching this game run through videos on YouTube.<\/p>\n<p>  In case someone is not familiar with PVS-Studio yet, this is a static analyzer that looks for errors and suspicious places in source code of programs.<\/p>\n<p>  <a href=\"https:\/\/viva64.com\/en\/pvs-studio-download\/?utm_source=habr&amp;utm_medium=banner&amp;utm_campaign=0769_Amnesia_The_Dark_Descent\"><\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/post_images\/42b\/757\/14b\/42b75714b45fa154c5497bdb32b2c568.png\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/42b\/757\/14b\/42b75714b45fa154c5497bdb32b2c568.png\"\/><\/div>\n<p><\/a><br \/>  I especially like delving into source code of games. So, if you are interested in what errors are made in games, you can read my previous articles. Also check out the <a href=\"https:\/\/www.viva64.com\/en\/tags\/?q=gamedev\">articles by my colleagues<\/a> about checking source code of games.<\/p>\n<p>  After checking, it turned out that a large amount of code overlaps between &#171;The Dark Descent&#187; and &#171;A Machine For Pigs&#187;, and the reports for these two projects were very similar. So almost all the errors that I will cite further take place in both projects.<\/p>\n<p>  The better half of errors found by the analyzer in these projects was copy-paste errors. This explains the title of the article. The main reason for these errors is the &#171;<a href=\"https:\/\/www.viva64.com\/en\/b\/0708\/\">last line effect<\/a>&#171;.<\/p>\n<p>  Let&#8217;s get right to it.<\/p>\n<h2>Copy-paste errors<\/h2>\n<p>  There were a lot of suspicious places that looked like inattentive copying. Some cases may be due to the internal logic of the game itself. Once they confused both the analyzer and me, at least a comment could be of use. After all, other developers may be as clueless as I am.<\/p>\n<p>  <b>Fragment 1.<\/b><\/p>\n<p>  Let&#8217;s start with an example where the entire function consists of comparing method results and fields values of two objects <i>aObjectDataA<\/i> and <i>aObjectDataB<\/i>. I will cite the entire function for clarity. Try to see for yourself where the error was made in the function:<\/p>\n<pre><code class=\"cpp\">static bool SortStaticSubMeshesForBodies(const ....&amp; aObjectDataA,                                          const ....&amp; aObjectDataB) {   \/\/Is shadow caster check   if(   aObjectDataA.mpObject->GetRenderFlagBit(....)      != aObjectDataB.mpObject->GetRenderFlagBit(....))   {     return  aObjectDataA.mpObject->GetRenderFlagBit(....)           &lt; aObjectDataB.mpObject->GetRenderFlagBit(....);   }   \/\/Material check   if( aObjectDataA.mpPhysicsMaterial != aObjectDataB.mpPhysicsMaterial)   {     return aObjectDataA.mpPhysicsMaterial &lt; aObjectDataB.mpPhysicsMaterial;   }    \/\/Char collider or not   if( aObjectDataA.mbCharCollider  != aObjectDataB.mbCharCollider)   {     return aObjectDataA.mbCharCollider &lt; aObjectDataB.mbCharCollider;   }    return  aObjectDataA.mpObject->GetVertexBuffer()         &lt; aObjectDataA.mpObject->GetVertexBuffer(); }<\/code><\/pre>\n<p>  Here&#8217;s a pic for you to avoid accidentally spying on the answer:<\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/post_images\/df0\/586\/aee\/df0586aee89d01f921ec08a83907f404.png\" alt=\"image2.png\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/df0\/586\/aee\/df0586aee89d01f921ec08a83907f404.png\"\/><\/div>\n<p>  Did you find a bug? So, in the last <i>return<\/i>, there is a comparison using <i>aObjectDataA<\/i> on both sides. Note that all the expressions in the original code were written in a line. Here I broke lines so that everything fit exactly in the width of the line. Just imagine how hard it will be to look for such a flaw at the end of the working day. Whereas the analyzer will find it immediately after building the project and running incremental analysis.<\/p>\n<p>  <a href=\"https:\/\/www.viva64.com\/en\/w\/v501\/\">V501<\/a> There are identical sub-expressions &#8216;aObjectDataA.mpObject->GetVertexBuffer()&#8217; to the left and to the right of the &#8216;&lt;&#8216; operator. WorldLoaderHplMap.cpp 1123<\/p>\n<p>  As a result, such an error will be found almost at the time of writing the code, instead of hiding in the depths of the code from several stages of Q&amp;A, making your search much more difficult.<\/p>\n<blockquote><p>Note by my colleague Andrey Karpov. Yes, this is a classic &#171;last line effect&#187; error. Moreover, this is also a classic pattern of the error related to comparing two objects. See the article &#171;<a href=\"https:\/\/www.viva64.com\/en\/b\/0509\/\">The Evil within the Comparison Functions<\/a>&#171;.<\/p><\/blockquote>\n<p><b>Fragment 2.<\/b><\/p>\n<p>  Let&#8217;s take a quick look at the code that triggered the warning:<\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/post_images\/595\/1c1\/a71\/5951c1a71998126ccdfe8954afac3512.png\" alt=\"image4.png\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/595\/1c1\/a71\/5951c1a71998126ccdfe8954afac3512.png\"\/><\/div>\n<p>  Here is a screenshot of the code for clarity.<\/p>\n<p>  This is how the warning looks like:<\/p>\n<p>  <a href=\"https:\/\/www.viva64.com\/en\/w\/v501\/\">V501<\/a> There are identical sub-expressions &#8216;lType == eLuxJournalState_OpenNote&#8217; to the left and to the right of the &#8216;||&#8217; operator. LuxJournal.cpp 2262<\/p>\n<p>  The analyzer found that there is an error in the check of the <i>lType<\/i> variable value. The equality with the same element of the <i>eLuxJournalState_OpenNote<\/i> enumerator is checked twice.<\/p>\n<p>  First, I wish this condition would be written in a table-like format for better readability. See the chapter 13 from the mini-book &#171;<a href=\"https:\/\/www.viva64.com\/en\/b\/0391\/\">The Ultimate Question of Programming, Refactoring, and Everything<\/a>&#187; for more details. <\/p>\n<pre><code class=\"cpp\">if(!(   lType == eLuxJournalState_OpenNote      || lType == eLuxJournalState_OpenDiary      || lType == eLuxJournalState_OpenNote      || lType == eLuxJournalState_OpenNarratedDiary))   return false;<\/code><\/pre>\n<p>  In this form, it becomes much easier to notice the error even without the analyzer.<\/p>\n<p>  Anyway, here comes a question \u2014 does such an erroneous check lead to logic distortion of the program? After all, one may need to check some other <i>lType<\/i> value, but the check was missed due to a copy-paste error. So, let&#8217;s take a look at the enumeration itself:<\/p>\n<pre><code class=\"cpp\">enum eLuxJournalState {   eLuxJournalState_Main,   eLuxJournalState_Notes,   eLuxJournalState_Diaries,   eLuxJournalState_QuestLog,   eLuxJournalState_OpenNote,   eLuxJournalState_OpenDiary,   eLuxJournalState_OpenNarratedDiary,    eLuxJournalState_LastEnum, };<\/code><\/pre>\n<p>  There are only three values with the word &#171;Open&#187; in their name. All three are present in the check. Most likely, there is no logic distortion here, but we can hardly know for sure. So, the analyzer either found a logical error that the game developer could fix, or found an &#171;ugly&#187; written snippet that would be worth rewriting for better elegancy.<\/p>\n<p>  <b>Fragment 3.<\/b><\/p>\n<p>  The following case is generally the most obvious example of a copy-paste error.<\/p>\n<p>  <a href=\"https:\/\/www.viva64.com\/en\/w\/v778\/\">V778<\/a> Two similar code fragments were found. Perhaps, this is a typo and &#8216;mvSearcherIDs&#8217; variable should be used instead of &#8216;mvAttackerIDs&#8217;. LuxSavedGameTypes.cpp 615<\/p>\n<pre><code class=\"cpp\">void cLuxMusicHandler_SaveData::ToMusicHandler(....) {   ....   \/\/ Enemies   \/\/Attackers   for(size_t i=0; i&lt;mvAttackerIDs.Size(); ++i)   {     iLuxEntity *pEntity = apMap                          ->GetEntityByID(mvAttackerIDs[i]);     if(....)     {       ....     }     else     {       Warning(\"....\", mvAttackerIDs[i]);     }   }    \/\/Searchers   for(size_t i=0; i&lt;mvSearcherIDs.Size(); ++i)   {     iLuxEntity *pEntity = apMap->GetEntityByID(mvSearcherIDs[i]);     if(....)     {       ....     }     else     {       Warning(\"....\", mvAttackerIDs[i]);     }   } }<\/code><\/pre>\n<p>  In the first loop, the <i>pEntity<\/i> pointer (obtained via <i>mvAttackerIDs<\/i>) is handled. If the condition is not met, a debug message is issued for the same <i>mvAttackerIDs<\/i>. However, in the next loop, which is formed the same as the previous code section, <i>pEntity<\/i> is obtained using <i>mvSearcherIDs<\/i>. While the warning is still issued with the mention of <i>mvAttackerIDs<\/i>.<\/p>\n<p>  Most likely, the code block with the note &#171;Searchers&#187; was copied from the &#171;Attackers&#187; block, <i>mvAttackerIDs<\/i> was replaced with <i>mvSearcherIDs<\/i>, but the <i>else<\/i> block was not changed. As a result, the error message uses an element of the wrong array.<\/p>\n<p>  This error does not affect the logic of the game, but this way you can play a dirty trick on a person who will have to debug this place, and waste time working with the wrong <i>mvSearcherIDs<\/i> element.<\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/post_images\/504\/383\/a71\/504383a71481361dda2e76c11bc8b246.png\" alt=\"image5.png\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/504\/383\/a71\/504383a71481361dda2e76c11bc8b246.png\"\/><\/div>\n<p>  <b>Fragment 4.<\/b><\/p>\n<p>  The analyzer indicated the next suspicious fragment with as many as three warnings:<\/p>\n<ul>\n<li><a href=\"https:\/\/www.viva64.com\/en\/w\/v547\/\">V547<\/a> Expression &#8216;pEntity == 0&#8217; is always false. LuxScriptHandler.cpp 2444<\/li>\n<li><a href=\"https:\/\/www.viva64.com\/en\/w\/v649\/\">V649<\/a> There are two &#8216;if&#8217; statements with identical conditional expressions. The first &#8216;if&#8217; statement contains function return. This means that the second &#8216;if&#8217; statement is senseless. Check lines: 2433, 2444. LuxScriptHandler.cpp 2444<\/li>\n<li><a href=\"https:\/\/www.viva64.com\/en\/w\/v1051\/\">V1051<\/a> Consider checking for misprints. It&#8217;s possible that the &#8216;pTargetEntity&#8217; should be checked here. LuxScriptHandler.cpp 2444<\/li>\n<\/ul>\n<p>  Take a look at the code:<\/p>\n<pre><code class=\"cpp\">void __stdcall cLuxScriptHandler::PlaceEntityAtEntity(....) {   cLuxMap *pMap = gpBase->mpMapHandler->GetCurrentMap();    iLuxEntity *pEntity = GetEntity(....);   if(pEntity == NULL) return;   if(pEntity->GetBodyNum() == 0)   {     ....   }    iPhysicsBody *pBody = GetBodyInEntity(....);   if(pBody == NULL) return;    iLuxEntity *pTargetEntity = GetEntity(....);   if(pEntity == NULL) return;  \/\/ &lt;=    iPhysicsBody *pTargetBody = GetBodyInEntity(....);   if(pTargetBody == NULL) return;    .... }<\/code><\/pre>\n<p>  The <a href=\"https:\/\/www.viva64.com\/en\/w\/v547\/\">V547<\/a> warning was issued for the second <i>pEntity == NULL<\/i> check. For the analyzer, this check will always be <i>false<\/i>, since if this condition were <i>true<\/i>, the function would exit earlier due to a previous similar check.<\/p>\n<p>  The next warning (<a href=\"https:\/\/www.viva64.com\/en\/w\/v649\/\">V649<\/a>) was issued just for the fact that we have two identical checks. Usually this case may not be a mistake. Who knows, may be one part of the code implements the same logic, and another part of the code must do something else based on the same check. But in this case, the body of the first check consists of <i>return<\/i>, so it won&#8217;t even get to the second check if the condition is <i>true<\/i>. By tracking this logic, the analyzer reduces the number of false messages for suspicious code and outputs them only for very strange logic.<\/p>\n<p>  The error indicated by the last warning is very similar in nature to the previous example. Most likely, all checks were duplicated from the first <i>if(pEntity == NULL)<\/i> check, and then the object being checked was replaced with the required one. In the case of the <i>pBody<\/i> and <i>pTargetBody<\/i> objects, the replacement was made, but the <i>pTargetEntity<\/i> object was forgotten. As a result, this object is not checked.<\/p>\n<p>  If you dig a bit deeper into the code of the example we are considering, it turns out that such an error will not affect the program performance. The <i>pTargetBody<\/i> pointer gets its value from the <i>GetBodyInEntity<\/i> function:<\/p>\n<pre><code class=\"cpp\">iPhysicsBody *pTargetBody = GetBodyInEntity(pTargetEntity,                                             asTargetBodyName);<\/code><\/pre>\n<p>  The first passed argument here is an unchecked pointer that is not used anywhere else. Fortunately, inside this function there is a check of the first argument for <i>NULL<\/i>:<\/p>\n<pre><code class=\"cpp\">iPhysicsBody* ....::GetBodyInEntity(iLuxEntity* apEntity, ....) {   if(apEntity == NULL){     return NULL;   }   .... }<\/code><\/pre>\n<p>  As a result, this code works correctly in the end, although it contains an error.<\/p>\n<p>  <b>Fragment 5.<\/b><\/p>\n<p>  Another suspicious place with copy-paste!<\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/post_images\/dbe\/bc4\/f05\/dbebc4f0536539d7aee9fe32bd0e04e1.png\" alt=\"image6.png\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/dbe\/bc4\/f05\/dbebc4f0536539d7aee9fe32bd0e04e1.png\"\/><\/div>\n<p>  In this method, the fields of the <i>cLuxPlayer<\/i> class object are zeroed.<\/p>\n<pre><code class=\"cpp\">void cLuxPlayer::Reset() {   ....   mfRoll=0;   mfRollGoal=0;   mfRollSpeedMul=0; \/\/&lt;-   mfRollMaxSpeed=0; \/\/&lt;-    mfLeanRoll=0;   mfLeanRollGoal=0;   mfLeanRollSpeedMul=0;   mfLeanRollMaxSpeed=0;    mvCamAnimPos =0;   mvCamAnimPosGoal=0;   mfRollSpeedMul=0; \/\/&lt;-   mfRollMaxSpeed=0; \/\/&lt;-   .... }<\/code><\/pre>\n<p>  But for some reason, the two variables <i>mfRollSpeedMul<\/i> and <i>mfRollMaxSpeed<\/i> are zeroed twice:<\/p>\n<ul>\n<li><a href=\"https:\/\/www.viva64.com\/en\/w\/v519\/\">V519<\/a> The &#8216;mfRollSpeedMul&#8217; variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 298, 308. LuxPlayer.cpp 308<\/li>\n<li><a href=\"https:\/\/www.viva64.com\/en\/w\/v519\/\">V519<\/a> The &#8216;mfRollMaxSpeed&#8217; variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 299, 309. LuxPlayer.cpp 309<\/li>\n<\/ul>\n<p>  Let&#8217;s look at the class itself and at its fields:<\/p>\n<pre><code class=\"cpp\">class cLuxPlayer : .... {   .... private:   ....   float mfRoll;   float mfRollGoal;   float mfRollSpeedMul;   float mfRollMaxSpeed;    float mfLeanRoll;   float mfLeanRollGoal;   float mfLeanRollSpeedMul;   float mfLeanRollMaxSpeed;    cVector3f mvCamAnimPos;   cVector3f mvCamAnimPosGoal;   float mfCamAnimPosSpeedMul;   float mfCamAnimPosMaxSpeed;   .... }<\/code><\/pre>\n<p>  Interestingly, there are three similar variable blocks with related names: <i>mfRoll<\/i>, <i>mfLeanRoll<\/i>, and <i>mvCamAnimPos<\/i>. In <i>Reset<\/i>, these three blocks are reset to zero, except for the last two variables from the third block, <i>mfCamAnimPosSpeedMul<\/i> and <i>mfCamAnimPosMaxSpeed<\/i>. Just in place of these two variables, duplicated assignments are found. Most likely, all these assignments were copied from the first assignment block, and then the variable names were replaced with the necessary ones.<\/p>\n<p>  It may be that the two missing variables should not have been reset, but the opposite is also very likely. In any case, repeated assignments will not be of great help in supporting this code. As you can see, in a long set of identical actions, you may not notice such an error, and the analyzer helps you out here.<\/p>\n<p>  <b>Fragment 5.5.<\/b><\/p>\n<p>  The code is very similar to the previous one. Let me give you a code snippet and a warning from the analyzer for it right away.<\/p>\n<p>  <a href=\"https:\/\/www.viva64.com\/en\/w\/v519\/\">V519<\/a> The &#8216;mfTimePos&#8217; variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 49, 53. AnimationState.cpp 53<\/p>\n<pre><code class=\"cpp\">cAnimationState::cAnimationState(....) {   ....   mfTimePos = 0;   mfWeight = 1;   mfSpeed = 1.0f;   mfBaseSpeed = 1.0f;   mfTimePos = 0;   mfPrevTimePos=0;   .... }<\/code><\/pre>\n<p>  The <i>mfTimePos<\/i> variable was set to 0 twice. As in the previous example, let&#8217;s get into in the declaration of this field:<\/p>\n<pre><code class=\"cpp\">class cAnimationState {   .... private:   ....   \/\/Properties of the animation   float mfLength;   float mfWeight;   float mfSpeed;   float mfTimePos;   float mfPrevTimePos;   .... }<\/code><\/pre>\n<p>  You may notice that this declarations block also corresponds to the assignment order in the erroneous code snippet, as in the previous example. Here in the assignment, <i>mfTimePos<\/i> gets the value instead of the <i>mfLength<\/i> variable. Except for in this case, the error can&#8217;t be explained by copying the block and the &#171;last line effect&#187;. <i>mfLength<\/i> may not need to be assigned a new value, but this piece of code is still dubious.<\/p>\n<p>  <b>Fragment 6.<\/b><\/p>\n<p>  This part of code from &#171;Amnesia: A Machine For Pigs&#187; sparked off the analyzer to issue a truckload of warnings. I will give only a part of the code that triggered errors of the same kind:<\/p>\n<pre><code class=\"cpp\">void cLuxEnemyMover::UpdateMoveAnimation(float afTimeStep) {   ....   if(prevMoveState != mMoveState)   {     ....      \/\/Backward     if(mMoveState == eLuxEnemyMoveState_Backward)     {       ....     }     ....     \/\/Walking     else if(mMoveState == eLuxEnemyMoveState_Walking)     {       bool bSync =    prevMoveState == eLuxEnemyMoveState_Running                    || eLuxEnemyMoveState_Jogging                     ? true : false;       ....     }     ....   } }<\/code><\/pre>\n<p>  Where is the error here?<\/p>\n<p>  Here are the analyzer warnings:<\/p>\n<ul>\n<li><a href=\"https:\/\/www.viva64.com\/en\/w\/v768\/\">V768<\/a> The enumeration constant &#8216;eLuxEnemyMoveState_Jogging&#8217; is used as a variable of a Boolean-type. LuxEnemyMover.cpp 672<\/li>\n<li><a href=\"https:\/\/www.viva64.com\/en\/w\/v768\/\">V768<\/a> The enumeration constant &#8216;eLuxEnemyMoveState_Walking&#8217; is used as a variable of a Boolean-type. LuxEnemyMover.cpp 680<\/li>\n<li><a href=\"https:\/\/www.viva64.com\/en\/w\/v768\/\">V768<\/a> The enumeration constant &#8216;eLuxEnemyMoveState_Jogging&#8217; is used as a variable of a Boolean-type. LuxEnemyMover.cpp 688<\/li>\n<\/ul>\n<p>  The if-else-if sequence in the original code is repeated, and further these warnings were issued for each body of each <i>else if<\/i>.<\/p>\n<p>  Let&#8217;s consider the line that the analyzer points to:<\/p>\n<pre><code class=\"cpp\">bool bSync =    prevMoveState == eLuxEnemyMoveState_Running              || eLuxEnemyMoveState_Jogging               ? true : false;<\/code><\/pre>\n<p>  No surprise, an error crept into such an expression, originally written in line. And I&#8217;m sure you&#8217;ve already noticed it. The <i>eLuxEnemyMoveState_Jogging<\/i> enumeration element is not compared with anything, but its value is checked. Most likely, the expression &#8216;prevMoveState == eLuxEnemyMoveState_Jogging&#8217;was meant.<\/p>\n<p>  Such a mistake may seem quite harmless. But in another article about <a href=\"https:\/\/www.viva64.com\/en\/b\/0647\/\">checking the Bullet Engine<\/a>, among the commits to the project, I found a <a href=\"https:\/\/github.com\/bulletphysics\/bullet3\/pull\/1289\">fix for an error<\/a> of the same kind, which led to the fact that forces were applied to objects from the wrong side. As for this case, this error was made several times. Well, note that the ternary condition is completely meaningless, since it will be applied to the boolean results of logical operators in the last place.<\/p>\n<p>  <b>Fragment 7.<\/b><\/p>\n<p>  Finally, the last couple of examples of copy-paste errors. This time again in a conditional statement. The analyzer issued a warning for this piece of code:<\/p>\n<pre><code class=\"cpp\">void iParticleEmitter::SetSubDivUV(const cVector2l &amp;avSubDiv) {   \/\/Check so that there is any subdivision   \/\/ and that no sub divison axis is   \/\/equal or below zero   if( (avSubDiv.x > 1 || avSubDiv.x > 1) &amp;&amp; (avSubDiv.x >0 &amp;&amp; avSubDiv.y >0))   {     ....   }   .... }<\/code><\/pre>\n<p>  I think that in such a separate fragment from the entire code, it is quite easy to notice an awkward place. Nonetheless, the error found its way to hide from developers of this game.<\/p>\n<p>  The analyzer issued the following message:<\/p>\n<p>  <a href=\"https:\/\/www.viva64.com\/en\/w\/v501\/\">V501<\/a> There are identical sub-expressions to the left and to the right of the &#8216;||&#8217; operator: avSubDiv.x > 1 || avSubDiv.x > 1 ParticleEmitter.cpp 199<\/p>\n<p>  The second parenthesis in the condition indicates that both <i>x<\/i> and <i>y<\/i> fields are checked. But in the first parenthesis, for some reason, this point was missed and only the <i>x<\/i> field is checked. In addition, judging by the review comment, both fields should have been checked. So it is not the &#171;last line effect&#187; that has worked here, but rather the &#171;first line effect&#187;, since in the first parenthesis the author forgot to replace accessing the <i>x<\/i> field with accessing the <i>y<\/i> field.<\/p>\n<p>  Obviously, such errors are very insidious, since in this case even the explanatory comment to the condition did not help the developer.<\/p>\n<p>  In such cases, I would recommend making it a habit to record related checks in tabular form. This way, it is easier both to edit, and notice a defect:<\/p>\n<pre><code class=\"cpp\">if(   (avSubDiv.x > 1 || avSubDiv.x > 1)    &amp;&amp; (avSubDiv.x > 0 &amp;&amp; avSubDiv.y > 0))<\/code><\/pre>\n<p>  <b>Fragment 7.5.<\/b><\/p>\n<p>  An absolutely similar error was found in a different place:<\/p>\n<pre><code class=\"cpp\">static bool EdgeTriEqual(const cTriEdge &amp;edge1, const cTriEdge &amp;edge2) {   if(edge1.tri1 == edge2.tri1 &amp;&amp; edge1.tri2 == edge2.tri2)     return true;   if(edge1.tri1 == edge1.tri1 &amp;&amp; edge1.tri2 == edge2.tri1)     return true;   return false; }<\/code><\/pre>\n<p>  Did you get a chance to see where it was hiding? It is not for nothing that we&#8217;ve already dealt with so many examples \ud83d\ude42<\/p>\n<p>  The analyzer has issued a warning:<\/p>\n<p>  <a href=\"https:\/\/www.viva64.com\/en\/w\/v501\/\">V501<\/a> There are identical sub-expressions to the left and to the right of the &#8216;==&#8217; operator: edge1.tri1 == edge1.tri1 Math.cpp 2914<\/p>\n<p>  We&#8217;ll sort this fragment through one part after another. Obviously, the first check checks the equality of the fields <i>edge1.tri1 <\/i>and <i>edge2.tri2<\/i>, and at the same time the equality of <i>edge1.tri2<\/i> and <i>edge2.tri2<\/i>:<\/p>\n<pre><code class=\"cpp\">edge1.tri1 -> edge2.tri1 edge1.tri2 -> edge2.tri2<\/code><\/pre>\n<p>  In the second check, judging by the correct part of the check &#8216;edge1.tri2 == edge2.tri1&#8217;, equality of these fields had to be checked in a crosswise way:<\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/post_images\/d73\/a22\/2ce\/d73a222ce82b81eac5215a51d7b6d70f.png\" alt=\"image7.png\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/d73\/a22\/2ce\/d73a222ce82b81eac5215a51d7b6d70f.png\"\/><\/div>\n<p>  But instead of checking for <i>edge1.tri1 == edge2.tri2<\/i>, there was a pointless check <i>edge1.tri1 == edge1.tri1<\/i>. By the way, all this is in the function, I removed nothing. Still such an error has wormed into the code.<\/p>\n<h2>Other errors<\/h2>\n<p>  <b>Fragment 1.<\/b><\/p>\n<p>  Here is the following code snippet with the original indents.<\/p>\n<pre><code class=\"cpp\">void iCharacterBody::CheckMoveCollision(....) {   ....   \/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/   \/\/Forward velocity reflection   \/\/Make sure that new velocity points in the right direction   \/\/and that it is not too large!   if(mfMoveSpeed[eCharDir_Forward] != 0)   {     vForwardVel = ....;     float fForwardSpeed = vForwardVel.Length();     if(mfMoveSpeed[eCharDir_Forward] > 0)       if(mfMoveSpeed[eCharDir_Forward] > fForwardSpeed)         mfMoveSpeed[eCharDir_Forward] = fForwardSpeed;     else       if(mfMoveSpeed[eCharDir_Forward] &lt; fForwardSpeed)         mfMoveSpeed[eCharDir_Forward] = -fForwardSpeed;   }   .... }<\/code><\/pre>\n<p>  PVS-Studio warning: <a href=\"https:\/\/www.viva64.com\/en\/w\/v563\/\">V563<\/a> It is possible that this &#8216;else&#8217; branch must apply to the previous &#8216;if&#8217; statement. CharacterBody.cpp 1591<\/p>\n<p>  This example can be confusing. Why does <i>else<\/i> have the same indent as the outer one at the <i>if<\/i> level? Is it implied that <i>else<\/i> is for the outermost condition? Well, then one has to place braces correctly, otherwise <i>else<\/i> refers to the right-front <i>if<\/i>.<\/p>\n<pre><code class=\"cpp\">if(mfMoveSpeed[eCharDir_Forward] > 0) {   if(mfMoveSpeed[eCharDir_Forward] > fForwardSpeed)     mfMoveSpeed[eCharDir_Forward] = fForwardSpeed; } else if(mfMoveSpeed[eCharDir_Forward] &lt; fForwardSpeed)  {   mfMoveSpeed[eCharDir_Forward] = -fForwardSpeed; }<\/code><\/pre>\n<p>  Or is it not so? When writing this article, I changed my mind several times about which version of the actions sequence for this code was most likely.<\/p>\n<p>  If we dig a bit deeper into this code, it turns out that the variable <i>fForwardSpeed<\/i>, which is compared in the lower <i>if<\/i>, can&#8217;t have a value less than zero, since it gets the value from the <i>Length<\/i> method:<\/p>\n<pre><code class=\"cpp\">inline T Length() const {   return sqrt( x * x + y * y +  z * z); }<\/code><\/pre>\n<p>  Then, most likely, the point of these checks is that we first check whether the <i>mfMoveSpeed<\/i> element is greater than zero, and then check its value relative to <i>fForwardSpeed<\/i>. Moreover, the last two <i>if<\/i> statements correspond to each other in terms of the wording.<\/p>\n<p>  In this case, the original code will work as intended! But it will definitely make the one who comes to edit\/refactor it rack their brains.<\/p>\n<p>  I thought I&#8217;d never come across code that looked like this. Out of interest, I looked at our <a href=\"https:\/\/www.viva64.com\/en\/examples\/\">collection of errors<\/a> found in open-source projects and described in articles. Examples of this error were also found in other projects \u2014 you can look at them <a href=\"https:\/\/www.viva64.com\/en\/examples\/v563\/\">yourself<\/a>.<\/p>\n<p>  Please, don&#8217;t write like this, even if you are clear about it yourself. Use braces, or correct indentation, or better \u2014 both. Don&#8217;t make those who come to understand your code suffer, or yourself in the future \ud83d\ude09<\/p>\n<p>  <b>Fragment 2.<\/b><\/p>\n<p>  This error has taken me aback, so it took a while to find logic here. In the end, it still seems to me that this is most likely a mistake, a quite whopping one.<\/p>\n<p>  Take a look at the code:<\/p>\n<pre><code class=\"cpp\">bool cBinaryBuffer::DecompressAndAdd(char *apSrcData, size_t alSize) {   ....   \/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/   \/\/ Init decompression   int ret = inflateInit(&amp;zipStream);   if (ret != Z_OK) return false;    \/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/   \/\/ Decompress, chunk by chunk    do   {     \/\/Set current output chunk     zipStream.avail_out = lMaxChunkSize;     ....     \/\/Decompress as much as possible to current chunk     int ret = inflate(&amp;zipStream, Z_NO_FLUSH);     if(ret != Z_OK &amp;&amp; ret != Z_STREAM_END)     {       inflateEnd(&amp;zipStream);       return false;     }     ....   }   while (zipStream.avail_out == 0 &amp;&amp; ret != Z_STREAM_END);   ....   return true; }<\/code><\/pre>\n<p>  <a href=\"https:\/\/www.viva64.com\/en\/w\/v711\/\">V711<\/a> It is dangerous to create a local variable within a loop with a same name as a variable controlling this loop. BinaryBuffer.cpp 371<\/p>\n<p>  So, we have a <i>ret<\/i> variable, which controls the exit from the <i>do-while<\/i> loop. But inside this loop, instead of assigning a new value to this external variable, a new variable named <i>ret<\/i> is declared. As a result, it overrides the external <i>ret<\/i> variable, and the variable that is checked in the loop condition will never change.<\/p>\n<p>  With mishap coinciding, such a loop could become infinite. Most likely, in this case, it is an internal condition that saves this code. It checks the value of the internal <i>ret<\/i> variable and leads to the exit of the function.<\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/post_images\/772\/eb5\/4ec\/772eb54ec62b4efec1de7dd3fc247b27.png\" alt=\"image8.png\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/772\/eb5\/4ec\/772eb54ec62b4efec1de7dd3fc247b27.png\"\/><\/div>\n<p>  <\/p>\n<h2>Conclusion<\/h2>\n<p>  Very often, developers do not use static analysis regularly, but with long breaks. Or even run the project through the analyzer only once. As a result of this approach, the analyzer often does not detect anything serious or finds something like the examples we are considering, which may not particularly affect the game&#8217;s performance. One gets the impression that the analyzer is not really useful. Well, it found such places, but everything still works.<\/p>\n<p>  The fact is that there were similar places where a mistake was on the surface, and definitely resulted in a program error. These fragments have already been refined due to long hours of debugging, tests runs, Q&amp;A department. As a result, when the analyzer checks the project only once, it shows only those problems that did not manifest themselves in any way. Sometimes such problems comprise critical issues that actually affected the program but will not likely to follow their scenario. Therefore, this error was unknown to the developers.<\/p>\n<p>  That&#8217;s why it is extremely important to evaluate the usefulness of static analysis only after its regular use. Once a one-time run through PVS-Studio revealed such suspicious and sloppy fragments in the code of this game, imagine how many obvious errors of this kind had to be localized and fixed in course of development.<\/p>\n<p>  Use a static analyzer regularly!<\/p><\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/524402\/\"> https:\/\/habr.com\/ru\/articles\/524402\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-1\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/post_images\/bc8\/fa6\/790\/bc8fa67904591e4e15c5b7d4e6c26e08.png\" alt=\"image1.png\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/bc8\/fa6\/790\/bc8fa67904591e4e15c5b7d4e6c26e08.png\"\/><\/div>\n<p>  Just before the release of the &#171;Amnesia: Rebirth&#187; game, the vendor &#171;Fractional Games&#187; opened the source code of the legendary &#171;Amnesia: The Dark Descent&#187; and its sequel &#171;Amnesia: A Machine For Pigs&#187;. Why not use the static analysis tool to see what dreadful mistakes are hidden in the inside of these cult horror games?  <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-387467","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/387467","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=387467"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/387467\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=387467"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=387467"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=387467"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}