#1
  1. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Oct 2012
    Posts
    3
    Rep Power
    0

    Weird "list index out of bounds" error


    I'm the developer of a commercial application with a lot of users and have gotten reports from a couple of users of a strange problem that appears to be random. In a simple function that navigates a string list that is passed to it, they are getting a "list index out of bounds" error that should never be happening. The code is below and from the Eureka Log error log I know that the error is happening on this line:

    ItemFound:=tblItems.Locate('serial', ItemsList[n], []);

    Not that it's really relevant, but this app uses the Advantage database and the purpose of the routine is to use some Advantage functionality to check for records being locked. I logged into the user's system to see what was happening. In one case where the list passed to the function should contain 4 items, the index number in the error was 4, when it only should have been looking for 0 to 3. In another case with 2 items, the number was 2 when it should have stopped at 1. Since this function gets the count of the list then loops through the list in a way that I've coded a thousand times, I don't know it could ever be looking beyond the last item. Even if the calling routine somehow passed more items than it should have, the function determines the count so how does the navigation loop end up going beyond the last item? I can't actually duplicate the problem on my own system and only a couple of users out of many have reported it so it's quite frustrating to solve. Any ideas on this?

    Glenn

    ----------

    Code:
    function ItemsLocked(ItemsList, LockList: TStringList; UseItemName: boolean): boolean;
    var
      aHandle: ADSHANDLE;
      tblItems: TaysTable;
      Rec, r, n, c: integer;
      UserInfo : ADS_MGMT_USER_INFO;
      Size, LockType : Unsigned16;
      ItemFound: boolean;
    
    begin
      r:=ACE.AdsMgConnect(pchar(ExtractFileDrive(formMain.Global.gblTableLocation)), nil, nil, @aHandle);
      Size:=sizeof(ADS_MGMT_USER_INFO);
      tblItems := QuickTable('items','',True);
      c:=ItemsList.Count-1;
      for n:=0 to c do begin
        if UseItemName then
          ItemFound:=tblItems.Locate('name', ItemsList[n], [])
        else
          ItemFound:=tblItems.Locate('serial', ItemsList[n], []);
        if ItemFound then begin
          Rec:=tblItems.Recno;
          r:=AdsMgGetLockOwner(aHandle, pchar(formMain.Global.gblTableLocation +'items.adt'), Rec, @UserInfo, @Size, @LockType);
          if LockType > 1 then
            LockList.Add(tblItems.FieldByName('Name').AsString + UserInfo.aucUserName;
        end;
      end;
      Result:=(LockList.Count > 0);
      ACE.AdsMgDisConnect(aHandle);
    end;
  2. #2
  3. No Profile Picture
    Contributing User
    Devshed Regular (2000 - 2499 posts)

    Join Date
    Jan 2006
    Location
    Carlsbad, CA
    Posts
    2,057
    Rep Power
    383
    Originally Posted by galcott
    In one case where the list passed to the function should contain 4 items, the index number in the error was 4, when it only should have been looking for 0 to 3. In another case with 2 items, the number was 2 when it should have stopped at 1.
    Any ideas on this?

    Glenn

    ----------
    We do not know the origin of ItemList.
    Is there any chance that some other part of your program or some other user could be affecting its contents at the same time?

    One suggestion - not for a solution but for diagnosis.
    1. Start by copying the contents of ItemList to a locally created TStringList and see if the issue persists.

    Clive
  4. #3
  5. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Oct 2012
    Posts
    3
    Rep Power
    0
    The ItemsList is passed to this function from various parts of the program. But even if the calling routine passed the wrong number of items for some reason, that doesn't explain the problem because the function counts the items and there's no way it should be able to loop beyond the value of the "c" variable. There's no way the function can be called from more than one place at the same time, and certainly no other user can affect it because each user runs a separate copy of the program.
  6. #4
  7. No Profile Picture
    Contributing User
    Devshed Regular (2000 - 2499 posts)

    Join Date
    Jan 2006
    Location
    Carlsbad, CA
    Posts
    2,057
    Rep Power
    383
    Well, the problem is that what you say can not happen is happening.
    Therefore, you have to throw out all your assumptions and try one change at a time
    to, at least, confirm what is NOT the problem. That has always been my approach.

    Besides my original suggestion I would:
    1. ignore "c" and put count-1 into the for loop directly.
    2. Add some code that checks count as you enter each iteration
    and see if it remains constant and matches the value before you enter the loop.

    Of course, someone else here may spot something we have both overlooked.

    Clive
  8. #5
  9. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jun 2008
    Posts
    356
    Rep Power
    7
    Not that I see where it could be happening, but the other possibility is that the list is getting smaller (items are deleted from it), thus the count will be off by as many as has been deleted. In cases like that, it is safer to code a for loop to start at the end and go down to 0

    For n := C downto 0 do
    begin
    ...
    end;

    That way, even if items are removed from the list, the list index (n) will always be valid.
  10. #6
  11. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Oct 2012
    Posts
    3
    Rep Power
    0
    It's true that what's happening seems impossible. I should emphasize that only 2 users out of many have seen the problem and I can't duplicate it. The problem with writing any diagnostic code to figure it out is that the users have to do the testing since they're the only ones getting the error. So it's a cumbersome process where I have to send the test version to my client (the vendor of the app) then he sends it to the users and we probably have to keep repeating this process.

    So basically I've decided to put the offending code in a try/except block and ignore the error. That won't have a significant negative effect on the functionality and seems to be the best workaround.

    Thanks for your input anyway!
  12. #7
  13. No Profile Picture
    Contributing User
    Devshed Regular (2000 - 2499 posts)

    Join Date
    Jan 2006
    Location
    Carlsbad, CA
    Posts
    2,057
    Rep Power
    383
    Yes. Sometimes it is smarter to walk round the side of the wall than keep banging your head against it

    I must admit, it does seem very weird.

IMN logo majestic logo threadwatch logo seochat tools logo