Skip to content

On Compiling Other People’s Code and the Downside of Uppity C Compilers

January 11, 2015

I’m continuing to try to re-build LCC1802 for my fine new MacBook. Today I pushed on recompiling the excellent AS assembler that I use to translate the compiler’s output to object code.

Once I got the compiler parameters right and fixed some minor objections it built ok but blew up at run time with the unhelpful message “Abort trap: 6”. Googling around got me little but using lldb i pinned it down to the following C statement:

strcpy(Dest,Dest+7);

It looks a bit funny because the operands overlap but the intent is clearly to remove the 1st 7 characters of the string Dest. Copying Dest to Dest+7 could be bad because you could overwrite something but Dest+7 to Dest should be ok. It turns out, though, that the llvm/c runtime is CHECKING for the overlap and aborting with the “abort trap 6” message.

This is not my experience with C compilers. I can see warning at compile time but checking and aborting at run time does NOT seem useful.

I’m able to get around this by redefining strcpy as

#define strcpy(a,b) memmove(a, b, strlen(b) + 1)

Sure, because that’s a LOT safer!

Advertisements

From → LLVM

One Comment
  1. John Payson permalink

    Hyper-modern C is very different from the language Dennis Ritchie invented that was popular in the 1990s. In the days before the C Standard, it was commonplace for various actions (e.g. integer overflow) to have consequences that were defined on some platforms but not others, and the authors of the C Standard saw no need to mandate that platforms that could cheaply guarantee such behaviors must do so. Platforms which could cheaply guarantee such behaviors were already doing so even before the C89 Standard was published, and there was no reason to expect that they wouldn’t continue doing so.

    Unfortunately, hyper-modern C takes the philosophy that any code which relies upon anything not mandated by the Standard should be considered broken even if 100% of compilers to date for all platforms that even remotely handle the target would have worked consistently, and programmers should thank compilers for forcing them to fix their “broken” code. I’m not sure about clang, but depending upon calling context, gcc will get creative with things like:

    // Assume “int” is 32 bits and “short” is 16
    unsigned int mult(unsigned short x, unsigned short y) { return x*y; }

    // Assume “int” and “long” are both 32 bits
    void set_value(long *value) { *value = 5678;}
    void set_value32(int32 *value) { set_value((long*)value); }

    The former example will sometimes malfunction if the product is in the range INT_MAX+1u
    to UINT_MAX; the latter example may fail to recognize that set_value32() will modify the
    object whose address is passed in since gcc considers “int32_t” and “long” as different
    types even when both have the same size and representation.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: