Analysieren des Codes der CUBA-Plattform mit PVS-Studio


Java-Entwickler haben Zugriff auf eine Reihe nützlicher Tools, mit denen qualitativ hochwertiger Code geschrieben werden kann, z. B. die leistungsstarke IDE IntelliJ IDEA, die kostenlosen Analysatoren SpotBugs, PMD und dergleichen. Die Entwickler, die an der CUBA-Plattform arbeiten, haben bereits alle diese Funktionen verwendet. Diese Überprüfung wird zeigen, wie das Projekt noch mehr von der Verwendung des statischen Code-Analysators PVS-Studio profitieren kann.

Ein paar Worte zum Projekt und zum Analysator


Die CUBA-Plattform ist ein übergeordnetes Framework für die Entwicklung von Unternehmensanwendungen. Die Plattform abstrahiert Entwickler von zugrunde liegenden Technologien, damit sie sich auf die Geschäftsaufgaben konzentrieren können und gleichzeitig die volle Flexibilität behalten, indem sie uneingeschränkten Zugriff auf Code auf niedriger Ebene gewähren. Der Quellcode wurde von GitHub heruntergeladen.

PVS-Studio ist ein Tool zum Erkennen von Fehlern und potenziellen Sicherheitslücken im Quellcode von Programmen, die in C, C ++, C # und Java geschrieben wurden. Der Analysator läuft auf 64-Bit-Windows-, Linux- und MacOS-Systemen. Um Java-Programmierern die Arbeit zu erleichtern, haben wir Plugins für Maven, Gradle und IntelliJ IDEA entwickelt. Ich habe das Projekt mit dem Gradle-Plugin überprüft und es lief reibungslos ab.

Fehler in den Bedingungen


Warnung 1

V6007 Ausdruck 'StringUtils.isNotEmpty ("handleTabKey")' ist immer wahr. SourceCodeEditorLoader.java (60)

@Override public void loadComponent() { .... String handleTabKey = element.attributeValue("handleTabKey"); if (StringUtils.isNotEmpty("handleTabKey")) { resultComponent.setHandleTabKey(Boolean.parseBoolean(handleTabKey)); } .... } 

Der aus dem Element extrahierte Attributwert wird nicht überprüft. Stattdessen erhält die Funktion isNotEmpty anstelle der Variablen handleTabKey ein Zeichenfolgenliteral als Argument.

Ein ähnlicher Fehler wurde in der Datei AbstractTableLoader.java gefunden:

  • V6007 Ausdruck 'StringUtils.isNotEmpty ("editierbar")' ist immer wahr. AbstractTableLoader.java (596)

Warnung 2

V6007 Der Ausdruck 'previousMenuItemFlatIndex> = 0' ist immer wahr. CubaSideMenuWidget.java (328)

 protected MenuItemWidget findNextMenuItem(MenuItemWidget currentItem) { List<MenuTreeNode> menuTree = buildVisibleTree(this); List<MenuItemWidget> menuItemWidgets = menuTreeToList(menuTree); int menuItemFlatIndex = menuItemWidgets.indexOf(currentItem); int previousMenuItemFlatIndex = menuItemFlatIndex + 1; if (previousMenuItemFlatIndex >= 0) { return menuItemWidgets.get(previousMenuItemFlatIndex); } return null; } 

Die Funktion indexOf gibt -1 zurück, wenn das Element nicht in der Liste gefunden wird. Der Wert 1 wird dann zum Index hinzugefügt, wodurch das Problem mit dem fehlenden Element verschleiert wird. Ein weiteres potenzielles Problem hat damit zu tun, dass die Variable previousMenuItemFlatIndex immer größer oder gleich Null ist. Wenn beispielsweise festgestellt wird, dass die Liste menuItemWidgets leer ist, führt das Programm zu einem Array-Überlauf.

Warnung 3

V6009 Die Funktion 'Löschen' könnte den Wert '-1' empfangen, während ein nicht negativer Wert erwartet wird. Argument überprüfen: 1. AbstractCollectionDatasource.java (556)

 protected DataLoadContextQuery createDataQuery(....) { .... StringBuilder orderBy = new StringBuilder(); .... if (orderBy.length() > 0) { orderBy.delete(orderBy.length() - 2, orderBy.length()); orderBy.insert(0, " order by "); } .... } 

