Need help finding the cause of a hang-up

Discussion in 'Plugin Development' started by Njol, Nov 12, 2012.

Thread Status:
Not open for further replies.
  1. Offline

    Njol

    Hello,
    Thank you for visiting my thread. Today's special is a hang-up in my code, served with a few headaches =P
    </joke>
    I have been trying to find the cause of a hang-up for like two weeks now (I have mostly been doing other stuff but my plugin doesn't run with this error and it prevents me from testing anything =P)

    Skript, my plugin, hangs up while parsing the following lines of my testing scripts:
    Code:
    grow tree of type argument 1 at block above targeted block
    loop-block is air, dirt, stone, grass, any plant or soil
    blocks north above, east above, south above and west above are allowed next to cactus
    player is holding iron hoe or diamond hoe
    
    Even though the full code of my plugin is huge I think that it's not important to know the full code to solve this issue as I strongly guess that it's the change in one method that's causing this but I have not been able to find any infinite loop there. I would really appreciate even a quick glance at my code as sometimes I'm retarded and miss stupid mistakes =P
    I would alse appreciate any generel advice on bugfixing in such cases, e.g. how to use a debugger as I've never used one in my life (Eclipse's in particular).

    Now some information in case anyone want to take a look at my code:
    This is the file causing the problems: https://github.com/Njol/Skript/blob/dev/src/main/java/ch/njol/skript/lang/SkriptParser.java#L247
    Everything worked perfectly until after I implemented expression lists (like 'x, y, and/or z'), i.e. used parseExpression instead of parseSingleExpr (it was a bit different but that was the main change).
    And this is a typical stack trace during the hang-up (it doesn't lead to a StackOverflowError, at least not within a reasonable time):
    Code:
        at ch.njol.skript.lang.SkriptParser.parse(SkriptParser.java:176)
        at ch.njol.skript.lang.SkriptParser.parse(SkriptParser.java:142)
        at ch.njol.skript.lang.SkriptParser.parseSingleExpr(SkriptParser.java:392)
        at ch.njol.skript.lang.SkriptParser.parseExpression(SkriptParser.java:252)
        at ch.njol.skript.lang.SkriptParser.parseExpression(SkriptParser.java:243)
        at ch.njol.skript.lang.SkriptParser.parse_i(SkriptParser.java:759)
        at ch.njol.skript.lang.SkriptParser.parse_i(SkriptParser.java:753)
        at ch.njol.skript.lang.SkriptParser.parse(SkriptParser.java:176)
        at ch.njol.skript.lang.SkriptParser.parse(SkriptParser.java:142)
        at ch.njol.skript.lang.SkriptParser.parseSingleExpr(SkriptParser.java:392)
        at ch.njol.skript.lang.SkriptParser.parseExpression(SkriptParser.java:252)
        at ch.njol.skript.lang.SkriptParser.parseExpression(SkriptParser.java:243)
        at ch.njol.skript.lang.SkriptParser.parse_i(SkriptParser.java:759)
        at ch.njol.skript.lang.SkriptParser.parse_i(SkriptParser.java:753)
        at ch.njol.skript.lang.SkriptParser.parse(SkriptParser.java:176)
        at ch.njol.skript.lang.SkriptParser.parse(SkriptParser.java:142)
        at ch.njol.skript.lang.SkriptParser.parseSingleExpr(SkriptParser.java:392)
        at ch.njol.skript.lang.SkriptParser.parseExpression(SkriptParser.java:269)
        at ch.njol.skript.lang.SkriptParser.parseExpression(SkriptParser.java:243)
        at ch.njol.skript.lang.SkriptParser.parse_i(SkriptParser.java:759)
        at ch.njol.skript.lang.SkriptParser.parse_i(SkriptParser.java:753)
        at ch.njol.skript.lang.SkriptParser.parse(SkriptParser.java:176)
        at ch.njol.skript.lang.SkriptParser.parse(SkriptParser.java:142)
        at ch.njol.skript.lang.SkriptParser.parseSingleExpr(SkriptParser.java:392)
        at ch.njol.skript.lang.SkriptParser.parseExpression(SkriptParser.java:252)
        at ch.njol.skript.lang.SkriptParser.parseExpression(SkriptParser.java:243)
        at ch.njol.skript.lang.SkriptParser.parse_i(SkriptParser.java:759)
        at ch.njol.skript.lang.SkriptParser.parse_i(SkriptParser.java:753)
        at ch.njol.skript.lang.SkriptParser.parse(SkriptParser.java:176)
        at ch.njol.skript.lang.SkriptParser.parse(SkriptParser.java:142)
        at ch.njol.skript.lang.SkriptParser.parseSingleExpr(SkriptParser.java:392)
        at ch.njol.skript.lang.SkriptParser.parseExpression(SkriptParser.java:252)
        at ch.njol.skript.lang.SkriptParser.parseExpression(SkriptParser.java:243)
        at ch.njol.skript.lang.SkriptParser.parse_i(SkriptParser.java:759)
        at ch.njol.skript.lang.SkriptParser.parse_i(SkriptParser.java:675)
        at ch.njol.skript.lang.SkriptParser.parse_i(SkriptParser.java:697)
        at ch.njol.skript.lang.SkriptParser.parse(SkriptParser.java:176)
        at ch.njol.skript.lang.SkriptParser.parse(SkriptParser.java:142)
    
    With links:
    at ch.njol.skript.lang.SkriptParser.parse(SkriptParser.java:176)
    at ch.njol.skript.lang.SkriptParser.parse(SkriptParser.java:142)
    at ch.njol.skript.lang.SkriptParser.parseSingleExpr(SkriptParser.java:392)
    at ch.njol.skript.lang.SkriptParser.parseExpression(SkriptParser.java:252)
    at ch.njol.skript.lang.SkriptParser.parseExpression(SkriptParser.java:243)
    at ch.njol.skript.lang.SkriptParser.parse_i(SkriptParser.java:759)
    at ch.njol.skript.lang.SkriptParser.parse_i(SkriptParser.java:753)
     
  2. you can add a loop variable, if its further than 3 recursive loops into it, then it will be halted, and the status of every fucntion will get printed
     
  3. Offline

    Njol

    Well I can already produce stack traces while the code is running with Java's VisualVM so I don't see the need for such a variable here ;)
     
  4. Offline

    TheFluffey

    Any help for Njol? I rely on him for his wonderful plugin.
     
    JazzaG likes this.
  5. Offline

    TheFluffey

    Please? (24h bump).
     
  6. Offline

    soulgem

    first of all... what is "i2"? i might be able to help if i can understand it's context.
     
  7. Offline

    fireblast709

    Njol what part of the script causes the hang? (like add a System.out.println("expression") to see what he is parsing at the very moment of the hang)
    soulgem read the code -_-. its an iterator of a for-loop, type integer, looping between a given start point and the expression length
     
  8. Offline

    Njol

    The code doesn't stop anywhere, it's caught in an infinite loop (or something similar as I haven't found any infinite loops) while parsing any of the posted lines (I realise that it's likely only part of the line causing the problem but I have no idea how to filter it out). I also posted a stack trace from during the hang-up (stack traces wary in the upper few lines, but the part I posted occurrs in all stack traces).

    BTW: I'm sorry that the code isn't documented/commented, but that's not part of my plugin's API so usually nobody takes a look at it except for me =P
     
  9. Offline

    fireblast709

  10. if your under a windows envioment, pressing ctrl+break shows the stack traces of every thread, use full when you server apper to hang unexcepted (mayby doing the too large worldedit of your brother) or like your plugin doing something, notice that this wont work whit wrappers (mostly)
     
  11. Offline

    Njol

    I though that the console would be spammed with complete nonsense but it actually resulted in nice patterns:
    Code:
    grow tree of type argument 1 at block above targeted block
    2012-11-15 21:07:21 [INFORMATION] block above targeted block [56]
    2012-11-15 21:07:21 [INFORMATION] above targeted block [64]
    2012-11-15 21:07:21 [INFORMATION] targeted block [71]
    2012-11-15 21:07:21 [INFORMATION] above [70]
    2012-11-15 21:07:21 [INFORMATION] targeted block [71]
    2012-11-15 21:07:21 [INFORMATION] above [70]
    2012-11-15 21:07:21 [INFORMATION] above targeted block [63]
    2012-11-15 21:07:21 [INFORMATION] targeted block [70]
    2012-11-15 21:07:21 [INFORMATION] above [69]
    2012-11-15 21:07:21 [INFORMATION] targeted block [70]
    2012-11-15 21:07:21 [INFORMATION] above [69]
     
     
    loop blocks in radius 1.5 around block 2 below player:
    2012-11-15 21:14:34 [INFORMATION] 2 below [58]
    2012-11-15 21:14:34 [INFORMATION] 2 below player [51]
    2012-11-15 21:14:34 [INFORMATION] below player [58]
    2012-11-15 21:14:34 [INFORMATION] player [65]
    2012-11-15 21:14:34 [INFORMATION] below [64]
    2012-11-15 21:14:34 [INFORMATION] player [65]
    2012-11-15 21:14:34 [INFORMATION] below [64]
    2012-11-15 21:14:34 [INFORMATION] below player [58]
    2012-11-15 21:14:34 [INFORMATION] player [65]
    2012-11-15 21:14:34 [INFORMATION] below [64]
    2012-11-15 21:14:34 [INFORMATION] player [65]
    2012-11-15 21:14:34 [INFORMATION] below [64]
     
     
    loop entities of types argument 1 in player's world:
    2012-11-15 21:37:41 [INFORMATION] 1 in player [35]
    2012-11-15 21:37:41 [INFORMATION] in player [42]
    2012-11-15 21:37:41 [INFORMATION] player [49]
    2012-11-15 21:37:41 [INFORMATION] in [48]
    2012-11-15 21:37:41 [INFORMATION] player [49]
    2012-11-15 21:37:41 [INFORMATION] in [48]
    2012-11-15 21:37:41 [INFORMATION] in player [42]
    2012-11-15 21:37:41 [INFORMATION] player [49]
    2012-11-15 21:37:41 [INFORMATION] in [48]
    2012-11-15 21:37:41 [INFORMATION] player [49]
    2012-11-15 21:37:41 [INFORMATION] in [48]
     
     
    loop blocks from block 5 south-east below the player to the block 5 south-west below the player:
    2012-11-15 21:38:52 [INFORMATION] south-west below the player [95]
    2012-11-15 21:38:52 [INFORMATION] below the player [102]
    2012-11-15 21:38:52 [INFORMATION] the player [109]
    2012-11-15 21:38:52 [INFORMATION] player [116]
    2012-11-15 21:38:52 [INFORMATION] the [115]
    2012-11-15 21:38:52 [INFORMATION] below [108]
    2012-11-15 21:38:52 [INFORMATION] the player [109]
    2012-11-15 21:38:52 [INFORMATION] player [116]
    2012-11-15 21:38:52 [INFORMATION] the [115]
    2012-11-15 21:38:52 [INFORMATION] below [108]
    2012-11-15 21:38:52 [INFORMATION] below the player [102]
    2012-11-15 21:38:52 [INFORMATION] the player [109]
    2012-11-15 21:38:52 [INFORMATION] player [116]
    2012-11-15 21:38:52 [INFORMATION] the [115]
    2012-11-15 21:38:52 [INFORMATION] below [108]
    2012-11-15 21:38:52 [INFORMATION] the player [109]
    2012-11-15 21:38:52 [INFORMATION] player [116]
    2012-11-15 21:38:52 [INFORMATION] the [115]
    2012-11-15 21:38:52 [INFORMATION] below [108]
     
     
    message "There are <green>%number of entities of type argument in world%<reset> %argument% in %world%"
    2012-11-15 21:40:37 [INFORMATION] type argument in world [46]
    2012-11-15 21:40:37 [INFORMATION] argument in world [53]
    2012-11-15 21:40:37 [INFORMATION] in world [60]
    2012-11-15 21:40:37 [INFORMATION] world [67]
    2012-11-15 21:40:37 [INFORMATION] world [67]
    2012-11-15 21:40:37 [INFORMATION] world [67]
    2012-11-15 21:40:37 [INFORMATION] world [67]
    2012-11-15 21:40:37 [INFORMATION] world [67]
    2012-11-15 21:40:37 [INFORMATION] world [67]
    2012-11-15 21:40:37 [INFORMATION] world [67]
    2012-11-15 21:40:37 [INFORMATION] world [67]
    2012-11-15 21:40:37 [INFORMATION] in world [60]
    2012-11-15 21:40:37 [INFORMATION] world [67]
    2012-11-15 21:40:37 [INFORMATION] world [67]
    2012-11-15 21:40:37 [INFORMATION] world [67]
    2012-11-15 21:40:37 [INFORMATION] world [67]
    2012-11-15 21:40:37 [INFORMATION] world [67]
    2012-11-15 21:40:37 [INFORMATION] world [67]
    2012-11-15 21:40:37 [INFORMATION] world [67]
    2012-11-15 21:40:37 [INFORMATION] world [67]
    
    These patterns are repeated infinitely while the longest expressions appear the least (BTW: the number after the expressions are the current stack size)

    These are all related to locations/blocks and worlds...

    BTW: this is what the CPU does the most while parsing the first line (grow tree of type argument 1 at block above targeted block):

    ch.njol.skript.lang.SkriptParser.parse_i() - 35%
    ch.njol.skript.log.SkriptLogger.stopSubLog() - 21%
    ch.njol.skript.util.Utils.getPlural() - 18.4%
    ch.njol.skript.registrations.Converters.converterExists() - 4.3%

    edit: this is why the getPlural is used so heavily:
    Code:
        at java.lang.String.toUpperCase(Unknown Source)
        at java.lang.String.toUpperCase(Unknown Source)
        at ch.njol.skript.util.Utils.getPlural(Utils.java:481)
        at ch.njol.skript.Aliases.getAlias(Aliases.java:440)
        at ch.njol.skript.Aliases.parseType(Aliases.java:405)
        at ch.njol.skript.Aliases.parseItemType(Aliases.java:357)
        at ch.njol.skript.expressions.ExprEntity.init(ExprEntity.java:58)
        at ch.njol.skript.lang.SkriptParser.parse(SkriptParser.java:202)
        at ch.njol.skript.lang.SkriptParser.parse(SkriptParser.java:144)
        at ch.njol.skript.lang.SkriptParser.parseSingleExpr(SkriptParser.java:372)
        at ch.njol.skript.lang.SkriptParser.parseExpression(SkriptParser.java:268)
    
    ExprEntity is an expression like 'cow' or 'player', but also 'arrow', which is checked to prevent conflicts.

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: May 29, 2016
  12. Offline

    fireblast709

    So if these blocks of output keep looping, that means there is a bug at the start of the loop, which causes it to (nearly) infinite loop. 2 questions:
    • Where does the parsing start (like the absolute beginning, where it read the file and parses it)
    • What is the full script you are parsing (or if the 4 lines of the OP are the full script, tell me)
    • How is the script ordered (as the example tells me the 1st line is the command and the other 3 are specifications). But this might as well be answered by the code
     
  13. Offline

    Njol

    Parsing is done for each line independently with Statement.parse(String) which calls SkriptParser's general parse() method with an iterator of all registered statements. That method then tests whether any pattern matches, and if one matches it parses the expressions included in the pattern. For example, the line "grow tree of type argument 1 at block above targeted block" matches the pattern of the tree effect which is something like "grow tree of type <type> <block>". It will then try all possibilities for those last two expressions, e.g. <type> = "argument 1" and <block> = "at block above targeted block" or <type> = "argument 1 at block" and <block> = "above targeted block" and if any combination works then it should stop. But it somehow doesn't stop anymore =/

    PS: I got different hang-ups by commenting out the lines that caused them to get more examples.

    PPS: After changing UnparsedLiterals and the expression list parsing a bit I actually got Skript to work again but with errors instead of hang-ups related to not parsing UnparsedLiterals everywhere. Thus I now believe that it's only an issue when parsing as Object, which is e.g. used in the comparision condition (<object> is <object>), the change effect (set <object> to <object>) and loops (loop <object>). Parsing as object also causes a string to be parsed as //any// possible expression, e.g. entities, blocks, messages, lines of a sign, etc. which might be another issue.
     
  14. Offline

    fireblast709

    for the last you should check if it is possibly another class, like dirt is a block, zombie is an entity, etc.
     
  15. Offline

    Njol

    After some more testing I have been able to make Skript work again by removing ExprLocation.
    I guess that Skript tries to parse every location as "<direction> <location>" which contains a location that is parsed as direction&location again, and repeating this as long as the line has spaces. But this should still stop within a reasonnable time...

    PS: removing ExprDirection and leaving ExprLocation still caused the hang-up, i.e. the direction in ExprLocation's pattern doesn't even matter I guess.
     
Thread Status:
Not open for further replies.

Share This Page