Stacktrace Question - StringIndexOutOfBoundsException

edited May 2018 in Library Questions

Hi All-

I'm trying to troubleshoot a bug that's been eluding me for a while now. Below is the first few lines of the stacktrace that is returned when it pops up. Does anyone know what "1967" refers to in the second line.

java.lang.StringIndexOutOfBoundsException: String index out of range: -1 at java.lang.String.substring(String.java:1967) at controlP5.ControlFont.calculateHeight(Unknown Source) at controlP5.ControlFont.adjust(Unknown Source) at controlP5.Label$MultilineLabel.draw(Unknown Source)

Tagged:

Answers

  • Look at your code

    Which line is causing this? Almost certainly the substring command. The string used or one of the parameters is -1 and not allowed to be used with substring

  • Show your code

  • Thanks Chrisir. I've already figured that out. Unfortunately it isn't realistic to post my code. I have thousands of lines and multiple threads. I'm also using several libraries and I'm interacting with an Arduino over serial and hundreds of text files. Nobody would be able to duplicate the error with just the code. I've been injecting println commands into the code to try to figure out where the problem is happening but as of yet I haven't been able to pinpoint it. What I was trying to figure out with this question is how to decipher some of the stack trace codes. Specifically, what does 1967 refer to?

  • Just post the line that caused the error

  • edited May 2018

    java.lang.String.substring(String.java:1967)

    Maybe it refers to the line number of Java's String::substring() method's source code. :-/

  • But the real error is the -1 being used as an index, which is obviously rubbish. Are you calling indexOf without checking the result?

  • In other words, the problem is in YOUR code.

  • (which is good, because that means we can fix it)

  • Are you calling indexOf() without checking the result?

    @koogs, according to the stack trace, it is the controlP5.ControlFont which is invoking String::substring(). :-B

    @typ0 has also mentioned he's doing threads: L-)

    I have thousands of lines and multiple threads.

  • So he is feeding Label$MultilineLabel the wrong parameters maybe use min(20, ......) ?

  • Hi All-

    Thanks for the responses. Ive made some progress on this.

    I developed a gui using controlP5. One of the components in the gui is a text area which I'm using as a console. I have it set up as follows:

    Output=controlP5.addTextarea("Output") //Make a textarea for the console
      .setPosition(360, 110)
        .setSize(330, 440)
          .setLineHeight(14)
            .setColorBackground(color(255,100))
              .setColorForeground(color(255,100))
                .scroll(1)
                  .hideScrollbar();
    

    I then created a function to post messages to the console and allow it to scroll:

    void displayln(String txt)
    {
      println(txt);
      s += (txt + "\n");
      if (s.length() > 2000)
      {
        s = s.substring(1000);
      }
      Output.setText(s);
    }
    

    The console is then updated every loop through draw(). I researched ways to use a system.out with controlP5 but I don't think its possible. This was what I came up with instead. It works except for the occasional random exception noted in my first post. Sometimes it will run for hours with many thousands of messages having scrolled through the console before receiving the exception. Sometimes it happens fairly quickly after starting. Yesterday I discovered if I comment out everything except println(txt); in the displayln function the issue never comes up. However, I've added println messages before and after the s=s.substring(1000) line and this doesn't appear to be the problem. What I'm thinking now is that, as @GoToLoop mentioned, controlP5 is using the substring method during the draw() function. Any thoughts?

  • Forgot to mention....the messages being sent to the console are coming from the second thread. I'm using two threads to avoid a stale gui during nested loops that take hours to finish.

  • www.sojamo.de/libraries/controlP5/examples/extra/ControlP5console/ControlP5console.pde

    I get the same thing running this example when I enter 'case 3'

  • The controlP5 console example worked perfectly for me. It is extremely unlikely that the problem is due to a bug in controlP5 because it is a very popular libray used by thousands and someone is likely to have experienced it before.

    In the method displayln(...) is the variable s being shared by both threads?

    If it is then that could be your problem - s is being changed between testing its length and calling substring(...)

  • Note substr(int beginIndex) return a StringIndexOutOfBoundsException if

    a) beginIndex < 0 or
    b) beginIndex > the string length

    The numeric value reported in the eception is length - beginIndex

  • @quark looks like this is a bug in controlP5. I found the following on the GitHub issues page for the project:

    https://github.com/sojamo/controlp5/issues/9

    I also modified the example as follows and was able to determine that the exception is thrown on draw(). What's strange is that it doesn't always happen right away after setMax is set. On one try I made it through draw() 21 times before the exception was thrown. Sometimes it is thrown the first time through.

    import controlP5.*;
    
    ControlP5 cp5;
    
    Textarea myTextarea;
    
    int c = 0;
    boolean case3 = false;
    int count = 0;
    
    Println console;
    
    void setup() {
      size(700, 400);
      cp5 = new ControlP5(this);
      cp5.enableShortcuts();
      frameRate(50);
      myTextarea = cp5.addTextarea("txt")
                      .setPosition(100, 100)
                      .setSize(200, 200)
                      .setFont(createFont("", 10))
                      .setLineHeight(14)
                      .setColor(color(200))
                      .setColorBackground(color(0, 100))
                      .setColorForeground(color(255, 100));
      ;
    
      console = cp5.addConsole(myTextarea);//
    }
    
    
    void draw() {
      println("Point 1");
      if (case3)
      {
        count += 1;
        println("Made it to loop #: " + count);
      }
      println("Point 2");
      background(128);
      noStroke();
      ellipseMode(CENTER);
      float n = sin(frameCount*0.01)*300;
      fill(110, 255,220);  
      ellipse(width/2, height/2, n , n);
    
      println(frameCount+"\t"+String.format("%.2f", frameRate)+"\t"+String.format("%.2f", n));
      println("Point 3");
    }
    
    void keyPressed() {
      switch(key) {
        case('1'):
        console.pause();
        break;
        case('2'):
        console.play();
        break;
        case('3'):
        console.setMax(8);
        case3 = true;
        break;
        case('4'):
        console.setMax(-1);
        break;
        case('5'):
        console.clear();
        break;
      }
    }
    

    The exception and behavior are consistent with what I am seeing in my project...although I'm not using the setMax() method.

  • My mistake it looks like a bug in controlP5. I should have looked at the stacktrace more closely.

  • I have looked at the controlP5 source code and can confirm there is a possible bug in the ControlFont class, the calculateHeight(...) method.

    Theoretically this method can throw a StringIndexOutOfBoundsException under certain circumstances but looking at the source code it is difficult to see how these circumstances might arise.

    Are you using controlP5'sPrintln class in your program?

  • I am using a function that I wrote to update the text area:

    void displayln(String txt)
    {
      println(txt);
      s += (txt + "\n");
      if (s.length() > 2000)
      {
        s = s.substring(1000);
      }
      Output.setText(s);
    }
    

    If I comment out everything except the println(txt) line the exception never happens. I have also verified that it isn't the call to substring in my function that generates the exception. Here is the exception I get:

    java.lang.StringIndexOutOfBoundsException: String index out of range: -1
        at java.lang.String.substring(String.java:1967)
        at controlP5.ControlFont.calculateHeight(Unknown Source)
        at controlP5.ControlFont.adjust(Unknown Source)
        at controlP5.Label$MultilineLabel.draw(Unknown Source)
        at controlP5.Label.draw(Unknown Source)
        at controlP5.ControllerGroup.draw(Unknown Source)
        at controlP5.ControllerGroup.drawControllers(Unknown Source)
        at controlP5.ControllerGroup.draw(Unknown Source)
        at controlP5.ControlWindow.draw(Unknown Source)
        at controlP5.ControlWindow.draw(Unknown Source)
        at sun.reflect.GeneratedMethodAccessor3.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at processing.core.PApplet$RegisteredMethods.handle(PApplet.java:1427)
        at processing.core.PApplet$RegisteredMethods.handle(PApplet.java:1420)
        at processing.core.PApplet.handleMethods(PApplet.java:1614)
        at processing.core.PApplet.handleDraw(PApplet.java:2450)
        at processing.awt.PSurfaceAWT$12.callDraw(PSurfaceAWT.java:1557)
        at processing.core.PSurfaceNone$AnimationThread.run(PSurfaceNone.java:316)
    

    I also tried using the technique in the console example instead of my displayln function and I get the same exception.

  • edited May 2018

    I take that to mean you are not using the Println class from controlP5.

    Are you calling displayln(String txt) from a secondary thread?

  • Correct..I'm not using Println in my project. I am calling displayln(String txt) from my second thread. I call a second thread to allow my gui to continue to update (including the text area that I'm using as a console).

  • OK I suspect that the problem is that the calculateHeight method which is being called in the main GUI thread is being interrupted by the second thread excuting the displayln method.

    In your displayln method comment out the last line only and try that i.e.

    void displayln(String txt)
    {
      println(txt);
      s += (txt + "\n");
      if (s.length() > 2000)
      {
        s = s.substring(1000);
      }
      // Output.setText(s);
    }
    
  • thanks @quark..I tried that and I don't get the exception. I'm not set on using my displayln function. I tried to use the same technique as in the console example which uses the Println class. This generated the same exception. I guess its similar though since with this technique I am calling println from the second thread. Is there a better way to create a console which can receive messages from a second thread?

  • On second thought, I'm questioning if using a second thread is the problem. the console example is a single thread and the same exception is generated. When I comment out the Output.setText(s) line in my code the textarea just stays blank. Perhaps the issue is more related to what is being displayed in the textarea/console?

  • The console example is not single threaded!

    The Println class creates a runnable thread that redirects the System.out.println() to a buffer which is then read and appended to the Textarea control.

  • Perhaps the issue is more related to what is being displayed in the textarea/console?

    As I said before I examined the source code and although theoretically possible iI can see the circumstances that would cause the code to generate the exception.

Sign In or Register to comment.