SgDotNet
Singapore Professional .NET User Group -For Cool Developers

Weird bug?

rated by 0 users
This post has 18 Replies | 2 Followers

Top 25 Contributor
Posts 176
choongseng Sad [:(] Posted: 12-02-2005 3:10 PM
I've this weird error, wonder if anyone here can help.

Out of nowhere, the constructor seems to call the ArrayList.Add, and this is absolutely no in my constructor of the class.

it is a ASP.net application and it happends only after some unpredictable long time.

I suspect that it is some internal object list which it ran out of the limit.

[IndexOutOfRangeException: Index was outside the bounds of the array.]
   System.Collections.ArrayList.Add(Object value) +41

Seacon.eBiz.Data.DataManagement.vg_sys_ms_db_Accounts..ctor(SQLConnectionBlock& ParentSQLConn) in D:\Development\Visual Studio Projects\Virgil\eBiz.Data.SQLSilo\DataManager.vb:20
   Seacon.eBiz.Web.Hovel.HovelContext..ctor(Int32 user_pKey, Int32 hovel_pKey) in D:\Development\Visual Studio Projects\Virgil\eBiz.Web\Web.Hovel\HovelContext.vb:49
   Seacon.eBiz.Web.PageLayoutHttpModule.OnAuthenticateRequest(Object sender, EventArgs ea) in D:\Development\Visual Studio Projects\Virgil\eBiz.Web\Web\PageLayoutHttpModule.vb:47

System.Web.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +92
   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +64
my development sketch book my personal blog
Top 10 Contributor
Posts 2,290
Inheriting from some other base class? Looks like a data layer class; what if executed outside of ASP.NET (e.g. Console presentation layer)?

The melody of logic will always play out the truth. ~ Narumi Ayumu, Spiral

Top 25 Contributor
Posts 176
 icelava wrote:
Inheriting from some other base class? Looks like a data layer class; what if executed outside of ASP.NET (e.g. Console presentation layer)?


Yea, you are right!

My class looks like this, it didn't inherits any class.
Haven't tried to make it on winform, because apparently it is quite tied to my asp.net context (lousy design ya..)
The observation is that, most of  the time the error occurs at this line (in the error message) but sometime it occurs at other line.
I've use "ByRef" to pass the connection object over, any problem with that?


    Public Class vg_sys_ms_db_Accounts        ' General Object Feature

        ' TODO: DataManagement - for DB Account retrieval
        Private SQLConn As Seacon.eBiz.Data.SQLConnectionBlock
        Public Params As Struct

        ' Events Definition
        Public Event PreExecuteEvent As EventHandler
        Public Event PostExecuteEvent As EventHandler

        ' Data Access Block
        Public ReadOnly Property DAB() As Data.SQLConnectionBlock
            Get
                Return MyClass.SQLConn
            End Get
        End Property
        ' Constructors
        Public Sub New(ByRef ParentSQLConn As Data.SQLConnectionBlock)
            Me.Params = New Struct
            Me.Params.ResetTrackers()
            Me.SQLConn = ParentSQLConn
        End Sub
        Public Class Struct
            Public Sub New()
                ResetTrackers()
            End Sub
            Public Sub Seal()
                MyClass._Seal = True
            End Sub
            Private _Seal As Boolean
my development sketch book my personal blog
Top 10 Contributor
Posts 2,290
Other than the HovelContext class, i do not see why the vg_sys_ms_db_Accounts has affinity to ASP.NET. This makes isolated testing more difficult.

I also do not see why you have a need to pass in by reference what seems to already be passed by reference by default. Unless you tell me Data.SQLConnectionBlock is a struct instead of a class/object, which case passing by reference is correct (since structs being value types are copied and not referenced).

I don't know about VB standards, but "struct" is the keyword identifier for declaring a struct type, so looking at your declaration of a class called Struct has really confused me. Recommend naming it to something more meaningful, e.g. TrackerCollection.

What does ResetTrackers() do? Why is there a need to "Reset" a newly created object? Are "trackers" stored in an ArrayList? Have you attempted to step trace to reveal which line blows that exception?

The melody of logic will always play out the truth. ~ Narumi Ayumu, Spiral

Top 25 Contributor
Posts 176
 icelava wrote:
Other than the HovelContext class, i do not see why the vg_sys_ms_db_Accounts has affinity to ASP.NET. This makes isolated testing more difficult.

You're right... I need to do some isolated testing with winform for those classes, but reluctant to do it now. Will update here if I got further testing on it.

 icelava wrote:

I also do not see why you have a need to pass in by reference what seems to already be passed by reference by default. Unless you tell me Data.SQLConnectionBlock is a struct instead of a class/object, which case passing by reference is correct (since structs being value types are copied and not referenced).


I was using ByVal... and then changed to ByRef... which I don't see any different, I got what you mean, that give me a better idea of the different though. ;-) thanks.

 icelava wrote:

I don't know about VB standards, but "struct" is the keyword identifier for declaring a struct type, so looking at your declaration of a class called Struct has really confused me. Recommend naming it to something more meaningful, e.g. TrackerCollection.

hehe... roger that, but I leave that for the time being.

 icelava wrote:

What does ResetTrackers() do? Why is there a need to "Reset" a newly created object? Are "trackers" stored in an ArrayList? Have you attempted to step trace to reveal which line blows that exception?

ResetTrackers actually do initialization (hmm... InitTrackers?)
That's why it is in the sub new.
Trackers are generated properties (correspond to some _privateVariables)
:-( bad thing is that, I never encounter the thing in debug mode, which it happends only after some long time (unexpectedly though).

Wait a minute.... I forgot to check out the Trace.axd, I think I check before, but no idea what's the outcome already, maybe the message is more or less the same.
my development sketch book my personal blog
Top 10 Contributor
Posts 2,290
 choongseng wrote:
Wait a minute.... I forgot to check out the Trace.axd, I think I check before, but no idea what's the outcome already, maybe the message is more or less the same.
I'm not referring to ASP.NET Trace. Debug the web application instead; Set a breakpoint at the constructor and step through it.

The melody of logic will always play out the truth. ~ Narumi Ayumu, Spiral

Top 25 Contributor
Posts 176
 icelava wrote:
 choongseng wrote:
Wait a minute.... I forgot to check out the Trace.axd, I think I check before, but no idea what's the outcome already, maybe the message is more or less the same.
I'm not referring to ASP.NET Trace. Debug the web application instead; Set a breakpoint at the constructor and step through it.


I got what you mean, but apparently, the error does not happen instantly under any predictable condition, which means I can't replay that error.

This is another same error, raised at different location:
System.Web.HttpUnhandledException: Exception of type 'System.Web.HttpUnhandledException' was thrown. ---> System.IndexOutOfRangeException: Index was outside the bounds of the array.
   at System.Collections.ArrayList.Add(Object value)
   at Seacon.eBiz.Web.Controls.TabbedPanel..ctor() in C:\Development\Visual Studio Projects\eBiz Framework\eBiz.Web\Web.Controls\TabbedPanel.vb:line 24
   at Seacon.eBiz.Web.PageContext.GenerateTabPanel() in C:\Development\Visual Studio Projects\eBiz Framework\eBiz.Web\Web\PageContext.vb:line 109
   at Seacon.eBiz.Web.PageLayoutHttpModule.MasterPageInitComplete(Object sender, EventArgs ea) in C:\Development\Visual Studio Projects\eBiz Framework\eBiz.Web\Web\PageLayoutHttpModule.vb:line 183
   at System.Web.UI.Page.OnInitComplete(EventArgs e)
   at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
   --- End of inner exception stack trace ---
   at System.Web.UI.Page.HandleError(Exception e)
   at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
   at System.Web.UI.Page.ProcessRequest(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
   at System.Web.UI.Page.ProcessRequest()
   at System.Web.UI.Page.ProcessRequestWithNoAssert(HttpContext context)
   at System.Web.UI.Page.ProcessRequest(HttpContext context)
   at ASP.sso_signon_aspx.ProcessRequest(HttpContext context)
   at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
   at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)

It basically, when ever the constructor is being executed, seems like it is keeping track of something with array. And I think that could be an internal stack overflow?

my development sketch book my personal blog
Top 10 Contributor
Posts 2,290
 choongseng wrote:
This is another same error, raised at different location:
System.Web.HttpUnhandledException: Exception of type 'System.Web.HttpUnhandledException' was thrown. ---> System.IndexOutOfRangeException: Index was outside the bounds of the array.
   at System.Collections.ArrayList.Add(Object value)
   at Seacon.eBiz.Web.Controls.TabbedPanel..ctor() in C:\Development\Visual Studio Projects\eBiz Framework\eBiz.Web\Web.Controls\TabbedPanel.vb:line 24
And what does TabbedPanel attempt during construction?

Also, do these classes happen to inherit from some base class? If so, check the base constructor.

The melody of logic will always play out the truth. ~ Narumi Ayumu, Spiral

Top 25 Contributor
Posts 176
Hope this won't surprise you:

    <DefaultProperty("Text"), ToolboxData("<{0}:[TabbedPanel] runat=server></{0}:[TabbedPanel]>")> Public Class [TabbedPanel]
        Inherits System.Web.UI.WebControls.WebControl

        Protected Overrides Sub Render(ByVal output As System.Web.UI.HtmlTextWriter)
            Dim CloseIDs As New ArrayList
            For Each nTab As Web.Controls.TabbedUserControl In Me.Controls
                CloseIDs.Add(nTab.ClientID)
#If DEBUG Then
                output.Write("<!--" & nTab.ClientID & "-->")
#End If
            Next
            For Each nTab As Web.Controls.TabbedUserControl In Me.Controls
                nTab.RenderTabBar(output, CloseIDs)
            Next
            For Each nTab As Web.Controls.TabbedUserControl In Me.Controls
                nTab.RenderTabContent(output)
            Next
        End Sub

        Public Sub New()
        End Sub
    End Class

I think I've to spare an incident support for this as I'm too tighted up with too many things and have no time to debug this weird thing.
my development sketch book my personal blog
Top 25 Contributor
Posts 176
ops... not to be surprise, it does inherits from the WebControl.
my development sketch book my personal blog
Top 25 Contributor
Posts 176
The code inspected using Lutz's reflector tool:

public up_vg_ms_User_Access_Agent_Sel(SQLConnectionBlock ConnBlock) : base(ref ConnBlock)
{
      up_vg_ms_User_Access_Agent_Sel.__ENCList.Add(new WeakReference(this));
      base.add_PreExecuteEvent(new StoredProcedureBaseClass<up_vg_ms_User_Access_Agent_Sel>.PreExecuteEventEventHandler(this, (IntPtr) this.PreExecute));
      base.add_PostExecuteEvent(new StoredProcedureBaseClass<up_vg_ms_User_Access_Agent_Sel>.PostExecuteEventEventHandler(this, (IntPtr) this.PostExecute));

}

My original code is as below:

    Public Class up_vg_ms_User_Access_Agent_Sel

        Inherits Seacon.eBiz.Data.SQLSilo.StoredProcedureBaseClass(Of Seacon.eBiz.Data.SQLSiloStruct.up_vg_ms_User_Access_Agent_Sel)

        Public Shadows Event PreExecuteEvent As System.EventHandler

        Public Shadows Event PostExecuteEvent As System.EventHandler

        Public Sub New(ByVal ConnBlock As Seacon.eBiz.Data.SQLConnectionBlock)

            MyBase.New(ConnBlock)

            AddHandler MyBase.PreExecuteEvent, AddressOf Me.PreExecute

            AddHandler MyBase.PostExecuteEvent, AddressOf Me.PostExecute

        End Sub

And the Base class is as below:

    Public MustInherit Class StoredProcedureBaseClass(Of boClass As {New})

 

        Protected SPCommand As SQLCommandBlock

        Public Params As boClass

 

        Protected Event PreExecuteEvent()

        Protected Event PostExecuteEvent()

 

        Public Sub New(ByRef ConnBlock As SQLConnectionBlock)

            ' Construct a new instance of boClass

            MyClass.Params = New boClass()

            MyClass.SPCommand = ConnBlock.GetCommandOperation()

            MyClass.SPCommand.CommandType = CommandType.StoredProcedure

            MyClass.SPCommand.CommandText = GetType(boClass).Name

        End Sub



Well, the case is closed! finally and the finding is simple because then the code is compiled under debug mode, the compiler emit the additional reference for debugger use. And after I've compile it with Release mode, the line is gone!

And the issue of the error is due to the fact that the ArrayList (__ENCList, *Add) is not tread safe.

The issue spend me one incident support ticket and many thanks to Li, who follow up the case.

The lesson learned is ALWAYS use Lutz's reflector tool to find out what is going on FIRST when there's weird bugs.

Hope this will be a useful resource for you guys to refer to, thanks icelava for some hints on the issue, the advice is correct, just that I should have used the reflector instead of looking at source code.

Cheers!

*Edited: it is the thread-not-safe Add method which runs on the static arraylist causes the exception.

my development sketch book my personal blog
Top 10 Contributor
Posts 2,290
Does that happen to be a VB-only compiler percularity? ;-)

Having used C# for so long, I've never encountered such a problem using domain and data layer objects. Debug mode or not. (Nope I did not peek into decompiled assemblies; not enough time)

The melody of logic will always play out the truth. ~ Narumi Ayumu, Spiral

Top 25 Contributor
Posts 176
 icelava wrote:
Does that happen to be a VB-only compiler percularity? ;-)

