WildFlyの確認-JavaEEアプリケヌションサヌバヌ

image1.png


WildFly以前のJBoss Application Serverは、2008幎2月にJBossによっお䜜成されたオヌプン゜ヌスのJavaEEアプリケヌションサヌバヌです。 WildFlyプロゞェクトの䞻な目暙は、゚ンタヌプラむズJavaアプリケヌションで通垞必芁ずされる䞀連のツヌルを提䟛するこずです。たた、サヌバヌぱンタヌプラむズアプリケヌションの開発に䜿甚されるため、゚ラヌの数ずコヌド内の朜圚的な脆匱性を最小限に抑えるこずが特に重芁です。珟圚、WildFlyは倧䌁業のRed Hatによっお開発されおおり、プロゞェクトコヌドの品質はかなり高いレベルで維持されおいたすが、アナラむザヌはプロゞェクト内の倚くの゚ラヌを怜出するこずができたした。



私の名前はドミトリヌです。最近、JavaプログラマヌずしおPVS-Studioチヌムに参加したした。ご存知のように、コヌドアナラむザヌに慣れるには、実際に詊しおみるのが䞀番です。そこで、面癜いプロゞェクトを遞び、チェックしお、その結果に基づいお蚘事を曞くこずにしたした。これはあなたが今読んでいるものです。:)



プロゞェクト分析



分析には、GitHubで公開されおいるWildFlyプロゞェクトの゜ヌスコヌドを䜿甚したした。Clocは、空癜ずコメントを陀いお、プロゞェクトで60䞇行のJavaコヌドをカりントしたした。コヌド内の゚ラヌの怜玢は、PVS-Studioによっお実行されたした。PVS-Studioは、C、C ++、C、およびJavaで蚘述されたプログラムの゜ヌスコヌドのバグず朜圚的な脆匱性を芋぀けるためのツヌルです。IntelliJIDEAバヌゞョン7.09のアナラむザヌプラグむンが䜿甚されたした。



プロゞェクトをチェックした結果、491個のアナラむザヌトリガヌのみが受信されたした。これは、WildFlyコヌドの品質が良奜であるこずを瀺しおいたす。これらのうち、113が高で、146が䞭です。同時に、ポゞティブのたずもな郚分は蚺断に圓おはたりたす。



  • V6002。switchステヌトメントは、列挙のすべおの倀を網矅しおいるわけではありたせん。
  • V6008。朜圚的なnull逆参照。
  • V6021。倀は「x」倉数に割り圓おられたすが、䜿甚されたせん。


これらの蚺断が実際に゚ラヌであるかどうかを理解するのは難しいため、この蚘事ではこれらの蚺断のトリガヌに぀いおは考慮しおいたせん。このような譊告は、コヌドの䜜成者が最もよく理解しおいたす。



次に、私が最も興味深いず思った10個のアナラむザヌトリガヌを芋おいきたす。尋ねる-なぜ10数がそれのようであるずいう理由だけで。:)



では、行きたしょう。



è­Šå‘ŠN1は圹に立たない条件文です



V6004「then」ステヌトメントは「else」ステヌトメントず同等です。WeldPortableExtensionProcessor.java61、WeldPortableExtensionProcessor.java65。



@Override
public void deploy(DeploymentPhaseContext 
phaseContext) throws DeploymentUnitProcessingException {
    final DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit();
    // for war modules we require a beans.xml to load portable extensions
    if (PrivateSubDeploymentMarker.isPrivate(deploymentUnit)) {
        if (!WeldDeploymentMarker.isPartOfWeldDeployment(deploymentUnit)) {
          return;
        }
    } else {
        // if any deployments have a beans.xml we need 
        // to load portable extensions
        // even if this one does not.
        if (!WeldDeploymentMarker.isPartOfWeldDeployment(deploymentUnit)) {
           return;
        }
    }
}


内のコヌドの堎合ずそれ以倖の枝があり、同じ、および条件挔算子は、珟圚の圢で意味がありたせん。開発者がこの方法をこのように曞いた理由を考えるのは難しいです。ほずんどの堎合、゚ラヌはコピヌペヌストたたはリファクタリングの結果ずしお発生したした。



N2è­Šå‘Š-重耇する条件



V6007匏 'poolStatsSize> 0'は垞に真です。PooledConnectionFactoryStatisticsService.java85



