How PVS-Studio ELKI was checked in January

If it seems to you that the New Year came only yesterday, and you did not notice how much more than half of January has passed, then all this time you have been busy looking for subtle bugs in the code you maintain. It also means that our article is for you. We, PVS-Studio, checked the ELKI open source project to show you what errors can be found in the code, how cleverly they can hide there, and how you can deal with it.







0111_ELKI_ru / image1.png







ELKI - what is this library?



ELKI Environment for Developing KDD-Applications Supported by Index-Structures. Java . – , , -. , . . .







, , , , . , ELKI, . , . , .







AGPL , , . . . .









ELKI 2 630 java, 186 444 , . open source .







. , . ! 10 , , , .









V6001 There are identical sub-expressions 'bounds[j + 1]' to the left and to the right of the '!=' operator. CLIQUEUnit.java(252)







private boolean checkDimensions(CLIQUEUnit other, int e) {
    for(int i = 0, j = 0; i < e; i++, j += 2) {
        if (dims[i] != other.dims[i]
            || bounds[j] != other.bounds[j]
            || bounds[j + 1] != bounds[j + 1]) {
          return false;
        }
    }
    return true;
}
      
      





if checkDimensions bounds[j + 1] . , , . checkDimensions true , .







if :







bounds[j + 1] != other.bounds[j + 1]
      
      







V6022 Parameter 'updates' is not used inside constructor body. DataStoreEvent.java(60)







V6022 Parameter 'removals' is not used inside constructor body. DataStoreEvent.java(60)







public DataStoreEvent(DBIDs inserts, DBIDs removals, DBIDs updates) {
    super();
    this.inserts = inserts;
    this.removals = inserts;
    this.updates = inserts;
}
      
      





. DataStoreEvent , . , , , .







, DataStoreEvent , , .







public static DataStoreEvent insertionEvent(DBIDs inserts) {
  return new DataStoreEvent(inserts, DBIDUtil.EMPTYDBIDS, DBIDUtil.EMPTYDBIDS);
}

public static DataStoreEvent removalEvent(DBIDs removals) {
  return new DataStoreEvent(DBIDUtil.EMPTYDBIDS, removals, DBIDUtil.EMPTYDBIDS);
}

public static DataStoreEvent updateEvent(DBIDs updates) {
  return new DataStoreEvent(DBIDUtil.EMPTYDBIDS, DBIDUtil.EMPTYDBIDS, updates);
}
      
      





- .







:







this.inserts = inserts;
this.removals = removals;
this.updates = updates;
      
      







V6012 The '?:' operator, regardless of its conditional expression, always returns one and the same value '0.5'. ClusterHullVisualization.java(173), ClusterHullVisualization.java(173)







public void fullRedraw() {
    ....
    boolean flat = (clusters.size() == topc.size());
    // Heuristic value for transparency:
    double baseopacity = flat ? 0.5 : 0.5;
    ....
}
      
      





baseopacity 0.5 , flat. , , - .







. , , . , 90 – . , .









V6025 Index '1' is out of bounds. GeneratorStatic.java(104)







@Override
public double[] computeMean() {
    // Not supported except for singletons.
    return points.size() == 1 ? points.get(1) : null;
}
      
      





computeMean , points , , , … 1. , IndexOutOfBoundsException .







:







return points.size() == 1 ? points.get(0) : null;
      
      





?



V6020 Divide by zero. The range of the 'referenceSetSize' denominator values includes zero. PreDeConNeighborPredicate.java(138)







