Yahoo Serious
2008-07-24 08:05:23 UTC
We use the global IdStack.GStack.LocalAddresses to get information about
local IP-addresses.
We sometimes use it from multiple threads. However, it seems that
TIdStack.LocalAddresses is not thread safe:
It is possible that thread A is using the returned LocalAddresses, e.g.:
A: MyAdresses.Assign(GStack.LocalAddresses)
but while copying the list thread B may be changing it:
B: MyAdresses.Assign(GStack.LocalAddresses)
because TIdStack.GetLocalAddresses does a:
FLocalAddresses.Clear;
So thread A may be referencing an item-index that B has just erased.
This is fortified by the LocalAddresses varying more these days, due to a.o.
VPN and BlueTooth. So even if the list is filled again by thread B, the
previous Count (returned in thread A) may differ from the present Count
(resulting from thread B).
This last problem is also possible in a single thread, if people access
LocalAddresses multiple times in a single procedure. People probably don't
realize this causes the list to be repopulated. E.g. looking at DejaNews
for earlier reports, I saw Don Siders (Team Indy!) suggest this code (in
2001):
---
// create listeners for each IP address on port 2112
for (iAddr = 0; iAddr < GStack->LocalAddresses->Count; iAddr++)
{
AServer->Bindings->Add();
AServer->Bindings->Items[iAddr]->IP = GStack->LocalAddresses[iAddr];
AServer->Bindings->Items[iAddr]->Port = 2112;
}
---
If the Count of LocalAddresses in the second call, has been decreased due to
the repopulationg, this will
cause an AV.
So I think this should be resolved, by either:
- make FLocalAddresses a thread safe list
- make GStack a threadvar
- make [Get]LocalAddresses a function with parameter (const ARepopulate:
boolean = False)
What do you think?
Yahoo
local IP-addresses.
We sometimes use it from multiple threads. However, it seems that
TIdStack.LocalAddresses is not thread safe:
It is possible that thread A is using the returned LocalAddresses, e.g.:
A: MyAdresses.Assign(GStack.LocalAddresses)
but while copying the list thread B may be changing it:
B: MyAdresses.Assign(GStack.LocalAddresses)
because TIdStack.GetLocalAddresses does a:
FLocalAddresses.Clear;
So thread A may be referencing an item-index that B has just erased.
This is fortified by the LocalAddresses varying more these days, due to a.o.
VPN and BlueTooth. So even if the list is filled again by thread B, the
previous Count (returned in thread A) may differ from the present Count
(resulting from thread B).
This last problem is also possible in a single thread, if people access
LocalAddresses multiple times in a single procedure. People probably don't
realize this causes the list to be repopulated. E.g. looking at DejaNews
for earlier reports, I saw Don Siders (Team Indy!) suggest this code (in
2001):
---
// create listeners for each IP address on port 2112
for (iAddr = 0; iAddr < GStack->LocalAddresses->Count; iAddr++)
{
AServer->Bindings->Add();
AServer->Bindings->Items[iAddr]->IP = GStack->LocalAddresses[iAddr];
AServer->Bindings->Items[iAddr]->Port = 2112;
}
---
If the Count of LocalAddresses in the second call, has been decreased due to
the repopulationg, this will
cause an AV.
So I think this should be resolved, by either:
- make FLocalAddresses a thread safe list
- make GStack a threadvar
- make [Get]LocalAddresses a function with parameter (const ARepopulate:
boolean = False)
What do you think?
Yahoo