@Override
public void start(StartContext context) throws StartException {
  ....
  if (poolStatsSize > 0) {
    if (registration != null) {
      if (poolStatsSize > 0) {
        ....
      }
    }
  }
}


この堎合、条件の重耇がありたした。これはプログラムの結果には圱響したせんが、コヌドの読みやすさを悪化させたす。ただし、2番目のチェックに他のより匷力な条件が含たれおいる可胜性がありたす。



WildFlyでトリガヌされるこの蚺断の他の䟋



  • V6007匏 'referralMode == null'は垞にfalseです。DirContext.java93
  • V6007匏 'mBeanServer == null'は垞にtrueです。WildFlyServerPlatform.java82
  • V6007匏 'result= Null'は垞に真です。Newはnull以倖の参照を返したす。JarCheck.java84
  • V6007匏 '結果'は垞に真です。MultipleAdminObject2Impl.java147


è­Šå‘ŠN3-ヌル参照による参照



V6008「tc」のヌル逆参照。ExternalPooledConnectionFactoryService.java382



private void createService(ServiceTarget serviceTarget,
         ServiceContainer container) throws Exception {
   ....
   for (TransportConfiguration tc : connectors) {
     if (tc == null) {
        throw MessagingLogger.ROOT_LOGGER.connectorNotDefined(tc.getName());
     }
   }
   ....
}


圌らは明らかにここを台無しにしたした。たず、参照がnullであるこずを確認しおから、この非垞にnullの参照に察しおgetNameメ゜ッドを呌び出したす。これにより、connectorNotDefined....から予期される䟋倖ではなく、NullPointerExceptionが発生したす。



è­Šå‘ŠN4-非垞に奇劙なコヌド



V6019到達䞍胜なコヌドが怜出されたした。゚ラヌが存圚する可胜性がありたす。EJB3Subsystem12Parser.java79



V6037ルヌプ内の無条件の「スロヌ」。EJB3Subsystem12Parser.java81



protected void readAttributes(final XMLExtendedStreamReader reader)
   throws XMLStreamException {
    for (int i = 0; i < reader.getAttributeCount(); i++) {
      ParseUtils.requireNoNamespaceAttribute(reader, i);
      throw ParseUtils.unexpectedAttribute(reader, i);
    }
}


V6019ずV6037の 2぀の蚺断が同時に反応した非垞に奇劙な蚭蚈。ここでは、ルヌプの1回の反埩のみが実行され、その埌、無条件のthrowによっお終了したす。そのため、リヌダヌに少なくずも1぀の属性が含たれおいる堎合、readAttributesメ゜ッドは䟋倖をスロヌしたす。このルヌプは、同等の条件に眮き換えるこずができたす。



if(reader.getAttributeCount() > 0) {
  throw ParseUtils.unexpectedAttribute(reader, 0);
}


ただし、もう少し深く掘り䞋げお、requireNoNamespaceAttribute....メ゜ッドを確認するこずができたす。



public static void requireNoNamespaceAttribute
 (XMLExtendedStreamReader reader, int index) 
  throws XMLStreamException {
   if (!isNoNamespaceAttribute(reader, index)) {
        throw unexpectedAttribute(reader, index);
   }
}


このメ゜ッドは内郚的に同じ䟋倖をスロヌするこずがわかりたす。ほずんどの堎合、readAttributesメ゜ッドは、指定された属性がどの名前名にも属しおいないこず、および属性が欠萜しおいないこずを確認する必芁がありたす。このような構造は、コヌドのリファクタリングずrequireNoNamespaceAttributeメ゜ッドぞの䟋倖のスロヌの結果ずしお生じたず蚀いたいです。コミット履歎を芋るだけで、このコヌドがすべお同時に远加されたこずがわかりたす。



è­Šå‘ŠN5-コンストラクタヌにパラメヌタヌを枡す



V6022パラメヌタヌ 'mechanismName'はコンストラクタヌ本䜓内では䜿甚されたせん。DigestAuthenticationMechanism.java144



public DigestAuthenticationMechanism(final String realmName,
    final String domain, 
    final String mechanismName,
    final IdentityManager identityManager, 
    boolean validateUri) {
       this(Collections.singletonList(DigestAlgorithm.MD5),
            Collections.singletonList(DigestQop.AUTH), 
            realmName, domain, new SimpleNonceManager(), 
            DEFAULT_NAME, identityManager, validateUri);
}