Having used C# for so long, I've never encountered such a problem using domain and data layer objects. Debug mode or not. (Nope I did not peek into decompiled assemblies; not enough time)


I'm not sure what is really going on in the scene, and with the knowledge that arraylist.add actually increase the array size first before it attempt to add the item into the array, this is my suspect:

Since the arraylist is not thread safe, the action of increasing the array and the action of assigning the item to the highest rank of the array is not atomic. Peeking into the reflected code, the arraylist is being expanded and the object itself is added into the static arraylist each time it is being constructed, should be for debugger usage to keep track of instances being created for a particular class.

And the problem lies when garbage collection takes place. Since the action is not atomic, it could be the case where a particular instance is being garbage collected and the static array list being shorted, which these actions happend within the expansion of the arraylist and the assignment of the last item within the ArrayList.Add function. And thus, exception!

My codes are on ASP.NET where there's many concurrent request, which each request is running as a thread and thus, due to such non-thread safe behaviour of the ArrayList and the fact that the debugger emits those nasty codes out, I've got myself into such problem.

I think C# will have the same problem as I don't think they have different debugging structure compare to VB.NET. ;-) will compile and reflect a c# when I've got time.
my development sketch book my personal blog
Top 25 Contributor
Posts 154
quite interesting, just for curiosity, here is a listing of the method implementations

This snippet is from: [Serializable()] public class ArrayList : IList, ICloneable

public virtual int Add(Object value)
{
    if (_size == _items.Length) EnsureCapacity(_size + 1);
         _items[_size] = value;
        _version++;
        return _size++;
}



and the synchronized version: [Serializable()] private class SyncArrayList : ArrayList

public override int Add(Object value)
{
    lock(_root) { return _list.Add(value); }
}

http://feelite.com/blog
Top 25 Contributor
Posts 176
Thanks.

I found that the issue occurs only when the particular class inherits WebControl.

Try it out!
my development sketch book my personal blog
Page 1 of 2 (19 items) 1 2 Next > | RSS
Copyright SgDotNet 2004-2008
Powered by Community Server (Commercial Edition), by Telligent Systems