Cyclone (programming language)
The Cyclone programming language was intended to be a safe dialect of the C language. It avoids buffer overflows and other vulnerabilities that are possible in C programs by design, without losing the power and convenience of C as a tool for system programming. It is no longer supported by its original developers, with the reference tooling not supporting 64-bit platforms. The Rust language is mentioned by the original developers for having integrated many of the same ideas Cyclone had.
Cyclone development was started as a joint project of Trevor Jim from AT&T Labs Research and Greg Morrisett's group at Cornell University in 2001. Version 1.0 was released on May 8, 2006.
Language features
Cyclone attempts to avoid some of the common pitfalls of C, while still maintaining its look and performance. To this end, Cyclone places the following limits on programs:NULL checks are inserted to prevent segmentation faults- Pointer arithmetic is limited
- Pointers must be initialized before use
- Dangling pointers are prevented through region analysis and limits on
free() - Only "safe" casts and unions are allowed
-
gotointo scopes is disallowed -
switchlabels in different scopes are disallowed - Pointer-returning functions must execute
return -
setjmpandlongjmpare not supported
- Never-
NULLpointers do not requireNULLchecks - "Fat" pointers support pointer arithmetic with run-time bounds checking
- Growable regions support a form of safe manual memory management
- Garbage collection for heap-allocated values
- Smart pointers, such as unique pointers
- Region-based memory management
- Tagged unions support type-varying arguments
- Injections help automate the use of tagged unions for programmers
- Polymorphism replaces some uses of
void* - Variadic arguments are implemented as fat pointers
- Exceptions replace some uses of
setjmpandlongjmp - Namespaces
- Type inference
- Pattern matching
- Templates, parameterized types
Pointer types
Cyclone implements three kinds of pointer:* @, and?.The purpose of introducing these new pointer types is to avoid common problems when using pointers. Take for instance a function, called
foo that takes a pointer to an int:int foo;
Although the person who wrote the function
foo could have inserted NULL checks, let us assume that for performance reasons they did not. Calling foo; will result in undefined behavior. To avoid such problems, Cyclone introduces the @ pointer type, which can never be NULL. Thus, the "safe" version of foo would be:int foo;
This tells the Cyclone compiler that the argument to
foo should never be NULL, avoiding the aforementioned undefined behavior. The simple change of * to @ saves the programmer from having to write NULL checks and the operating system from having to trap NULL pointer dereferences. This extra limit, however, can be a rather large stumbling block for most C programmers, who are used to being able to manipulate their pointers directly with arithmetic. Although this is desirable, it can lead to buffer overflows and other "off-by-one"-style mistakes. To avoid this, the ? pointer type is delimited by a known bound, the size of the array. Although this adds overhead due to the extra information stored about the pointer, it improves safety and security. Take for instance a simple strlen function, written in C:int strlen
This function assumes that the string being passed in is terminated by
'\0'. However, what would happen if were passed to this string? This is perfectly legal in C, yet would cause strlen to iterate through memory not necessarily associated with the string s. There are functions, such as strnlen which can be used to avoid such problems, but these functions are not standard with every implementation of ANSI C. The Cyclone version of strlen is not so different from the C version:int strlen
Here,
strlen bounds itself by the length of the array passed to it, thus not going over the actual length. Each of the kinds of pointer type can be safely cast to each of the others, and arrays and strings are automatically cast to ? by the compiler.Dangling pointers and region analysis
Consider the following code, in C:char* itoa
The function
itoa allocates an array of chars buf on the stack and returns a pointer to the start of buf. However, the memory used on the stack for buf is deallocated when the function returns, so the returned value cannot be used safely outside of the function. While GNU Compiler Collection and other compilers will warn about such code, the following will typically compile without warnings:char* itoa
GNU Compiler Collection can produce warnings for such code as a side-effect of option or, but there are no guarantees that all such errors will be detected.
Cyclone does regional analysis of each segment of code, preventing dangling pointers, such as the one returned from this version of
itoa. All of the local variables in a given scope are considered to be part of the same region, separate from the heap or any other local region. Thus, when analyzing itoa, the Cyclone compiler would see that z is a pointer into the local stack, and would report an error.Fat pointers
A fat pointer is used for allowing pointer arithmetic. Fat pointers must be declared with@fat. For example, argv is often declared as type char**, or alternatively thought of as char*. In Cyclone, this is instead expressed as char*@fat*@fat.Cyclone instead allows
? to represent *@fat. Thus, the two declarations are equivalent:int main;
// equivalent to the more verbose declaration
int main;
Parameterized types
Similar to templates in C++, Cyclone has a form of generic programming.typedef struct LinkedList<`a> LinkedList<`a>;
//...
LinkedList
An "abstract" type can be used, that encapsulates the implementation type but ensures the definition does not leak to the client.
abstract struct Queue<`a> ;
extern struct Queue<`a>;
Namespaces
Namespaces exist in Cyclone, similar to C++. Namespaces are used to avoid name clashes in code, and follow the:: notation as in C++. Namespaces can be nested.namespace foo
namespace bar
Pattern matching
Pattern-matching can be accomplished in Cyclone like so:int g
A
let declaration is used to match a pattern and expression.typedef struct Pair Pair;
void f
Type inference
In Cyclone, rather than usingauto like C and C++ or var in Java and C#, Cyclone instead uses _ to denote a type-inferred variable._ x = malloc;
// instead of:
SomeType x = malloc;
_ myNumber = 100; // inferred to int
Exceptions
Cyclone features exceptions. An uncaught exception will halt the program. Like Java, Cyclone features a null pointer exception, calledNull_Exception.typedef FILE File;
File* f = fopen;
try catch
One can also manually throw exceptions:
throw new Null_Exception;