Legacy C: function declarations

I originally learned C/C++ in the mid-90s by reading a combination of C and C++ books and then until recently continued to program in C++ using features common to both. Because of this I missed or forgot several differences between the two languages, one of which I only became aware of recently.

void foo();

void foo(int i)
{
    ...
}

void main(void)
{
    foo();
}

In C the above code will compile, link and run, with undefined results. In C++ you’ll get a link error.
The difference comes about because firstly in C a function declaration with no parameters isn’t a prototype; that is, an empty parameter list means that no information is available about what parameters that function accepts; this is in contrast to C++ where an empty declaration is also a prototype specifying that the function takes no parameters – that is, there’s an implicit ‘void’. The second difference of course results from the fact that C++ allows function overloading (using name mangling) whereas C doesn’t – every function name has to be unique. More differences like these are listed in Bjarne Stroustrup’s paper at http://www.research.att.com/~bs/sibling_rivalry.pdf

If you’re using GCC, -Wall won’t catch this – you have to use -Wstrict-prototypes. Since such declarations have been deprecated since 1989 (C89), code that’s still using them should probably be fixed. Unlike C99, every compiler implements C89 since it was the C standard.

Posted in Uncategorized | Comments Off

Programming Windows Forms

System.Windows.Forms is the namespace in .NET that contains all the graphical components available for use by an application [until .NET 3.0 at least]. Unfortunately while Visual Studio provides a simple means to throw together a WinForms application it’s all too easy to end up with very complex code which suffers from seemingly unexplainable crashes.

The problem is that the CLR (Common Language Runtime, the thing that hosts the .NET bytecode) runs within a COM (Component Object Model) server that runs atop the Win32 API; thus you have to consider many of the same issues in .NET as you do when programming in C/C++ for Win32.

When Visual Studio creates an initial Windows Forms application, you’ll find it creates a class

public class MyClass


with a constructor

public MyClass()


I’m not sure why they use that declaration by default: you can change it to

public sealed class MyClass


with a private constructor. The only way people would be able to inherit from an executable is by renaming it from .exe to .dll; since you don’t want people doing that, make it sealed. Likewise, there’s no need for a public constructor, since you’ll be calling it from within your main method which is within your class.

When you get around to creating controls on your new form and adding events, it’s all too easy just to go right ahead and fill in the implementation right there. If you do this, you’ll end up with a class which rapidly gets out of control: at its worst, you could end up with a single class which is many thousands of lines long and contains hundreds of member variables. This is bad. If you put some thought into the design up-front, then it makes life a lot easier in future.

Do as little as possible in the UI layer, since Visual Studio already puts a lot of code in there already. .NET doesn’t really use resources (c.f. resource forks in MacOS) except to store the version information and icons, and so it creates the GUI by running initialization methods which are created at design-time and stored along with your code. In .NET all the initialization code, along with UI control variables, get put into your top-level class. .NET 2.0 improves the situation a little bit by at least putting all that code into a separate file as part of a “partial” class which gets merged with your UI class during compilation; this means all the setup code gets hidden in another file that shouldn’t be edited manually. I consider it a mis-feature though, since it seems there’s something broken if you have to have such big classes that they have to be split between multiple files. I have the same issue with the #region token which allows you to collapse regions of code; all it does is encourage you to write badly-written, rambling methods and hide it all under a single line (see C# Regions Considered Harmful).

As soon as something in the UI changes, try and store that fact in another class. This helps prevent having to ‘screen-scrape’ by constantly referring to UI variables to get their values throughout the program.

One of the things with .NET that fairly quickly becomes an issue with any moderately sized application is that all programs are single-threaded by default. If you want to do anything which takes more than about 250ms, you need to learn about threading, invoking and locking. Creating a new thread in .NET is very simple: all you need is

using System.Threading;

Thread t = new Thread(new ThreadStart(YourThreadMethod));
t.Name = "Worker Thread";
t.IsBackground = [false,true];
t.Start();