Die letzten beiden Zeichen des orderBy- Puffers werden gelöscht, wenn die Gesamtzahl der Elemente größer als Null ist, d. H. Wenn die Zeichenfolge mindestens ein Zeichen enthält. Die Startposition, an der der Löschvorgang beginnt, wird jedoch um 2 versetzt. Wenn orderBy also zufällig ein Zeichen enthält, wird beim Versuch, es zu löschen, eine StringIndexOutOfBoundsException ausgelöst .

Warnung 4

V6013 Die Objekte 'masterCollection' und 'entity' werden als Referenz verglichen. Möglicherweise war ein Gleichstellungsvergleich beabsichtigt. CollectionPropertyContainerImpl.java (81)

 @Override public void setItems(@Nullable Collection<E> entities) { super.setItems(entities); Entity masterItem = master.getItemOrNull(); if (masterItem != null) { MetaProperty masterProperty = getMasterProperty(); Collection masterCollection = masterItem.getValue(masterProperty.getName()); if (masterCollection != entities) { updateMasterCollection(masterProperty, masterCollection, entities); } } } 

In der Funktion updateMasterCollection werden die Werte von Entitäten in masterCollection kopiert. Eine Zeile zuvor wurden die Sammlungen anhand von Referenzen verglichen, aber der Programmierer beabsichtigte wahrscheinlich, dass es sich um einen Vergleich nach Wert handelt.

Warnung 5

V6013 Die Objekte 'value' und 'oldValue' werden als Referenz verglichen. Möglicherweise war ein Gleichstellungsvergleich beabsichtigt. WebOptionsList.java (278)

 protected boolean isCollectionValuesChanged(Collection<I> value, Collection<I> oldValue) { return value != oldValue; } 

Dieser Fall ähnelt dem vorherigen. Die Sammlungen werden in der Funktion isCollectionValuesChanged verglichen, und der Referenzvergleich ist möglicherweise auch hier nicht beabsichtigt.

Redundante Bedingungen


Warnung 1

V6007 Ausdruck 'mask.charAt (i + offset)! = PlaceHolder' ist immer wahr. DatePickerDocument.java (238)

 private String calculateFormattedString(int offset, String text) .... { .... if ((mask.charAt(i + offset) == placeHolder)) { // <= .... } else if ((mask.charAt(i + offset) != placeHolder) && // <= (Character.isDigit(text.charAt(i)))) { .... } .... } 

Die zweite Bedingung prüft einen Ausdruck, der dem in der ersten Bedingung geprüften Ausdruck entgegengesetzt ist. Letzteres kann daher sicher entfernt werden, um den Code zu verkürzen.

V6007 Der Ausdruck 'connector == null' ist immer falsch. HTML5Support.java (169)

 private boolean validate(NativeEvent event) { .... while (connector == null) { widget = widget.getParent(); connector = Util.findConnectorFor(widget); } if (this.connector == connector) { return true; } else if (connector == null) { // <= return false; } else if (connector.getWidget() instanceof VDDHasDropHandler) { return false; } return true; } 

Nach dem Verlassen der while- Schleife ist der Wert der Connector- Variablen nicht gleich null , sodass die redundante Prüfung gelöscht werden kann.

Eine weitere verdächtige Warnung dieser Art, die untersucht werden muss:

  • V6007 Ausdruck 'StringUtils.isBlank (strValue)' ist immer wahr. Param.java (818)

Nicht erreichbarer Code in Tests


V6019 Nicht erreichbarer Code erkannt. Möglicherweise liegt ein Fehler vor. TransactionTest.java (283)

 private void throwException() { throw new RuntimeException(TEST_EXCEPTION_MSG); } @Test public void testSuspendRollback() { Transaction tx = cont.persistence().createTransaction(); try { .... Transaction tx1 = cont.persistence().createTransaction(); try { EntityManager em1 = cont.persistence().getEntityManager(); assertTrue(em != em1); Server server1 = em1.find(Server.class, server.getId()); assertNull(server1); throwException(); // <= tx1.commit(); // <= } catch (Exception e) { // } finally { tx1.end(); } tx.commit(); } finally { tx.end(); } } 

Die Funktion throwException löst eine Ausnahme aus, die die Ausführung des Aufrufs von tx1.commit verhindert . Diese beiden Zeilen sollten vertauscht werden, damit der Code ordnungsgemäß funktioniert.

Auch bei anderen Tests gab es einige ähnliche Probleme:

  • V6019 Nicht erreichbarer Code erkannt. Möglicherweise liegt ein Fehler vor. TransactionTest.java (218)
  • V6019 Nicht erreichbarer Code erkannt. Möglicherweise liegt ein Fehler vor. TransactionTest.java (163)
  • V6019 Nicht erreichbarer Code erkannt. Möglicherweise liegt ein Fehler vor. TransactionTest.java (203)
  • V6019 Nicht erreichbarer Code erkannt. Möglicherweise liegt ein Fehler vor. TransactionTest.java (137)
  • V6019 Nicht erreichbarer Code erkannt. Möglicherweise liegt ein Fehler vor. UpdateDetachedTest.java (153)
  • V6019 Nicht erreichbarer Code erkannt. Möglicherweise liegt ein Fehler vor. EclipseLinkDetachedTest.java (132)
  • V6019 Nicht erreichbarer Code erkannt. Möglicherweise liegt ein Fehler vor. PersistenceTest.java (223)

Verdächtige Argumente


Warnung 1

V6023 Der Parameter 'salt' wird vor der Verwendung immer im Methodenkörper neu geschrieben. BCryptEncryptionModule.java (47)

 @Override public String getHash(String content, String salt) { salt = BCrypt.gensalt(); return BCrypt.hashpw(content, salt); } 

In der Kryptographie ist Salt eine Datenzeichenfolge, die Sie zusammen mit dem Kennwort an eine Hash-Funktion übergeben. Es wird hauptsächlich verwendet, um das Programm vor Wörterbuchangriffen und Regenbogentabellenangriffen zu schützen und identische Passwörter zu verschleiern. Mehr hier: Salz (Kryptographie) .

In dieser Funktion wird die übergebene Zeichenfolge direkt nach der Eingabe überschrieben. Das Ignorieren des an die Funktion übergebenen Werts ist eine potenzielle Sicherheitsanfälligkeit.

Warnung 2

Diese Funktion löste zwei Warnungen gleichzeitig aus:

  • V6023 Der Parameter 'offsetWidth' wird vor seiner Verwendung immer im Methodenkörper neu geschrieben. CubaSuggestionFieldWidget.java (433)
  • V6023 Der Parameter 'offsetHeight' wird vor seiner Verwendung immer im Methodenkörper neu geschrieben. CubaSuggestionFieldWidget.java (433)

 @Override public void setPosition(int offsetWidth, int offsetHeight) { offsetHeight = getOffsetHeight(); .... if (offsetHeight + getPopupTop() > ....)) { .... } .... offsetWidth = containerFirstChild.getOffsetWidth(); if (offsetWidth + getPopupLeft() > ....)) { .... } else { left = getPopupLeft(); } setPopupPosition(left, top); } 

Das ist ein merkwürdiger Ausschnitt. Die Funktion wird mit nur zwei Variablen als Argumente aufgerufen , offsetWidth und offsetHeight . Beide werden vor der Verwendung überschrieben.

Warnung 3

V6022 Der Parameter 'Verknüpfung' wird im Konstruktorkörper nicht verwendet. DeclarativeTrackingAction.java (47)

 public DeclarativeTrackingAction(String id, String caption, String description, String icon, String enable, String visible, String methodName, @Nullable String shortcut, ActionsHolder holder) { super(id); this.caption = caption; this.description = description; this.icon = icon; setEnabled(enable == null || Boolean.parseBoolean(enable)); setVisible(visible == null || Boolean.parseBoolean(visible)); this.methodName = methodName; checkActionsHolder(holder); } 

Die Funktion verwendet den als Verknüpfungsparameter übergebenen Wert nicht. Möglicherweise ist die Benutzeroberfläche der Funktion veraltet, oder diese Warnung ist nur falsch positiv.

Noch ein paar Mängel dieses Typs:

  • V6022 Der Parameter 'type' wird im Konstruktorkörper nicht verwendet. QueryNode.java (36)
  • V6022 Der Parameter 'text2' wird im Konstruktorkörper nicht verwendet. MarkerAddition.java (22)
  • V6022 Der Parameter 'Auswahl' wird im Konstruktorkörper nicht verwendet. AceEditor.java (114)
  • V6022 Der Parameter 'options' wird im Konstruktorkörper nicht verwendet. EntitySerialization.java (379)

Unterschiedliche Funktionen, gleicher Code


Warnung 1

V6032 Es ist seltsam, dass der Hauptteil der Methode 'firstItemId' dem Hauptteil einer anderen Methode 'lastItemId' vollständig entspricht. ContainerTableItems.java (213), ContainerTableItems.java (219)
 @Override public Object firstItemId() { List<E> items = container.getItems(); return items.isEmpty() ? null : items.get(0).getId(); } @Override public Object lastItemId() { List<E> items = container.getItems(); return items.isEmpty() ? null : items.get(0).getId(); } 

Die Funktionen firstItemId und lastItemId haben die gleichen Implementierungen. Letzteres sollte wahrscheinlich den Index des letzten Elements abrufen, anstatt das Element auf Index 0 abzurufen.

Warnung 2

V6032 Es ist seltsam, dass der Hauptteil der Methode dem Körper einer anderen Methode vollständig entspricht. SearchComboBoxPainter.java (495), SearchComboBoxPainter.java (501)

 private void paintBackgroundDisabledAndEditable(Graphics2D g) { rect = decodeRect1(); g.setPaint(color53); g.fill(rect); } private void paintBackgroundEnabledAndEditable(Graphics2D g) { rect = decodeRect1(); g.setPaint(color53); g.fill(rect); } 

Zwei weitere Funktionen mit verdächtig identischen Körpern. Ich vermute, dass einer von ihnen mit einer anderen Farbe anstelle von color53 arbeiten sollte .

Null-Dereferenzierung


Warnung 1

V6060 Die Referenz 'descriptionPopup' wurde verwendet, bevor sie gegen null verifiziert wurde. SuggestPopup.java (252), SuggestPopup.java (251)

 protected void updateDescriptionPopupPosition() { int x = getAbsoluteLeft() + WIDTH; int y = getAbsoluteTop(); descriptionPopup.setPopupPosition(x, y); if (descriptionPopup!=null) { descriptionPopup.setPopupPosition(x, y); } } 

In nur zwei Zeilen gelang es dem Programmierer, einen höchst verdächtigen Code zu schreiben. Zuerst wird die Methode setPopupPosition der ObjektbeschreibungPopup aufgerufen, und dann wird das Objekt auf null geprüft. Der erste Aufruf von setPopupPosition ist wahrscheinlich redundant und möglicherweise gefährlich. Ich denke, es resultiert aus schlechtem Refactoring.

Warnung 2

V6060 Die 'tableModel'-Referenz wurde verwendet, bevor sie gegen null verifiziert wurde. DesktopAbstractTable.java (1580), DesktopAbstractTable.java (1564)

 protected Column addRuntimeGeneratedColumn(String columnId) { // store old cell editors / renderers TableCellEditor[] cellEditors = new TableCellEditor[tableModel.getColumnCount() + 1]; // <= TableCellRenderer[] cellRenderers = new TableCellRenderer[tableModel.getColumnCount() + 1]; // <= for (int i = 0; i < tableModel.getColumnCount(); i++) { // <= Column tableModelColumn = tableModel.getColumn(i); if (tableModel.isGeneratedColumn(tableModelColumn)) { // <= TableColumn tableColumn = getColumn(tableModelColumn); cellEditors[i] = tableColumn.getCellEditor(); cellRenderers[i] = tableColumn.getCellRenderer(); } } Column col = new Column(columnId, columnId); col.setEditable(false); columns.put(col.getId(), col); if (tableModel != null) { // <= tableModel.addColumn(col); } .... } 

Dieser Fall ähnelt dem vorherigen. Zu dem Zeitpunkt, an dem das tableModel- Objekt auf null geprüft wird, wurde bereits mehrmals darauf zugegriffen.

Ein weiteres Beispiel:

  • V6060 Die 'tableModel'-Referenz wurde verwendet, bevor sie gegen null verifiziert wurde. DesktopAbstractTable.java (596), DesktopAbstractTable.java (579)

Wahrscheinlich ein logischer Fehler


V6026 Dieser Wert ist bereits der Variablen 'sortAscending' zugeordnet. CubaScrollTableWidget.java (488)

 @Override protected void sortColumn() { .... if (sortAscending) { if (sortClickCounter < 2) { // special case for initial revert sorting instead of reset sort order if (sortClickCounter == 0) { client.updateVariable(paintableId, "sortascending", false, false); } else { reloadDataFromServer = false; sortClickCounter = 0; sortColumn = null; sortAscending = true; // <= client.updateVariable(paintableId, "resetsortorder", "", true); } } else { client.updateVariable(paintableId, "sortascending", false, false); } } else { if (sortClickCounter < 2) { // special case for initial revert sorting instead of reset sort order if (sortClickCounter == 0) { client.updateVariable(paintableId, "sortascending", true, false); } else { reloadDataFromServer = false; sortClickCounter = 0; sortColumn = null; sortAscending = true; client.updateVariable(paintableId, "resetsortorder", "", true); } } else { reloadDataFromServer = false; sortClickCounter = 0; sortColumn = null; sortAscending = true; client.updateVariable(paintableId, "resetsortorder", "", true); } } .... } 

In der ersten Bedingung wurde der Variablen sortAscending bereits der Wert true zugewiesen, aber später wird ihr wieder derselbe Wert zugewiesen. Dies muss ein Fehler sein, und der Autor meinte wahrscheinlich den Wert falsch .

Ein ähnliches Beispiel aus einer anderen Datei:

  • V6026 Dieser Wert ist bereits der Variablen 'sortAscending' zugeordnet. CubaTreeTableWidget.java (444)

Seltsame Rückgabewerte


Warnung 1

V6037 Eine bedingungslose 'Rückkehr' innerhalb einer Schleife. QueryCacheManager.java (128)

 public <T> T getSingleResultFromCache(QueryKey queryKey, List<View> views) { .... for (Object id : queryResult.getResult()) { return (T) em.find(metaClass.getJavaClass(), id, views.toArray(....)); } .... } 

Der Analysator hat einen bedingungslosen Aufruf zur Rückkehr bei der ersten Iteration einer for- Schleife erkannt. Entweder ist diese Zeile falsch oder die Schleife sollte als if- Anweisung neu geschrieben werden.

Warnung 2

V6014 Es ist seltsam, dass diese Methode immer ein und denselben Wert zurückgibt. DefaultExceptionHandler.java (40)

 @Override public boolean handle(ErrorEvent event, App app) { Throwable t = event.getThrowable(); if (t instanceof SocketException || ExceptionUtils.getRootCause(t) instanceof SocketException) { return true; } if (ExceptionUtils.getThrowableList(t).stream() .anyMatch(o -> o.getClass().getName().equals("...."))) { return true; } if (StringUtils.contains(ExceptionUtils.getMessage(t), "....")) { return true; } AppUI ui = AppUI.getCurrent(); if (ui == null) { return true; } if (t != null) { if (app.getConnection().getSession() != null) { showDialog(app, t); } else { showNotification(app, t); } } return true; } 

Diese Funktion gibt jeweils true zurück, während die letzte Zeile offensichtlich false fordert. Es sieht aus wie ein Fehler.

Hier ist eine vollständige Liste anderer ähnlicher verdächtiger Funktionen:

  • V6014 Es ist seltsam, dass diese Methode immer ein und denselben Wert zurückgibt. ErrorNodesFinder.java (31)
  • V6014 Es ist seltsam, dass diese Methode immer ein und denselben Wert zurückgibt. FileDownloadController.java (69)
  • V6014 Es ist seltsam, dass diese Methode immer ein und denselben Wert zurückgibt. IdVarSelector.java (73)
  • V6014 Es ist seltsam, dass diese Methode immer ein und denselben Wert zurückgibt. IdVarSelector.java (48)
  • V6014 Es ist seltsam, dass diese Methode immer ein und denselben Wert zurückgibt. IdVarSelector.java (67)
  • V6014 Es ist seltsam, dass diese Methode immer ein und denselben Wert zurückgibt. IdVarSelector.java (46)
  • V6014 Es ist seltsam, dass diese Methode immer ein und denselben Wert zurückgibt. JoinVariableNode.java (57)

Warnung 3

V6007 Der Ausdruck 'needReload' ist immer falsch. WebAbstractTable.java (2702)

 protected boolean handleSpecificVariables(Map<String, Object> variables) { boolean needReload = false; if (isUsePresentations() && presentations != null) { Presentations p = getPresentations(); if (p.getCurrent() != null && p.isAutoSave(p.getCurrent()) && needUpdatePresentation(variables)) { Element e = p.getSettings(p.getCurrent()); saveSettings(e); p.setSettings(p.getCurrent(), e); } } return needReload; } 

Die Funktion gibt die Variable needReload zurück , deren Wert immer falsch ist . In einer der Bedingungen fehlt wahrscheinlich ein Code zum Ändern dieses Werts.

Warnung 4

V6062 Mögliche unendliche Rekursion innerhalb der 'isFocused'-Methode. GwtAceEditor.java (189), GwtAceEditor.java (190)

 public final native void focus() /*-{ this.focus(); }-*/; public final boolean isFocused() { return this.isFocused(); } 

Der Analysator hat eine rekursive Funktion ohne Stoppbedingung erkannt. Diese Datei enthält viele Funktionen, die mit dem Schlüsselwort native gekennzeichnet sind und auskommentierten Code enthalten. Die Entwickler schreiben diese Datei wahrscheinlich gerade neu und werden bald auch die Funktion isFocused bemerken.

Verschiedenes


Warnung 1

V6002 Die switch-Anweisung deckt nicht alle Werte der Enum 'Operation' ab: ADD. DesktopAbstractTable.java (665)

 /** * Operation which caused the datasource change. */ enum Operation { REFRESH, CLEAR, ADD, REMOVE, UPDATE } @Override public void setDatasource(final CollectionDatasource datasource) { .... collectionChangeListener = e -> { switch (e.getOperation()) { case CLEAR: case REFRESH: fieldDatasources.clear(); break; case UPDATE: case REMOVE: for (Object entity : e.getItems()) { fieldDatasources.remove(entity); } break; } }; .... } 

Die switch- Anweisung hat keine Groß- / Kleinschreibung für den Wert ADD . Dies ist der einzige Wert, der nicht überprüft wird. Daher sollten sich die Entwickler diesen Code ansehen.

Warnung 2

V6021 Variable 'Quelle' wird nicht verwendet. DefaultHorizontalLayoutDropHandler.java (177)

 @Override protected void handleHTML5Drop(DragAndDropEvent event) { LayoutBoundTransferable transferable = (LayoutBoundTransferable) event .getTransferable(); HorizontalLayoutTargetDetails details = (HorizontalLayoutTargetDetails) event .getTargetDetails(); AbstractOrderedLayout layout = (AbstractOrderedLayout) details .getTarget(); Component source = event.getTransferable().getSourceComponent(); // <= int idx = (details).getOverIndex(); HorizontalDropLocation loc = (details).getDropLocation(); if (loc == HorizontalDropLocation.CENTER || loc == HorizontalDropLocation.RIGHT) { idx++; } Component comp = resolveComponentFromHTML5Drop(event); if (idx >= 0) { layout.addComponent(comp, idx); } else { layout.addComponent(comp); } if (dropAlignment != null) { layout.setComponentAlignment(comp, dropAlignment); } } 

Die Variablenquelle wird deklariert, aber nicht verwendet. Vielleicht haben die Autoren vergessen, dem Layout eine Quelle hinzuzufügen, genau wie bei einer anderen Variablen dieses Typs, comp .

Andere Funktionen mit nicht verwendeten Variablen:

  • V6021 Variable 'Quelle' wird nicht verwendet. DefaultHorizontalLayoutDropHandler.java (175)
  • V6021 Der Wert wird der Variablen 'r' zugewiesen, aber nicht verwendet. ExcelExporter.java (262)
  • V6021 Variable 'over' wird nicht verwendet. DefaultCssLayoutDropHandler.java (49)
  • V6021 Variable 'übertragbar' wird nicht verwendet. DefaultHorizontalLayoutDropHandler.java (171)
  • V6021 Variable 'übertragbar' wird nicht verwendet. DefaultHorizontalLayoutDropHandler.java (169)
  • V6021 Die Variable 'beanLocator' wird nicht verwendet. ScreenEventMixin.java (28)

Warnung 3

V6054 Klassen sollten nicht mit ihrem Namen verglichen werden. MessageTools.java (283)

 public boolean hasPropertyCaption(MetaProperty property) { Class<?> declaringClass = property.getDeclaringClass(); if (declaringClass == null) return false; String caption = getPropertyCaption(property); int i = caption.indexOf('.'); if (i > 0 && declaringClass.getSimpleName().equals(caption.substring(0, i))) return false; else return true; } 

Der Analysator hat einen Klassenvergleich mit Namen festgestellt. Es ist falsch, Klassen nach Namen zu vergleichen, da die Namen von JVM-Klassen gemäß der Spezifikation nur innerhalb eines Pakets eindeutig sein dürfen. Ein solcher Vergleich führt zu falschen Ergebnissen und zur Ausführung des falschen Codes.

Kommentar von CUBA Platform-Entwicklern


Jedes große Projekt hat sicherlich Fehler. In diesem Wissen sind wir uns gerne einig, als das PVS-Studio-Team angeboten hat, unser Projekt zu überprüfen. Das CUBA-Repository enthält Gabeln einiger OSS-Bibliotheken von Drittanbietern, die unter Apache 2 lizenziert sind, und es sieht so aus, als sollten wir diesem Code mehr Aufmerksamkeit schenken, da der Analysator in diesen Quellen eine Reihe von Problemen festgestellt hat. Wir verwenden derzeit SpotBugs als primären Analysator, und einige der von PVS-Studio gemeldeten großen Fehler werden nicht bemerkt. Es scheint, wir sollten selbst einige zusätzliche Diagnosen schreiben. Vielen Dank an das PVS-Studio Team für den Job.

Die Entwickler sagten uns auch, dass die Warnungen V6013 und V6054 falsch positiv waren; Es war ihre bewusste Entscheidung, diesen Code so zu schreiben, wie sie es taten. Der Analysator wurde zum Erkennen verdächtiger Codefragmente entwickelt, und die Wahrscheinlichkeit, echte Fehler zu finden, variiert je nach Diagnose. Solche Warnungen können jedoch mithilfe des speziellen Mechanismus zur Unterdrückung von Massenwarnungen problemlos verarbeitet werden, ohne dass die Quelldateien geändert werden müssen.

Außerdem kann das PVS-Studio-Team den Satz "Es scheint, wir sollten selbst zusätzliche Diagnosen schreiben" nicht zur Kenntnis nehmen und auf dieses Bild verzichten :)

Bild 3

Fazit


PVS-Studio kann eine perfekte Ergänzung zu vorhandenen Qualitätskontrollwerkzeugen sein, die in Ihrem Entwicklungsprozess verwendet werden. Dies gilt insbesondere für Unternehmen mit Dutzenden, Hunderten oder Tausenden von Entwicklern. PVS-Studio wurde entwickelt, um Fehler nicht nur zu erkennen, sondern Ihnen auch bei der Behebung zu helfen. Damit meine ich nicht die automatische Codebearbeitung, sondern zuverlässige Mittel zur Kontrolle der Codequalität. In einem großen Unternehmen ist es nicht für jeden Entwickler möglich, die jeweiligen Teile des Codes mit verschiedenen Tools zu überprüfen. Eine bessere Lösung für solche Unternehmen wäre daher die Verwendung von Tools wie PVS-Studio, die in jeder Entwicklungsphase eine Kontrolle der Codequalität ermöglichen nur auf der Programmierseite.

Source: https://habr.com/ru/post/de449020/


All Articles