I'm in the process of reviewing many of our applications. One application came back with quite a few null deference issues. It is worth mentioning is that I am quite unfamiliar with VB.NET so bear with any issues I may relay with my code.
Public Sub SomeMethod()
Try
PerformLog("Entering SomeMethod")
Dim intTemp As Short
Erase gstrFieldWhatever //Defined earlier: Public gstrFieldWhatever() As String
...
intTemp = intTemp + 1
ReDim Preserve gstrFieldWhatever(intTemp)
gstrFieldWhatever(intTemp) = "Z*L-"
The analyzer, Fortify in this case, is reporting that Erase gstrFieldWhatever will cause a potential null exception when we try to call it later at gstrFieldWhatever(intTemp) = "Z*L-". However, we using ReDim Preserve gstrFieldWhatever(intTemp) should create a new array. If this is the case, why would the analyzer indicate a potential null dereference issue?
The gstrFieldWhatever is a public field. There's a risk if this object is used in multi-threaded code, because the field could be accessed between when it is freed and when it is ReDimmed.
In most cases, the use of ReDim Preserve indicates a place where you really want a collection like List(Of String), however, I understand if that change might cascade into other areas of the code.
Related
Ok so I was in college and I was talking to my teacher and he said my code isn't good practice. I'm a bit confused as to why so here's the situation. We basically created a for loop however he declared his for loop counter outside of the loop because it's considered good practice (to him) even though we never used the variable later on in the code so to me it looks like a waste of memory. We did more to the code then just use a message box but the idea was to get each character from a string and do something with it. He also used the Mid() function to retrieve the character in the string while I called the variable with the index. Here's an example of how he would write his code:
Dim i As Integer = 0
Dim justastring As String = "test"
For i = 1 To justastring.Length Then
MsgBox( Mid( justastring, i, 1 ) )
End For
And here's an example of how I would write my code:
Dim justastring As String = "test"
For i = 0 To justastring.Length - 1 Then
MsgBox( justastring(i) )
End For
Would anyone be able to provide the advantages and disadvantages of each method and why and whether or not I should continue how I am?
Another approach would be, to just use a For Each on the string.
Like this no index variable is needed.
Dim justastring As String = "test"
For Each c As Char In justastring
MsgBox(c)
Next
I would suggest doing it your way, because you could have variables hanging around consuming(albeit a small amount) of memory, but more importantly, It is better practice to define objects with as little scope as possible. In your teacher's code, the variable i is still accessible when the loop is finished. There are occasions when this is desirable, but normally, if you're only using a variable in a limited amount of code, then you should only declare it within the smallest block that it is needed.
As for your question about the Mid function, individual characters as you know can be access simply by treating the string as an array of characters. After some basic benchmarking, using the Mid function takes a lot longer to process than just accessing the character by the index value. In relatively simple bits of code, this doesn't make much difference, but if you're doing it millions of times in a loop, it makes a huge difference.
There are other factors to consider. Such as code readability and modification of the code, but there are plenty of websites dealing with that sort of thing.
Finally I would suggest changing some compiler options in your visual studio
Option Strict to On
Option Infer to Off
Option Explicit to On
It means writing more code, but the code is safer and you'll make less mistakes. Have a look here for an explanation
In your code, it would mean that you have to write
Dim justastring As String = "test"
For i As Integer = 0 To justastring.Length - 1 Then
MsgBox( justastring(i) )
End For
This way, you know that i is definitely an integer. Consider the following ..
Dim i
Have you any idea what type it is? Me neither.
The compiler doesn't know what so it defines it as an object type which could hold anything. a string, an integer, a list..
Consider this code.
Dim i
Dim x
x = "ab"
For i = x To endcount - 1
t = Mid(s, 999)
Next
The compiler will compile it, but when it is executed you'll get an SystemArgumenException. In this case it's easy to see what is wrong, but often it isn't. And numbers in strings can be a whole new can of worms.
Hope this helps.
The following VB .net code gives me an out of memory exception. Does anybody knows why?
Dim vArray As ILArray(Of Double) = ILMath.rand(10000000)
Using ILScope.Enter(vArray)
For i As Integer = 1 To 100
vArray = ILMath.add(vArray, vArray)
Next
End Using
Thank you very much.
In this toy example you can simply remove the artificial scope and it will run fine:
Dim vArray As ILArray(Of Double) = ILMath.rand(10000000)
For i As Integer = 1 To 100
vArray = ILMath.add(vArray, vArray)
Next
Console.WriteLine("OK: " + vArray(0).ToString())
Console.ReadKey()
However, in a more serious situation, ILScope will be your friend. As stated on the ILNumerics page an artificial scope ensures a deterministic memory management:
All arrays created inside the scope are disposed once the block was
left.
Otherwise one had to rely on the GC for cleanup. And, as you know, this involves a gen 2 collection for large objects – with all disadvantages in terms of performance.
In order to be able to dispose the arrays they need to be collected and tracked somehow. Whether or not this qualifies for the term 'memory leak' is rather a philosophical question. I will not go into it here. The deal is: after the instruction pointer runs out of the scope these arrays are taken care of: their memory is put into the memory pool and will be reused. As a consequence, no GC will be triggered.
The scheme is especially useful for long running operations and for large data. Currently, the arrays are released only AFTER the scope block was left. So if you create an algorithm/ loop which requires more memory than available on your machine you need to clean up DURING the loop already:
Dim vArray As ILArray(Of Double) = ILMath.rand(10000000)
For i As Integer = 1 To 100
Using ILScope.Enter
vArray.a = ILMath.add(vArray, vArray)
' ...
End Using
Next
Here, the scope cleans up the memory after each iteration of the loop. This affects all local arrays assigned within the loop body. If we want an array value to survive the loop iteration we can assign to its .a property as shown with vArray.a.
I'm having trouble understanding what's not happening, in my case, with IEnumerator in vb.net.
I have this code which pulls data from a database and then reads the first two rows, summing up a column from each row into 'numGirls'. Then, with 'resEnum1.Reset()', I expected 'resEnum' to reset itself to the begining of the collection, but it doesn't;
Dim resEnum1 As IEnumerator = iTrack.res_by_gender(False, YearCB.Text).GetEnumerator
resEnum1.Reset()
Dim resSet As Object
Dim numGirls As Integer = 0
For x = 0 To 1
resEnum1.MoveNext()
resSet = resEnum1.Current
numGirls += resSet.qty
Next
resEnum1.Reset()
At this point my code should continue and iterate through the collection starting at the begining of the collection (-1) with a MoveNext;
While resEnum1.MoveNext
'...........'
End While
However, the IEnumerator (resEnum1) does not infact get reset but continues from the third row of the collection. Why?
Obviously I'm not understaing something, unless it is up to me to re-invent the wheel and implement the 'reset' in code?
Not all enumerators implement the Reset method inherited from IEnumerator. You could think of it as a "forward-only" enumerator.
"The Reset method is provided for COM interoperability. It does not necessarily need to be implemented; instead, the implementer can simply throw a NotSupportedException.". - MSDN
I am retrieving a byte blob from an SQLite database/record set. I am not experienced with garbage collection yet.
When I say:
Dim bt() As Byte
bt = r.fields("mybyteblob").value
... is that okay or unsafe?
I would like to make a copy of the byte array in the record set field, and I am not sure if I am simply referencing the byte array here instead of copying it.
In your code you are only referencing the byte array.
If you want to copy it you need
Dim bt() As Byte
if r.fields("mybyteblob").Value Is not Nothing then
dim lenArray = r.fields("mybyteblob").Length
bt = new Byte(lenArray)
Array.Copy(r.fields("mybyteblob").value, bt, lenArray)
end if
There is another alternative.
The Buffer class is faster than Array and more appropriate because you are using a byte array
Dim bt() As Byte
if r.fields("mybyteblob").Value Is not Nothing then
dim lenArray = r.fields("mybyteblob").Length
bt = new Byte(lenArray)
Buffer.BlockCopy(r.fields("mybyteblob").value, 0, bt, 0, lenArray)
end if
Here a good question on the two methods
It is very unusual to run into garbage collection problems if you only write managed code (i.e. no P/Invoke).
Many smart people has put a lot of effort into making garbage collection work without you having to worry about it, so do just that: don't worry about it. Just write your code, and if you run into a specific behavior you don't understand, then ask about that particular behavior (and I can assure you that in 99.9967% [1] of the cases it will not be the garbage collector).
[1] This is not a random number. I've ran into a garbage collection gotcha once in ~10 years of programming. Assuming 10 bugs a day and 300 days of work per year, that makes 29999/30000 bugs which are not garbage-collection related = 99.9967%.
the message was variable j is used before it have been assigned value.If in php language, it's not a problem at all.
Dim j() As String
Dim i As Integer
If (i = 1) Then
j(0) = "x"
Else
j(0) = "d"
End If
in php language,it's not a problem at all.
php doesn't use real arrays. A real array is a contiguous block of memory. Php uses a collection type with array-like semantics. They call it an array, but it's not really. Collections seldom make the same kind of guarantees about continuity because of performance problems caused when the collection grows at runtime.
If you want php-style "arrays" in .Net, you need to do the same thing php does and use a collection. The System.Collections.Generics.List<T> type works pretty well. Then you can append to the List by using its .Add() method or using the collection initializer syntax demonstrated below (requires Visual Studio 2010):
Dim i As Integer = 1
Dim j As New List(Of String) From { If(i = 1, "x","d") }
We can forgive php it's naming lapse, though, as real arrays should be used sparingly. A collection is almost always more appropriate.