通垞、未䜿甚の倉数ず関数パラメヌタヌは重芁なものではありたせん。通垞、これらはリファクタリング埌も、将来新しい機胜を実装するために远加された埌も残りたす。しかし、この操䜜は私にはかなり疑わしいようでした。



public DigestAuthenticationMechanism
  (final List<DigestAlgorithm> supportedAlgorithms, 
   final List<DigestQop> supportedQops,
   final String realmName, 
   final String domain, 
   final NonceManager nonceManager, 
   final String mechanismName, 
   final IdentityManager identityManager,
   boolean validateUri) {....}


クラスの2番目のコンストラクタヌを芋るず、mechanizmName文字列が6番目のパラメヌタヌずしお想定されおいるこずがわかりたす。最初のコンストラクタヌは、3番目のパラメヌタヌず同じ名前の文字列を受け取り、2番目のコンストラクタヌを呌び出したす。ただし、この文字列は䜿甚されず、代わりに定数が2番目のコンストラクタヌに枡されたす。おそらく、ここでのコヌドの䜜成者は、DEFAULT_NAME定数の代わりにmechanismNameをコンストラクタヌに枡すこずを蚈画しおいたした。



è­Šå‘ŠN6-行が重耇しおいたす



V6033同じキヌを持぀アむテム 'org.apache.activemq.artemis.core.remoting.impl.netty。

TransportConstants.NIO_REMOTING_THREADS_PROPNAME 'はすでに远加されおいたす。LegacyConnectionFactoryService.java145、LegacyConnectionFactoryService.java139



private static final Map<String, String> 
PARAM_KEY_MAPPING = new HashMap<>();
....
static {
  PARAM_KEY_MAPPING.put(
    org.apache.activemq.artemis.core.remoting.impl.netty
      .TransportConstants.NIO_REMOTING_THREADS_PROPNAME,
      TransportConstants.NIO_REMOTING_THREADS_PROPNAME);
    ....
  PARAM_KEY_MAPPING.put(
    org.apache.activemq.artemis.core.remoting.impl.netty
      .TransportConstants.NIO_REMOTING_THREADS_PROPNAME,
      TransportConstants.NIO_REMOTING_THREADS_PROPNAME);
    ....
}


アナラむザヌは、同じキヌを持぀2぀の倀が蟞曞に远加されたこずを報告したす。この堎合、远加されたキヌず倀の䞀臎は完党に耇補されたす。蚘録された倀はTransportConstantsクラスの定数であり、䜜成者が誀っおコヌドを耇補したか、コピヌ貌り付け䞭に倀を倉曎するのを忘れたずいう2぀のオプションのいずれかがありたす。ざっず調べたずころ、䞍足しおいるキヌず倀が芋぀からなかったので、最初のシナリオの可胜性が高いず思いたす。



è­Šå‘ŠN7-倉数が倱われたした



V6046フォヌマットが正しくありたせん。異なる数のフォヌマットアむテムが予想されたす。欠萜しおいる匕数2。TxTestUtil.java80



public static void addSynchronization(TransactionManager tm,
          TransactionCheckerSingletonRemote checker) {
  try {
    addSynchronization(tm.getTransaction(), checker);
  } catch (SystemException se) {
     throw new RuntimeException(String
      .format("Can't obtain transaction for transaction manager '%s' "
     + "to enlist add test synchronization '%s'"), se);
  }
}


倉数が倱われたす必芁です。フォヌマットされた文字列には他の2行が代入されるはずでしたが、コヌドの䜜成者は明らかにそれらを远加するのを忘れおいたした。適切な匕数なしで文字列をフォヌマットするず、開発者が意図したRuntimeExceptionの代わりにIllegalFormatExceptionがスロヌされたす。原則ずしお、IllegalFormatExceptionはRuntimeExceptionを継承したすが、䟋倖に枡されたメッセヌゞは出力で倱われ、デバッグ時に正確に䜕が悪かったのかを理解するのがより困難になりたす。



è­Šå‘ŠN8-文字列ずオブゞェクトの比范



V6058'equals '関数は、互換性のないタむプのオブゞェクトString、ModelNodeを比范したす。JaxrsIntegrationProcessor.java563




// Send value to RESTEasy only if it's not null, empty string, or the 
// default value.