The method YourThreadMethod will now be run in a separate thread. Setting IsBackground to true will mean that if the other threads exit (e.g someone closes the application window) the thread will be terminated automatically; setting it to false means the application will remain alive until the thread finishes its work. A fairly fundamental thing to remember is that you cannot access any UI controls (even to read their values) in your own thread; doing so will work most of the time [in .NET 1.1; .NET 2.0 throws an exception], but will result in random crashes. If you want to access the UI, you have to Invoke onto the UI thread like this:

private void UIAccess()
{
    if (<SomeUIControl>.InvokeRequired)
    {
        <SomeUIControl>.BeginInvoke(new MethodInvoker(UIAccess));
        return;
    }

    // now, continue with updating the UI
}

What this does is, if you’re not already on the GUI thread then InvokeRequired will be true. BeginInvoke posts a message to the Windows message queue, and your method will be called again at some time in the future. Depending on how busy Windows is, it may be anything from microseconds to a couple of hundred milliseconds later – though usually you’ll get called back within about 20ms.

The reason threads can’t access UI controls is because Windows Forms code in the framework is mostly wrappers around Win32 [1] and the native controls are not thread-safe.

Another consideration when using threads in .NET is whether or not you’re going to be invoking COM components. Threads are by default created in the MTA (Multi Threaded Apartment) but if you’re going to be using a COM object that requires an STA (Single Threaded Apartment) you can change the default by setting the Thread.ApartmentState property.

[1] http://www.shawnburke.com/archive/2005/02/03/shipping-windows-forms-source-for-.net-framework-2.0-thanks-for.aspx

Posted in Windows | Comments Off

C and sequence points

In recent years GCC, the GNU compiler, has gained many more diagnostic warnings both at standard warning levels such as -Wall and with the addition of new flags such as -Warray-bounds. While it can’t match static analysis tools, it can point out several potential flaws in the code that can reduce portability or introduce subtle bugs.

One of the assumptions that many programmers have is that the right hand side of an expression is evaluated before the left hand side. It turns out that the C standard defines several ‘sequence points’ between which operations are guaranteed to have been carried out, and the equals sign isn’t one of them. While most compilers will do the expected thing, it’s in theory possible that one exists which evaluates the LHS before the RHS. Therefore if you update a variable and use its value on both sides, new versions of GCC will produce a warning that the operation is undefined:


1 int main(void)
2 {
3         char c[2];
4         char *p = c;
5         *p++ = p[0];
6         return 0;
7 }

> cc -Wall -o test test.c
test.c: In function 'main':
test.c:5: warning: operation on 'p' may be undefined
>

While outdated, The C Book (it’s out of print but has been made available online) has a good overview of sequence points.

Posted in Uncategorized | Comments Off

fdisk.exe -> diskpart.exe

I’ve just come across the DiskPart command in Vista; apparently it’s in XP too. It’s handy because it’s more flexible than the GUI tool. For example, to mark a partition as active:

DISKPART> list disk

Disk ### Status Size Free Dyn Gpt
——– ———- ——- ——- — —
* Disk 0 Online 112 GB 2520 KB

DISKPART> list partition

Partition ### Type Size Offset
————- —————- ——- ——-
Partition 1 Primary 78 GB 1024 KB
* Partition 2 Primary 34 GB 78 GB

DISKPART> select disk 0
Disk 0 is now the selected disk.
DISKPART> select partition 2
Partition 2 is now the selected partition.
DISKPART> active
DiskPart marked the current partition as active.
DISKPART>

I never knew what happened to fdisk.exe from Win9x, but it seems it transmogrified into diskpart.

Posted in Windows | Comments Off

Windows XP and disabling the automatic reboot nag

Many people get annoyed by the way Windows prompts them to reboot after installing updates – the “Reboot – Now or Later” prompt keeps re-appearing every 10 minutes when you’re not ready to reboot quite yet. Well there is a way to stop Windows nagging you to reboot…

Start -> Run…
Type gpedit.msc and hit OK
Open Computer Administration -> Administrative Templates -> Windows Components -> Windows Updates
Double-click “Re-prompt for restart with scheduled installations”
Set it to Enabled, and set the “Restart time (minutes)” to something big, like 1440 minutes.

Windows will now only prompt you to restart every 24 hours – 144 times less frequently!

Posted in Windows | Comments Off

Debugging Windows

