Watching the world from the intersection of Software and Life

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.
  1. /*
  2.  * C Program to accept N integer number and store them in an array AR.
  3.  * The odd elements in the AR are copied into OAR and other elements
  4.  * are copied into EAR. Display the contents of OAR and EAR.
  5.  */
  6. #include <stdio.h>
  7.  
  8. void main()
  9. {
  10.     long int ARR[10], OAR[10], EAR[10];
  11.     int i, j = 0, k = 0, n;
  12.  
  13.     printf("Enter the size of array AR \n");
  14.     scanf("%d", &n);
  15.     printf("Enter the elements of the array \n");
  16.     for (i = 0; i < n; i++)
  17.     {
  18.         scanf("%ld", &ARR[i]);
  19.         fflush(stdin);
  20.     }
  21.     /*  Copy odd and even elements into their respective arrays */
  22.     for (i = 0; i < n; i++)
  23.     {
  24.         if (ARR[i] % 2 == 0)
  25.         {
  26.             EAR[j] = ARR[i];
  27.             j++;
  28.         }
  29.         else
  30.         {
  31.             OAR[k] = ARR[i];
  32.             k++;
  33.         }
  34.     }
  35.     printf("The elements of OAR are \n");
  36.     for (i = 0; i < j; i++)
  37.     {
  38.         printf("%ld\n", OAR[i]);
  39.     }
  40.     printf("The elements of EAR are \n");
  41.     for (i = 0; i < k; i++)
  42.     {
  43.         printf("%ld\n", EAR[i]);
  44.     }
  45. }


$ 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

Comments

Popular posts from this blog

Comparing Ada and High Integrity C++

An Ada Publish-Subscribe Producer-Consumer Exercise

Ada vs C++ Bit-fields