In the beginning ...
Over the many years of my career I have gained a strong respect for many software development practitioners. I have known may people with amazing talent, energy, intellect, and understanding of software development issues, languages, and practices. These people produced in me a naive respect for the entire field of software development.
Recently I have been asking myself
Who put the sham in the shamalma dingdong?
I see software products on the market with minimal connection to either correct behavior or robust behavior. For decades now the most frequent software vulnerability has been buffer overflows. While many buffer overflows have been fixed over the years, there does not seem to be any reduction in buffer overflow vulnerabilities. While some programming languages provide garbage collection, memory leaks abound in current operational code. Java and C# provide garbage collection as the default behavior of their implementations, but sometimes Java and C# programs still leak memory. C++ provides destructors, but C++ code is replete with memory leaks. C is the mother of all modern unsafe and insecure programming.
What's that phrase I have heard for so many decades? Ah yes. "The programming language doesn't matter. You can write good code in any language." I agree with second part of that statement. It is possible to write correct programs in any language. My recent observation, however, is that what is possible is not necessarily likely. If the choice of programming languages does not matter, then why do so many software development practitioners use languages with syntax derived from C? Does a C-derived syntax improve the quality of the resulting code, or the programming experience, or the quality of static analysis tools? Why not program everything in machine code? Why not program everything in COBOL?
What does matter in a programming language?
Many people like scripting languages because they allow rapid development of software. Decades ago programmers were worried about optimizing the speed of execution of software. Now the emphasis for many is the speed of development of software.Some companies adopted mottoes such as "cheaper, faster, better" to describe how they want to develop software. Experience has shown that the best that can be achieved is two out of three. In many cases only one out of three is achieved. Most recently none of those goals is actually achieved. While a project may release something near the imposed schedule it is now frequently an incomplete release that will need countless patches and sub-releases to meet the initial vision for the product.Is this behavior simply a result of the clashes between processes, schedules, and staffing levels, or is there more to the problem? Could there be a fundamental problem with the tools used by software development practitioners?
Even simple programs can have serious flaws
The following C program was extracted from the Sanfoundry web page
This
C Program puts even & odd elements of an array in 2 separate
arrays. The program first finds the odd and even elements of the
array. Then the odd elements of an array is stored in one array and
even elements of an array is stored in another array.
Here
is source code of the C program to put even & odd elements of an
array in 2 separate arrays. The C program is successfully compiled
and run on a Linux system. The program output is also shown below.
/*
* C Program to accept N integer number and store them in an array AR.
* The odd elements in the AR are copied into OAR and other elements
* are copied into EAR. Display the contents of OAR and EAR.
*/
#include <stdio.h>
void main()
{
long int ARR[10], OAR[10], EAR[10];
int i, j = 0, k = 0, n;
printf("Enter the size of array AR \n");
scanf("%d", &n);
printf("Enter the elements of the array \n");
for (i = 0; i < n; i++)
{
scanf("%ld", &ARR[i]);
fflush(stdin);
}
/* Copy odd and even elements into their respective arrays */
for (i = 0; i < n; i++)
{
if (ARR[i] % 2 == 0)
{
EAR[j] = ARR[i];
j++;
}
else
{
OAR[k] = ARR[i];
k++;
}
}
printf("The elements of OAR are \n");
for (i = 0; i < j; i++)
{
printf("%ld\n", OAR[i]);
}
printf("The elements of EAR are \n");
for (i = 0; i < k; i++)
{
printf("%ld\n", EAR[i]);
}
}
$ cc pgm39.c $ a.out Enter the size of array AR 6 Enter the elements of the array 34 56 78 90 12 39 The elements of OAR are 39 1 32768 11542516 11210377 The elements of EAR are 34
This program is used as an educational example of good C programming, yet it contains the seeds of a buffer overflow and also produces incorrect results. While it is possible to write a version of this C program without either of these problems, it is much easier to write the program as we see it. The C definition of an array lies at the heart of the problems this program shows. Could the use of a different programming language have helped avoid these problems? Of course it could.
An Ada program to fix the problems of the above C program
------------------------------------------------------------------ -- An Ada program to read integer values into an array, then -- -- copy the odd values into an odd array and the even values -- -- into an even array -- ------------------------------------------------------------------ with Ada.Text_IO; use Ada.Text_IO; procedure Even_Odd_2 is package Int_IO is new Ada.Text_IO.Integer_IO(Integer); use Int_Io; type Int_Array is array(Positive range <>) of Integer; Num : Positive; begin -- Prompt for and read the number of elements to input Put("Enter the number of integers you want to input: "); Get(Item => Num); declare All_Vals : Int_Array(1..Num); Enum : Natural := 0; Onum : Natural := 0; begin -- read all values into All_Vals for Element of All_Vals loop Put("Enter an integer: "); Get(Item => Element); if Element mod 2 = 0 then Enum := Enum + 1; else Onum := Onum + 1; end if; end loop; -- Declare the odd and even arrays, populate them -- and print their contents declare Ear : Int_Array(1..Enum); Oar : Int_Array(1..Onum); E_Index : Positive := 1; O_Index : Positive := 1; begin -- Populate the even and odd arrays for Element of All_Vals loop if Element mod 2 = 0 then Ear(E_Index) := Element; E_Index := E_Index + 1; else Oar(O_Index) := Element; O_Index := O_Index + 1; end if; end loop; -- Print the even array contents if Ear'Length > 0 then Put_Line("Even values:"); for Element of Ear loop Put_Line(Integer'Image(Element)); end loop; else Put_Line("There are no even values."); end if; -- Print the odd array contents if Oar'Length > 0 then Put_Line("Odd values:"); for Element of Oar loop Put_Line(Integer'Image(Element)); end loop; else Put_Line("There are no odd values:"); end if; end; end; end Even_Odd_2;
Discussion of the Ada version
The Ada version declares the arrays only after determining exactly how large the arrays need to be, preventing the possibility of trying to access the array outside its bounds. The size and index range for every Ada array is always available wherever the array is used. None of the array iteration mechanisms used in this program rely upon the programmer knowing the size of the array before execution time. These factors prevent this program from using the wrong set of index values for outputting the values as was done in the C program. Using the correct tool (Ada) allows one to produce a correct program with no more effort than was needed to produce the erroneous C program
No comments:
Post a Comment