The next time Windows crashes, you can learn what caused it, so instead of cursing Windows you can try to fix it by updating a specific driver. Of course it is possible that Windows will be completely mangled when it does crash, but I find I usually get good data from the crash dumps.

By default, Windows saves a “minidump” when it crashes; this contains register contents and a stack trace. It’s also possible to configure it to dump the kernel memory, or the complete memory in the system; these are more useful for postmortem debugging of drivers which are being developed, or if more components are causing a crash (for example, I recently had a recurrent crash caused by a virtual FS driver and an anti-virus driver). If you’re not getting a full analysis using a “small memory dump” then you could try dumping the kernel memory. Dumping the entire memory contents is something which should be avoided, especially on modern PCs with a gigabyte or two of memory!

To change crash dump settings, go to the Control Panel -> System -> Advanced -> [Startup and Recovery] Settings . Under Write Debugging Information, the “Small memory dump” is a minidump, while you can also select kernel and entire dumps.

To get started, obtain WinDBG from the Debugging Tools for Windows. Load WinDBG, and under File -> Symbol File Path, enter “SRV*c:websymbols*http://msdl.microsoft.com/download/symbols” (without quotes) – this informs WinDBG to download OS debug symbols from the Microsoft site and put them in C:websymbols . Next, open a minidump crash dump: File -> Open Crash Dump… and select the file from C:WINDOWSMinidump[Minidump file] If prompted to save the current workspace, choose No. WinDBG will proceed to load the symbols and do an initial analysis: it may tell you what the crash was probably caused by, but this doesn’t give us much information. When it’s finished the initial loading, you’ll see a KD> prompt at the bottom of the screen. Into this box, type

!analyze -v

Windows will do a complete verbose analysis and dump all the information it has. I find Windows tends to crash when I’m torrenting lots of files, so I analyzed one of my minidumps:

Microsoft (R) Windows Debugger Version 6.6.0007.5
Copyright (c) Microsoft Corporation. All rights reserved.

Loading Dump File [C:WINDOWSMinidumpMini031907-02.dmp]
Mini Kernel Dump File: Only registers and stack trace are available

Symbol search path is: SRV*c:websymbols*http://msdl.microsoft.com/download/symbols
Executable search path is:
Windows XP Kernel Version 2600 (Service Pack 2) UP Free x86 compatible
Product: WinNt, suite: TerminalServer SingleUserTS
Built by: 2600.xpsp_sp2_gdr.061219-0316
Kernel base = 0x804d7000 PsLoadedModuleList = 0x8055a620
Debug session time: Mon Mar 19 21:18:41.859 2007 (GMT+1)
System Uptime: 0 days 0:22:43.468
Loading Kernel Symbols
………………………………….

…………………………………………………………………………………
Loading User Symbols
Loading unloaded module list
……..
*******************************************************************************
* *
* Bugcheck Analysis *
* *
*******************************************************************************

Use !analyze -v to get detailed debugging information.

BugCheck 100000D1, {400, 2, 0, f768aa96}

Probably caused by : FA312nd5.sys ( FA312nd5!SendNdisPacket+180 )

Followup: MachineOwner
———

kd> !analyze -v
*******************************************************************************
* *
* Bugcheck Analysis *
* *
*******************************************************************************

DRIVER_IRQL_NOT_LESS_OR_EQUAL (d1)
An attempt was made to access a pageable (or completely invalid) address at an
interrupt request level (IRQL) that is too high. This is usually
caused by drivers using improper addresses.
If kernel debugger is available get stack backtrace.
Arguments:
Arg1: 00000400, memory referenced
Arg2: 00000002, IRQL
Arg3: 00000000, value 0 = read operation, 1 = write operation
Arg4: f768aa96, address which referenced memory

Debugging Details:
——————

READ_ADDRESS: 00000400

CURRENT_IRQL: 2

FAULTING_IP:
NDIS!NdisMStartBufferPhysicalMapping+10
f768aa96 8b8700040000 mov eax,dword ptr [edi+400h]

CUSTOMER_CRASH_COUNT: 2

DEFAULT_BUCKET_ID: DRIVER_FAULT

BUGCHECK_STR: 0xD1

PROCESS_NAME: Idle

LAST_CONTROL_TRANSFER: from f7cd6c64 to f768aa96

