C - How is it possible to ensure that code doesn’t just crash due to a uncaught type error and pointers pointing randomly to memory

I am always wondering how its possible that so much of the internet infrastructure is written in C - a language with very limited type checking.

How is it possible to ensure that code doesn’t just crash due to a uncaught type error and pointers pointing randomly to memory.

Its still a mystery to me – but, somehow, with some kind of discipline in place, its very possible.

I think a similar kind of discipline is needed for Prolog, and other such languages.

Dan

But C does have static type checking. I remember K&R C with next to no static typechecking but I choose ANSI C now with compiler warnings. I’ve done some SML which does type inference and type checking. It’s got its advantages I must say.

But, this is very limited. Once you pass to a function argument, say, a pointer to struct, you are on your own, there is actually no guaranteed way, as far as i know, to check, even at run time that the function received a type correct pointer.

And any “type” checks during runtime could crash the program as well.

Dan

I do low-level development. The typechecking in place can be a hassle at times. I can’t remember the last time I saw an error with pointers to be honest and that covers a lot of code written by a lot of prgrammers.

As an example, my Prolog system is 500 lines of assembly code, 20,000 lines of C, and 30,000 lines of Prolog. I did as much as I could in Prolog, and as much as I could in C - so keeping up the abstraction ladder as much as possible. In six years there was not one ‘pointer error’ in that C code. I’m just a normal C programmer.

Edit: Actually, I did have a bug with the garbarge collector. Was it a pointer problem or a me not thinking it through problem?

Hi,

This is very interesting …

I think the question is: how much trust do you have in your code … when it runs that it won’t crash.

Or, stated differently, what is it, in your code that gives you that trust?

I am thinking to write C level code, but keep thinking that if i were to use C++, and use it as if it were C without any of the object oriented stuff – i would essentially program in C with type checking for free.

Does this makes sense?

Dan

Not really. You’re getting the same level of static type checking. You get run time type determination with C++ (I’m thinking polymmorphic functions), but if you’re not using classes…

I like C. I’ve been doing it since the late 1980s for work and play. As far as play is concerned, the last decade has seen me using C to build abstract machines which execute my Prolog or Lisp code. I just can be bothered writing another application in C for fun, I don’t have the free time to waste on a lower abstraction level than I could be on.

I’ve used Prolog in the past to build validation models for designs that were to be realised in C. Right now I’m implementing a protocol. Either it’ll be validated in Promela/SPIN (very applicable to protocols), or some automated reasoning system written in Prolog.

That doesn’t answer your question as it concerns validation not verification. Coding is a bit mechanical. Design on the other hand…

Looks like i didn’t recall correctly … the code below which i copied from an online tutorial and slightly amended – the c compiler does warn of incompatibility when calling the function the second time with the incorrect structure type.

So, that’s great. that’s basically what i wanted although, better if it doesnt compile at all.

I guess in C++ this wouldn’t compile due to incompatible types.

Btw, the complied code executes and prints garbage for the second call.

Dani

#include <stdio.h>
#include <string.h>
 
struct student 
{
           int id;
           char name[20];
           float percentage;
};

/* added this */
struct moo
{
char name[20];
float percentage;
};

void func(struct student *record);
 
int main() 
{
          struct student record;
 
          record.id=1;
          strcpy(record.name, "Raju");
          record.percentage = 86.5;
 
 
          func(&record);
      
          struct moo rmoo;
 
          strcpy(rmoo.name, "Raju_moo");
          rmoo.percentage = 86.5;
 
          func(&rmoo);
          
          
          return 0;
}
 
void func(struct student *record)
{
          printf(" Id is: %d \n", record->id);
          printf(" Name is: %s \n", record->name);
          printf(" Percentage is: %f \n", record->percentage);
}

There’s no way that would get through any compiler I use at work. You need to look into your compilation flags so it doesn’t compile.

Oh, and look up strncpy and use it instead of strcpy.

1 Like

I used an online compiler – i don’t have a compiler installed anymore on my machine … indeed should check flags …

thanks,

Dan

Add -Werror in the extra compiler flags (click the litle gear at the top right).

Then change func to

void func(struct student *record) {}

you’ll get this:

main.c: In function ‘main’:
main.c:35:16: error: passing argument 1 of ‘func’ from incompatible pointer type [-Werror=incompatible-pointer-types]
           func(&rmoo);
                ^
main.c:17:6: note: expected ‘struct student *’ but argument is of type ‘struct moo *’
 void func(struct student *record) {}
      ^~~~
cc1: all warnings being treated as errors
2 Likes

I’m interested in Mercury for this reason. It adds types to Prolog. It provides runtime speedups as a result. Presumably also allows silly mistakes to be caught at compile-time. I didn’t find good examples of its use as an embedded language though, so I moved on.

Discipline is everything in any language.
For my 2 cents, when I write C code I still have habits from 30 years ago when I worked on fail-safe railway signalling systems. There are two things I always do no matter how pointless they seem,

  1. if (CONSTANT == var) rather than (if var == CONSTANT) … try using “=” instead of “==” and see which one compiles.

  2. Check the return values of every single function you call. Even printf and fclose. Wrap them up if you need to, safe_prinf, safe_fclose etc. Check the return values and log any failures. You may never have checked the response from fclose() in your life but one day, the disk will fill up and it just might not close at that point…or printf was over a socket stream and it dropped the last two bytes and left the remote end hanging…usually at 3AM when you are asleep in bed dreaming of better things.

I meant in “C” code @EricGT :smiley:

Thank you.

Can you share more of your hard earned experiences from c programming work your work in safety critical systems …

thanks,

Dan

@EricGT, no I meant C function. And yes, checking can change the meaning of the code especially if you accidentally use = rather than == hence the method of putting the constant first; the compiler will baulk and refuse point blank to allow you to assign (=) a variable into the constant which is why you do it. If you use “if (var = CONSTANT)” and you meant “==” (and who hasn’t done this after a long day?) then you might not see it immediately…

1 Like

@grossdan those two are the ones I remember best, as I still practice them when in C land.

Other things I remember were mainly on dual processor systems: we had the technique of feeding the same inputs to both units and thus the code should be doing the same thing on both…at key points where outputs were set e.g. switching points, lighting lamps etc, the cpus would “exchange tokens” and compare… both tokens should be the same and were different values for every key stage in the program, diligently logged and maintained.

If the tokens didn’t match then something was badly wrong and BOTH boards called a routine called “hari_kari” which surged 12V through a fuse and took the board offline immediately.

Nice name :slight_smile:

I guess there were other boards in standby compensating …

Dan

You would hope so wouldn’t you!

Have you tried if (var = CONSTANT) with a recent compiler. You get a warning. I’ve worked at places where the coding standard forbids CONSTANT == var and the compiler is forced to turn that warning into an error so it doesn’t compile. Being a Prolog programmer I’m quite happy with symmetric relations, if your programmers have a problem with “CONSTANT == var” then maybe you need new programmers!

One of the most interesting programming entries on Wikipedia is the Immunity-aware one. I didn’t know it was a thing but had seen a fair few of the examples in my travels. It’s actually a good read:

1 Like