protected PreDeConModel computeLocalModel(DoubleDBIDList neighbors, ....) {
    final int referenceSetSize = neighbors.size();
    ....
    // Shouldn't happen:
    if(referenceSetSize < 0) {
        LOG.warning("Empty reference set – 
            should at least include the query point!");
        return new PreDeConModel(Integer.MAX_VALUE, DBIDUtil.EMPTYDBIDS);
    }
    ....
    for(int d = 0; d < dim; d++) {
        s[d] /= referenceSetSize;
        mvVar.put(s[d]);
    }
    ....
}
      
      





, . . . .







neighbors, computeLocalModel. neighbors if, , . .. referenceSetSize < 0 , set – . , referenceSetSize == 0.







neighbors, for . , .









V6062 Possible infinite recursion inside the 'setInitialMeans' method. Predefined.java(65), Predefined.java(66)







public void setInitialMeans(List<double[]> initialMeans) {
    this.setInitialMeans(initialMeans);
}
      
      





. , . , - :







this.setInitialMeans(initialMeans.toArray(new double[0][0]));
      
      





, , , , - . , , :







public void setInitialMeans(double[][] initialMeans) {
    double[][] vecs = initialMeans.clone(); // TODO: deep copy?
    this.initialMeans = vecs;
}
      
      







V6094 The expression was implicitly cast from 'int' type to 'double' type. Consider utilizing an explicit type cast to avoid the loss of a fractional part. An example: double A = (double)(X) / Y;. ProbabilityWeightedMoments.java(130)







public static <A> double[] alphaBetaPWM(...., final int nmom) {
    final int n = adapter.size(data);
    final double[] xmom = new double[nmom << 1];
    double aweight = 1. / n, bweight = aweight;
    for(int i = 0; i < n; i++) {
        ....
        for(int j = 1, k = 2; j < nmom; j++, k += 2) {
            xmom[k + 1] += val * (aweight *= (n - i - j + 1) / (n - j + 1));
            xmom[k + 1] += val * (bweight *= (i - j + 1) / (n - j + 1));
        }
    }
    return xmom;
}
      
      





for (n — i — j + 1) / (n — j + 1) int double. : , . , , , xmom double. , , (n – i – j + 1) / (n – j + 1). , n – j + 1 x. : (x – i) / x. 0 , . . . n , , .







, , double:







xmom[k + 1] += val * (aweight *= (double) (n - i - j + 1) / (n - j + 1));
xmom[k + 1] += val * (bweight *= (double) (i - j + 1) / (n - j + 1));
      
      







V6079 Value of the 'splitpoint' variable is checked after use. Potential logical error is present. KernelDensityFittingTest.java(97), KernelDensityFittingTest.java(97)







public final void testFitDoubleArray() throws IOException {
    ....
    int splitpoint = 0;
    while(fulldata[splitpoint] < splitval && splitpoint < fulldata.length) {
        splitpoint++;
    }
    ....
}
      
      





while fulldata splitpoint splitval, , splitpoint , . while , .









V6019 Unreachable code detected. It is possible that an error is present. Tokenizer.java(172)







V6007 Expression 'c != '\n'' is always true. Tokenizer.java(169)







public String getStrippedSubstring() {
    int sstart = start, ssend = end;
    while(sstart < ssend) {
        char c = input.charAt(sstart);
        if(c != ' ' || c != '\n' || c != '\r' || c != '\t') {
            break;
        }
        ++sstart;
    }
    ....
}
      
      





, . V6019 : ++sstart, V6007 if, .







if ? . : c != ' ', c != '\n', c != '\r', c != '\t'. - . false, true, - || () if . ifbreak, while, sstart . V6019 .







, - :







if(c != ' ' && c != '\n' && c != '\r' && c != '\t')
      
      





,



V6009 Function 'equals' receives an odd argument. An object 'other.similarityFunction' is used as an argument to its own method. AbstractSimilarityAdapter.java(91)







@Override
public boolean equals(Object obj) {
    if(obj == null) {
        return false;
    }

    if(!this.getClass().equals(obj.getClass())) {
        return false;
    }

    AbstractSimilarityAdapter<?> other = (AbstractSimilarityAdapter<?>) obj;
    return other.similarityFunction.equals(other.similarityFunction);
}
      
      





equals AbstractSimilarityAdapter. , , , equals . , , equals . .







:







return this.similarityFunction.equals(other.similarityFunction);
      
      





, , Java. ' '. , , , .









, . — , – . – , . – , . , .







– . , review , unit . , , .









, , , . . , ?







, , . , , , , . , . . , .







, , , :







  1. Trans-Proteomic Pipeline (TPP).
  2. - .
  3. ?
  4. ROOT — .
  5. NCBI Genome Workbench: .



All Articles