STACK_TEXT:
8054fd68 f7cd6c64 00000000 86327b1c 00000000 NDIS!NdisMStartBufferPhysicalMapping+0×10
8054fe0c f7cd6a98 86345000 00000000 86653b00 FA312nd5!SendNdisPacket+0×180
8054fe24 f76866bd 86345000 8054fe44 00000001 FA312nd5!EuphyterSendPackets+0xa4
8054fea0 f7688f0f 00000000 86653ad0 86117401 NDIS!ndisMStartSendPackets+0×228
8054fec4 f7684f02 00000000 00000001 86570788 NDIS!ndisMProcessDeferred+0×39
8054fee8 f7000528 86570788 00000000 861174a8 NDIS!ndisMSend+0x1cf
8054ff24 f766e985 8658e970 861174e0 00000002 psched!MpSend+0×706
8054ff4c f3d53d00 864d36a0 861174e0 864d43c0 NDIS!ndisMSendX+0x1d6
8054ff74 f3d538ce 864d43c0 861174e0 866b15e0 tcpip!ARPSendData+0×198
8054ffa0 f3d5370a 864d43c0 8054ff02 00000001 tcpip!ARPTransmit+0×193
8054ffd0 f3d534a9 86583008 010a000a 861174e0 tcpip!SendIPPacket+0x18e
8055011c f3d58da8 f3d91698 85e7a3f8 85e7a390 tcpip!IPTransmit+0x287f
80550188 f3d58365 f20c5de8 00000002 00000000 tcpip!TCPSend+0x5d8
805501ac f3d50a08 00000002 00000002 805501d8 tcpip!ProcessPerCpuTCBDelayQ+0×95
805501e0 f3d50b97 00000002 00000001 80550304 tcpip!ProcessTCBDelayQ+0xc4
80550254 f3d503ec f3d98ae0 00000000 80550380 tcpip!TCBTimeout+0xb94
80550264 804dc4fd f3d98af0 f3d98ae0 c98507d6 tcpip!TCBTimeoutdpc+0xf
80550380 804dc378 80559080 80558e20 ffdff000 nt!KiTimerListExpire+0×122
805503ac 804dbbd4 80559480 00000000 000151ac nt!KiTimerExpiration+0xaf
805503c0 80558e20 ffdffc50 00000000 00000000 nt!KiRetireDpcList+0×46
805503d0 804dbb4d 00000000 0000000e 00000000 nt!KiIdleThread0
805503d4 00000000 0000000e 00000000 00000000 nt!KiIdleLoop+0×26

STACK_COMMAND: kb

FOLLOWUP_IP:
FA312nd5!SendNdisPacket+180
f7cd6c64 395de0 cmp dword ptr [ebp-20h],ebx

SYMBOL_STACK_INDEX: 1

FOLLOWUP_NAME: MachineOwner

MODULE_NAME: FA312nd5

IMAGE_NAME: FA312nd5.sys

DEBUG_FLR_IMAGE_TIMESTAMP: 3a844532

SYMBOL_NAME: FA312nd5!SendNdisPacket+180

FAILURE_BUCKET_ID: 0xD1_FA312nd5!SendNdisPacket+180

BUCKET_ID: 0xD1_FA312nd5!SendNdisPacket+180

Followup: MachineOwner
———

From this, you can clearly see that the blame lies with FA312nd5.sys, the driver for my FA311 network card: it was trying to read from address 0×400, which is almost certainly invalid.

So the next time Windows crashes with the infamous IRQL_NOT_LESS_OR_EQUAL BSOD (or any other error), you’ll know how to find out what the culprit is, and which driver to check for updates.

Posted in Windows | Comments Off

Microsoft vs. C99

The C language is a very old, going back to the days before personal computers, before the time of operating systems as we currently know them.

It was devised in the early 1970s as a systems implementation language, a way to avoid having to program an operating system entirely in machine or assembly code; the name comes from its predecessor, B. At the time it was designed, both computer memory and processing time were very valuable commodities, and so the classic terseness of C was born.