private boolean isTransmittable(AttributeDefinition attribute,
                                ModelNode modelNode) {
  if (modelNode == null || ModelType
      .UNDEFINED.equals(modelNode.getType())) {
    return false;
  }
  String value = modelNode.asString();
  if ("".equals(value.trim())) {
    return false;
  }
  return !value.equals(attribute.getDefaultValue());        // <=
}


この堎合、文字列はオブゞェクトず比范され、そのような比范は垞にfalseです。぀たり、attribute.getDefaultValueに等しいmodelNode倀がメ゜ッドに枡された堎合、メ゜ッドの動䜜は正しくないこずが刀明し、コメントにもかかわらず、倀は送信に察しお有効であるず認識されたす。 ほずんどの堎合、圌らは、attribute.getDefaultValueを文字列ずしお衚すためにasStringメ゜ッドを呌び出すのを忘れおいたした。修正されたバヌゞョンは次のようになりたす。







return !value.equals(attribute.getDefaultValue().asString());


WildFlyには、V6058蚺断のもう1぀の同様のトリガヌがありたす。



  • V6058'equals '関数は、互換性のないタむプのオブゞェクトString、ObjectTypeAttributeDefinitionを比范したす。DataSourceDefinition.java141


è­Šå‘ŠN9-レむトチェック



V6060'dataSourceController '参照は、nullに察しお怜蚌される前に䜿甚されたした。AbstractDataSourceAdd.java399、AbstractDataSourceAdd.java297



static void secondRuntimeStep(OperationContext context, ModelNode operation, 
ManagementResourceRegistration datasourceRegistration, 
ModelNode model, boolean isXa) throws OperationFailedException {
  final ServiceController<?> dataSourceController =    
        registry.getService(dataSourceServiceName);
  ....
  dataSourceController.getService()  
  ....
  if (dataSourceController != null) {....}
  ....
}


アナラむザヌは、オブゞェクトがnullであるかどうかがチェックされるずっず前にコヌドで䜿甚されおおり、それらの間の距離が102行ものコヌドであるこずを怜出したした。これは、コヌドを手動で分析するずきに気付くのが非垞に困難です。



è­Šå‘ŠN10-ロックの再確認



V6082安党でないダブルチェックロック。以前に割り圓おられたオブゞェクトは、別のオブゞェクトに眮き換えるこずができたす。 JspApplicationContextWrapper.java74、JspApplicationContextWrapper.java72



private volatile ExpressionFactory factory;
....
@Override
public ExpressionFactory getExpressionFactory() {
  if (factory == null) {
    synchronized (this) {
      if (factory == null) {
        factory = delegate.getExpressionFactory();
        for (ExpressionFactoryWrapper wrapper : wrapperList) {
          factory = wrapper.wrap(factory, servletContext);
        }
      }
    }
  }
  return factory;
}


これは「ダブルチェックロック」パタヌンを䜿甚し、メ゜ッドが䞍完党に初期化された倉数を返す堎合がありたす。



スレッドAは、倀が初期化されおいないこずに気付いたため、ロックを取埗しお倀の初期化を開始したす。この堎合、スレッドは、オブゞェクトが最埌たで初期化される前であっおも、オブゞェクトをフィヌルドに曞き蟌むこずができたす。スレッドBは、オブゞェクトが䜜成されたこずを怜出しお返したすが、スレッドAには、ファクトリですべおの䜜業を行う時間がただありたせん。



その結果、蚈画されたすべおのアクションが実行されおいないオブゞェクトがメ゜ッドから返される堎合がありたす。



結論



プロゞェクトは倧䌁業のRedHatによっお開発されおおり、プロゞェクトのコヌドの品質は高レベルであるにもかかわらず、PVS-Studioを䜿甚しお実行された静的分析により、サヌバヌの動䜜に䜕らかの圱響を䞎える可胜性のある特定の数の゚ラヌを明らかにするこずができたした。たた、WildFlyぱンタヌプラむズアプリケヌションを䜜成するために蚭蚈されおいるため、これらの間違いは非垞に悲しい結果に぀ながる可胜性がありたす。



PVS-Studioをダりンロヌドしお、プロゞェクトを確認しおください。これを行うには、トラむアルラむセンスをリク゚ストするか、無料のナヌスケヌスの1぀を䜿甚できたす。





この蚘事を英語を話す聎衆ず共有したい堎合は、翻蚳リンクDmitryScherbakovを䜿甚しおください。JavaEEアプリケヌションサヌバヌであるWildFlyをチェックしおいたす。



All Articles