The first real standardisation to the language was done in the late 80s; in 1989 ANSI (American National Standards Institute) published its standard, while in 1990 ISO revised the standard. Between them, this new standard of the C language became known as C89. Every compiler which is available today supports this standard, whatever platform or operating system it’s on.

In the intervening years, C not so much matured as started to show its age with its lack of features found in modern languages, such as single-line comments, declare-anywhere variables, and a number of other important features; in the meantime, C++ had grown up and was now a full superset of C – because of this, many programmers switched over from C to C++ simply by renaming .c files to .cpp and letting the compiler do the rest of the work. That wasn’t good enough for some people, though – there were people who were still writing operating systems, and they needed to keep using pure C; they couldn’t use C++ with all its exceptions and complex workings. For them, they created workarounds to the limitations of C by typedef’ing and macros and a number of other ‘hacks’.

In fact, even C++ had a fairly important limitation which only becomes apparent when you try and do systems-level programming; it lacks a precise definition of its data types! For most uses this isn’t a problem – after all, who usually cares whether an ‘int’ can hold 16 million or 4 billion, either way it’s a big number which you’re only likely to hit if you’re doing scientific or financial work. For systems people, though, it is a problem – for example the ATA system is defined by having a number of commands which take a structure consisting of a number of 32-bit elements. So, how to represent a 32-bit integer? The solution has typically been to typedef a u_int32_t as an ‘unsigned int’, which has worked and should continue to work in the future. However, some unlucky souls decided to gamble on a ‘long’ being 32-bit, which was unwise even as long ago as 1993 when DEC created the 64-bit Alpha CPU. What we are seeing as we move into a world of a single platform having both 32-bit (x86) and 64-bit (x86-64) architectures is code which used to work is now failing due to short-sighted programmers and standards committees.

So what has this all got to do with the C language, you may ask? Well, in 1999 the ISO committee in charge of the C standard re-convened and overhauled updated the language in a number of places. While a lot of this was simply bringing it up-to-date with C++ with regards to comments, variable declaration and the like, it also added a number of incompatible new features. A couple of these, such as named structure initialisation (eg struct FILE f = {.fsize=0};) and variable-length arrays (eg int f1(int bsize) { char buffer[bsize]; }) were handy to have, the systems folk finally got a standard way to express integer sizes. Although they are still usually implented as typedefs, people using C99 now have access to several new integral types, including (but not limited to) int8_t, int16_t, int32_t and even int64_t. This means that programmers don’t have to second-guess future developments in machine architecture; by using one of the predefined types they are sheltered from new technologies. The addition of a 64-bit data type is a nod to the gcc people who for many years used an unofficial ‘long long’ as a way to represent a 64-bit number – C99 adds it as an official type in addition to having the int64_t specifier.

With all the advantages C99 appears to have over C89, you’d be mistaken for thinking the compiler writers would have gone running to update their compilers to take advantage of the new features; after all, many of them had unofficial support for them in the form of compiler-specific extensions, so it should be relatively straightforward to bring their compiler into compliance. Unfortunately, while the GNU people have done just that, a fairly few big companies seem completely unaware of it. What we’ve seen is the GNU folk bring out version 3 of their suite with incremental support for C99, with support slowly improving until now, at version 3.4 support is relatively complete. Intel have also, as usual, updated their brilliant ICC compiler suite for both Windows and Linux to have C99 support – from what I gather, the compiler itself is fully compliant. With both open-source and commercial sides covered, there are two companies left – Borland and Microsoft, both of whom target the Windows market.

Borland have been very quiet on the compiler side, and I am unaware what (if any) work they’re doing to update it.

I have worked with Visual Studio for a while now, and was disappointed to learn that the 2003 version compiler didn’t have support for C99 – in fact, Microsoft appear to discourage C programming in favour of C++, with a certain effort required to get a raw C file. The excuse they have is that they\’re brought out C# and have thus been fairly busy getting that up and running. I would be disappointed if Microsoft chose to completely abandon C support in their suite, but it looks as though that may happen – if the rumours are true, we may be coerced into only running Managed (C# and C++) code on future versions of Windows.

All in all, I think C99 is a major step forward for the C language – it brings clear advantages over C++ for people who don’t want/need an OO language; it continues to ensure programming in C is a pleasure.

Posted in Windows | Comments Off