Can repeating C source code causing compile errors? - c

As per another question I had asked earlier I think I may have found my problem but I need an experts eye.
I found the file /net/ipv4/tcp_zero_copy.c which was causing a compile failure of my kernel.
I no very little about C or C++, when I look at the file in my C/C++ editor it looks like the same code is repeating over over over (I think 4 times).
My question is simple;
Would that be enough to cause a problem with the compiler? If the same code showed up over and over in the same file?
Here is the source code of the file (from end to end 148 lines in total);
/*
* Support routines for TCP zero copy transmit
*
* Created by Vladislav Bolkhovitin
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*/
#include <linux/skbuff.h>
net_get_page_callback_t net_get_page_callback __read_mostly;
EXPORT_SYMBOL(net_get_page_callback);
net_put_page_callback_t net_put_page_callback __read_mostly;
EXPORT_SYMBOL(net_put_page_callback);
/*
* Caller of this function must ensure that at the moment when it's called
* there are no pages in the system with net_priv field set to non-zero
* value. Hence, this function, as well as net_get_page() and net_put_page(),
* don't need any protection.
*/
int net_set_get_put_page_callbacks(
net_get_page_callback_t get_callback,
net_put_page_callback_t put_callback)
{
int res = 0;
if ((net_get_page_callback != NULL) && (get_callback != NULL) &&
(net_get_page_callback != get_callback)) {
res = -EBUSY;
goto out;
}
if ((net_put_page_callback != NULL) && (put_callback != NULL) &&
(net_put_page_callback != put_callback)) {
res = -EBUSY;
goto out;
}
net_get_page_callback = get_callback;
net_put_page_callback = put_callback;
out:
return res;
}
EXPORT_SYMBOL(net_set_get_put_page_callbacks);
/*
* Support routines for TCP zero copy transmit
*
* Created by Vladislav Bolkhovitin
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*/
#include <linux/skbuff.h>
net_get_page_callback_t net_get_page_callback __read_mostly;
EXPORT_SYMBOL(net_get_page_callback);
net_put_page_callback_t net_put_page_callback __read_mostly;
EXPORT_SYMBOL(net_put_page_callback);
/*
* Caller of this function must ensure that at the moment when it's called
* there are no pages in the system with net_priv field set to non-zero
* value. Hence, this function, as well as net_get_page() and net_put_page(),
* don't need any protection.
*/
int net_set_get_put_page_callbacks(
net_get_page_callback_t get_callback,
net_put_page_callback_t put_callback)
{
int res = 0;
if ((net_get_page_callback != NULL) && (get_callback != NULL) &&
(net_get_page_callback != get_callback)) {
res = -EBUSY;
goto out;
}
if ((net_put_page_callback != NULL) && (put_callback != NULL) &&
(net_put_page_callback != put_callback)) {
res = -EBUSY;
goto out;
}
net_get_page_callback = get_callback;
net_put_page_callback = put_callback;
out:
return res;
}
EXPORT_SYMBOL(net_set_get_put_page_callbacks);
/*
* Support routines for TCP zero copy transmit
*
* Created by Vladislav Bolkhovitin
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*/
#include <linux/skbuff.h>
net_get_page_callback_t net_get_page_callback __read_mostly;
EXPORT_SYMBOL(net_get_page_callback);
net_put_page_callback_t net_put_page_callback __read_mostly;
EXPORT_SYMBOL(net_put_page_callback);
/*
* Caller of this function must ensure that at the moment when it's called
* there are no pages in the system with net_priv field set to non-zero
* value. Hence, this function, as well as net_get_page() and net_put_page(),
* don't need any protection.
*/
int net_set_get_put_page_callbacks(
net_get_page_callback_t get_callback,
net_put_page_callback_t put_callback)
{
int res = 0;
if ((net_get_page_callback != NULL) && (get_callback != NULL) &&
(net_get_page_callback != get_callback)) {
res = -EBUSY;
goto out;
}
if ((net_put_page_callback != NULL) && (put_callback != NULL) &&
(net_put_page_callback != put_callback)) {
res = -EBUSY;
goto out;
}
net_get_page_callback = get_callback;
net_put_page_callback = put_callback;
out:
return res;
}
EXPORT_SYMBOL(net_set_get_put_page_callbacks);
** EDIT **
Also I just used Notepad++ to compare the individual blocks of code where it looked like they ended. According to the compare tool all 3 block match each other.
Here is the compiler output from the place it died to the command prompt it returned to me.
CC net/ipv4/tcp_zero_copy.o
net/ipv4/tcp_zero_copy.c:63:1: error: redefinition of â__kcrctab_net_get_page_callbackâ
net/ipv4/tcp_zero_copy.c:14:1: note: previous definition of â__kcrctab_net_get_page_callbackâ was here
net/ipv4/tcp_zero_copy.c:63:1: error: redefinition of â__kstrtab_net_get_page_callbackâ
net/ipv4/tcp_zero_copy.c:14:1: note: previous definition of â__kstrtab_net_get_page_callbackâ was here
net/ipv4/tcp_zero_copy.c:63:1: error: redefinition of â__ksymtab_net_get_page_callbackâ
net/ipv4/tcp_zero_copy.c:14:1: note: previous definition of â__ksymtab_net_get_page_callbackâ was here
net/ipv4/tcp_zero_copy.c:66:1: error: redefinition of â__kcrctab_net_put_page_callbackâ
net/ipv4/tcp_zero_copy.c:17:1: note: previous definition of â__kcrctab_net_put_page_callbackâ was here
net/ipv4/tcp_zero_copy.c:66:1: error: redefinition of â__kstrtab_net_put_page_callbackâ
net/ipv4/tcp_zero_copy.c:17:1: note: previous definition of â__kstrtab_net_put_page_callbackâ was here
net/ipv4/tcp_zero_copy.c:66:1: error: redefinition of â__ksymtab_net_put_page_callbackâ
net/ipv4/tcp_zero_copy.c:17:1: note: previous definition of â__ksymtab_net_put_page_callbackâ was here
net/ipv4/tcp_zero_copy.c:74:5: error: redefinition of ânet_set_get_put_page_callbacksâ
net/ipv4/tcp_zero_copy.c:25:5: note: previous definition of ânet_set_get_put_page_callbacksâ was here
net/ipv4/tcp_zero_copy.c:98:1: error: redefinition of â__kcrctab_net_set_get_put_page_callbacksâ
net/ipv4/tcp_zero_copy.c:49:1: note: previous definition of â__kcrctab_net_set_get_put_page_callbacksâ was here
net/ipv4/tcp_zero_copy.c:98:1: error: redefinition of â__kstrtab_net_set_get_put_page_callbacksâ
net/ipv4/tcp_zero_copy.c:49:1: note: previous definition of â__kstrtab_net_set_get_put_page_callbacksâ was here
net/ipv4/tcp_zero_copy.c:98:1: error: redefinition of â__ksymtab_net_set_get_put_page_callbacksâ
net/ipv4/tcp_zero_copy.c:49:1: note: previous definition of â__ksymtab_net_set_get_put_page_callbacksâ was here
make[2]: *** [net/ipv4/tcp_zero_copy.o] Error 1
make[1]: *** [net/ipv4] Error 2
make: *** [net] Error 2
root#dev01:/usr/src/linux# ls

It depends on what is being repeated,
A function declaration repeated won't give any errors.
A function definition repeated would give errors.
A variable being created\defined with same name would give errors.
#2 & #3 give errors as they break the ODR(One Definition Rule).
void doSomething(); //no error
void doSomething();
void doSomething();
void doSomething()
{
}
int main()
{
int i; //error
int i;
doSomething();
return 1;
}
In this code:
net_get_page_callback_t net_get_page_callback __read_mostly;
defines an variable and doing so repeatedly, leads to multiple definition of same named variable and hence the redefinition error.

It is an error for a function to be multiply defined in a translation unit. That is what happens here. Try posting the first few error messages from compilation.

Related

Extent of MISRA C 2012 Directive 4.1: Runtime checks before pointer dereferencing in a library

MISRA C 2012 Directive 4.1 says that Run-time failures should be minimized and further states for pointer dereferencing that a pointer should be checked for NULL before it's dereferenced,
unless it's already known to be not NULL.
When writing a library performing simple operations, checking the input pointers in each library function
for NULL creates larger and therefore less understandable code even for simple operations.
For example below library computes the squared euclidian norm of a vector and gets used in a controller
/*** Option 1: Checking pointers ***/
Library:
/* file vector.c */
bool_t bVectorNormSq(float32_t pf32Vec[], uint8_t u8Len, float32_t *pf32NormSq)
{
uint8_t u8n;
bool bRet = false;
/* Check pointers */
if( (pf32Vec != NULL) && (pf32NormSq != NULL) )
{
*pf32NormSq = 0.0f;
for(u8n = 0U; u8n < u8Len; u8n++)
{
*pf32NormSq += (pf32Vec[u8n] * pf32Vec[u8n]);
}
bRet = true;
}
else
{
/* Do not alter pf32NormSq (unknown if valid pointer) */
bRet = false;
}
return bRet;
}
/* EOF */
Consumer of library:
/* file controller.c */
/* ... */
bool_t bControllerStep(void)
{
float32_t pf32MyVec[3] = { 0 };
float32_t f32MyNorm = 0.0f;
/* ... */
/* MISRA C 2012 Rule 17.7, Call will always be successful, thus return value not checked */
(void)bVectorNormSq(pf32MyVec, 3U, &f32MyNorm);
/* ... */
}
/* EOF */
/*** Option 2: Not checking pointer, responsibility to supply valid inputs placed on caller ***/
Library:
/* file vector.c */
/**
* #note This library assumes that valid pointers will be supplied,
* pointers are NOT checked before they are used.
*/
/* Assert macro expands to "(void)(CONDITION)" for NDEBUG defined */
#ifdef NDEBUG
VECTOR_ASSERT( CONDITION ) (void)(CONDITION)
#else
/* ... */
#endif /* NDEBUG */
float32_t f32VectorNormSq(float32_t pf32Vec[], uint8_t u8Len)
{
float32_t f32Norm = 0.0f;
uint8_t u8n = 0U;
VECTOR_ASSERT(pf32Vec!=NULL);
for(u8n = 0U; u8n < u8Len; u8n++)
{
f32NormSq += (pf32Vec[u8n] * pf32Vec[u8n]);
}
}
/* EOF */
Consumer of library:
/* file controller.c */
/* ... */
bool_t bControllerStep(void)
{
float32_t pf32MyVec[3] = { 0 };
float32_t f32MyNorm = 0.0f;
/* ... */
f32MyNorm = f32VectorNormSq(pf32MyVec, 3U);
/* ... */
}
/* EOF */
For option 1 the library function f32VectorNormSq() can be reasoned by the caller bControllerStep() to always execute successfully (return true),
because the array pf32MyVec is defined in the caller and pf32MyVec thus can't be NULL. Therefore the caller chooses to ignore the return value.
Above reasoning is likely to be the applicable for many uses of the library, resulting in callers
frequently ignoring return values for option 1. This could lead to a programmer being complacend in ignoring return values, even if they shouldn't, e.g. because a
zero division was detected by the library.
Opposed to this option 2 assumes the caller supplying valid pointers, documents this in the library /* #note...*/ and only uses a assert for NULL pointers to assist during development,
later to be disabled for deployment. In this option a Boolean return value being present highlights to the programmer that the library operation might fail for reasons
other than invalid pointers or incorrect other trivial inputs, e.g due to zero division and care should be taken before using the computed values,
avoiding the risk of complacency.
Therefore my question(s):
Is it situations as in the example shown compliant to MISRA C for a libary to neglect checking pointers or other trivial inputs?
Are there any additional conditions that have to be fullfilled, besides documenting the missing input checking in the source code, e.g. is a formal deviation needed?
Application background:
This is just an aerospace student with focus in control systems, trying to understand how things are done properly in the actual coding of control systems, by writing his own control algorithms as if they were running on the real thing i.e. by following standards like MISRA C.
Code written by me will NOT be going on a live system anytime soon, but for the purpose of your answers please consider this code as running on the actual system where a failure of the function is classified as catastrophic, .i.e. everybody dies.
I'm aware of the whole software and hardware engineering (SAE ARP4754, SAE ARP4761, DO-178C, ...) around the actual implementation process. This question is really just about the instructions executing on the hardware, not about the need for redudant & dissimilar hardware or requirements, reviews, testing, ...
EDIT:
The library in question is low in the code stack thus sanitizing code for inputs from the outside (sensors,...) can be expected to be present. I'm trying to avoid falling prey to Cargo cult programming by blindly following the rule "Always check all inputs".
Regarding Option 1 - how would you write the documentation to that function? Does this make sense:
bVectorNormSq
Description of what this function does here.
pf32Vec A pointer to an allocated array of [u8Len] that will-...
u8Len The size of the array [pf32Vec] in bytes.
...
Returns: true if successful, false in case pf32Vec was a null pointer.
It doesn't make sense. You already documented that pf32Vec must be a pointer to an allocated array so why would the usernot read that part, but read the part about return status? How are we even supposed to use this function?
bool result = bVectorNormSq(some_fishy_pointer, ...); // checks for null internally
if(result == false)
{
/* error: you passed a null pointer */
}
Why can't you instead write that very same code like this?
if(some_fishy_pointer == NULL)
{
/* handle the error instead of calling the function in the first place */
}
else
{
bVectorNormSq(some_fishy_pointer, ...); // does not check for null internally
}
It's the same amount of error checking, same amount of branches. Literally the only difference is the slower execution speed of the first version.
Also, your extra error checks add extra complexity which could in turn lead to extra bugs.
Potential bugs:
if( (pf32Vec = NULL) ||(pf32NormSq = NULL) )
or
if( (pf32Vec =! NULL) && (pf32NormSq != NULL) )
or (not just a potential bug):
bool_t ... bool bRet = false; ... return bRet;
Extra error checking is a good thing, but place it where it matters - sanitize data at the point where it gets assigned. Example:
const char* ptr = strstr(x,y);
if(ptr == NULL) // Correct! Check close to the location where the pointer is set
{}
...
some_function(ptr);
...
void some_function (const char* str)
{
if(str == NULL) // Not correct. This function has nothing to do with the strstr call.
}

C unused pointer parameter

I have found the following function definition in Linux source:
static int __ref kernel_init(void *unused)
{
int ret;
kernel_init_freeable();
/* need to finish all async __init code before freeing the memory */
async_synchronize_full();
ftrace_free_init_mem();
free_initmem();
mark_readonly();
/*
* Kernel mappings are now finalized - update the userspace page-table
* to finalize PTI.
*/
pti_finalize();
system_state = SYSTEM_RUNNING;
numa_default_policy();
rcu_end_inkernel_boot();
if (ramdisk_execute_command) {
ret = run_init_process(ramdisk_execute_command);
if (!ret)
return 0;
pr_err("Failed to execute %s (error %d)\n",
ramdisk_execute_command, ret);
}
/*
* We try each of these until one succeeds.
*
* The Bourne shell can be used instead of init if we are
* trying to recover a really broken machine.
*/
if (execute_command) {
ret = run_init_process(execute_command);
if (!ret)
return 0;
panic("Requested init %s failed (error %d).",
execute_command, ret);
}
if (!try_to_run_init_process("/sbin/init") ||
!try_to_run_init_process("/etc/init") ||
!try_to_run_init_process("/bin/init") ||
!try_to_run_init_process("/bin/sh"))
return 0;
panic("No working init found. Try passing init= option to kernel. "
"See Linux Documentation/admin-guide/init.rst for guidance.");
}
My question concerns the unused argument to the function. I have seen some other questions where one can use the GCC attribute specifier to declare the argument as unused and some other techniques, but this one looks like it would generate some weird compiler warnings since I see no usage of any suppression techniques here. Does anyone know what is the use of this argument here?
The unused parameter is there, because kernel_init is run as a kernel_thread which expects a pointer to int(void*) function as the first argument.
From here:
pid = kernel_thread(kernel_init, NULL, CLONE_FS);

nrf51 timer driver code bugs

I'm currently trying to make an application using the nrf51 development kit & I'm trying to use the timer driver, when I induled the C & H files of the driver I got some error :
static const nrf_drv_timer_config_t m_default_config[] = {// here it told me there is error #1
#if (TIMER0_ENABLED == 1)
NRF_DRV_TIMER_DEFAULT_CONFIG(0),
#endif
#if (TIMER1_ENABLED == 1)
NRF_DRV_TIMER_DEFAULT_CONFIG(1),
#endif
#if (TIMER2_ENABLED == 1)
NRF_DRV_TIMER_DEFAULT_CONFIG(2)
#endif
};
// here it told me there is error #2
ret_code_t nrf_drv_timer_init(nrf_drv_timer_t const * const p_instance,
nrf_drv_timer_config_t const * p_config,
nrf_timer_event_handler_t timer_event_handler)
{
ASSERT((p_instance->instance_id) < TIMER_INSTANCE_NUMBER);
ASSERT(TIMER_IS_BIT_WIDTH_VALID(p_instance->instance_id, p_config->bit_width));
if (m_cb[p_instance->instance_id].state != NRF_DRV_STATE_UNINITIALIZED)
{
return NRF_ERROR_INVALID_STATE; // timer already initialized
}
if (p_config == NULL)
{
p_config = &m_default_config[p_instance->instance_id];
}
#ifdef SOFTDEVICE_PRESENT
if (p_instance->p_reg == NRF_TIMER0)
{
return NRF_ERROR_INVALID_PARAM;
}
#endif
nrf_drv_common_irq_enable(p_instance->irq, p_config->interrupt_priority);
mp_contexts[p_instance->instance_id] = p_config->p_context;
if (timer_event_handler != NULL)
{
m_timer_event_handlers[p_instance->instance_id] = timer_event_handler;
}
else
{
return NRF_ERROR_INVALID_PARAM;
}
nrf_timer_mode_set(p_instance->p_reg, p_config->mode);
nrf_timer_bit_width_set(p_instance->p_reg, p_config->bit_width);
nrf_timer_frequency_set(p_instance->p_reg, p_config->frequency);
m_cb[p_instance->instance_id].state = NRF_DRV_STATE_INITIALIZED;
return NRF_SUCCESS;
}
the error #1 says that "an empty initializer is invalid for an array with unspecified bound"
the error #2 says that it expected an expression
I till now didn't use any of these functions in the main.c code, I'm just added the header files that will be used further.
Error 1: Apparently neither of TIMERx_ENABLED is 1, so the array will be empty. As it is const, there is no chance to initialize it later. That would also result in an array of zero elements, which is not allowed. Easiest might be to have an #else clause with a single null entry. However, I suspect you have to configure the stuff for your system first. Read the documentation.
Error 2: might be a follow up error, or one of the custom types are not defined - hard to say without more info, or the location the error is reported is simply not that of the actual error, or ... . Best is to fix the first error, then try again for error 2.
If you are using examples from nordic then the defines are either in nrf_drv_config.h or in the sdk_config.h for new versions of the nordic sdk.
You have to enable the timers by changing the TIMER_ENABLED define to 1. Then do the same for the timers you want to use.
You could make these defines yourself as other people have suggested.

SQLite: wrong call of sqlite3_prepare_v2 -> SIGSEGV

I've got stuck on my homework with SQLite. I use 2 columns; the first for product, the second for count. A user adds new products, which updates the count. We have to control, that the user doesn't add the same product again, or prevent him from picking more units than are available. We have to use it frequently, so I created functions:
int exists(char *param, sqlite3** ppDb) //0 if product exists
{
int error = 0;
char *a = NULL;
sqlite3_stmt **ppStmt = NULL;
const char **pzTail = NULL;
char *zSQL = sqlite3_mprintf("SELECT 'products' FROM 'table' WHERE 'products' LIKE '%q'", param);
//HERE IT FALS
error = sqlite3_prepare_v2(
*ppDb, /* Database handle */
zSQL, /* SQL statement, UTF-8 encoded */
(sizeof(zSQL)+1), /* Maximum length of zSql in bytes. */
ppStmt, /* OUT: Statement handle */
pzTail /* OUT: Pointer to unused portion of zSql */
);
sqlite3_free(zSQL);
a = (char*) sqlite3_column_text(*ppStmt, 0);
return strcmp(a, param); //0 if same -> product is in db yet
}
//similar one for count
Call
int main(int argc, const char *argv[])
{
sqlite3 *pDb;
int error = 0;
//parsing input
error = sqlite3_open(argv[1], &pDb);
if (error == 0)
{
sqlite3_exec(
pDb, /* An open database */
"CREATE TABLE 'table' ('products', 'quantity')", /* SQL */
0, /* Callback function */
NULL, /* 1st argument to callback */
NULL /* Error msg written here */
);
if (exists(param[1], &pDb) == 0)
{
fprintf (stderr, "ERROR: Product exists yet\n");
}
else
{
char *zSQL = sqlite3_mprintf("INSERT INTO 'table' VALUES ('%q', '0')", param[1]);
error = sqlite3_exec(
pDb, /* An open database */
zSQL, /* SQL to be evaluated */
0, /* Callback function */
NULL, /* 1st argument to callback */
NULL /* Error msg written here */
);
sqlite3_free(zSQL);
if (error == 0) printf("Added\n");
else printf("%i", error);
}
}
else return 1;
return 0;
}
It fails on sqlite3_prepare_v2. I expect there is a problem with the pointer on pDb, but I wasn't able to fix it (I'm not fan of pointers - too strong a tool for beginner). When it fails, the debugger stacked on line 93396 in sqlite3.c (*ppStmt = 0; - it writes somewhere, where it should'nt).
Compiled on linux x64:
gcc -std=c99 -Wall -pedantic -Wextra -Werror -DSQLITE_THREADSAFE=0 -ldl -o sqlite main.c sqlite3.c
Nothing wrong (if I've copied wrongly brackets, ignore it - it's not the problem), SQLite 3.7.14.1
Sorry for my English, I'm from Czech.
sqlite3_prepare_v2 wants to write the statement pointer into your output variable, but you are not giving it a pointer to this pointer variable, you are giving it a NULL pointer.
Use:
sqlite3_stmt *pStmt;
sqlite3_prepare_v2(..., &pStmt, ...);
Also note that identifiers should be quoted with "double quotes" or [brackets] or
`backticks`
but not with 'single quotes', which are used for literal strings.

Try catch statements in C

I was thinking today about the try/catch blocks existent in another languages. Googled for a while this but with no result. From what I know, there is not such a thing as try/catch in C. However, is there a way to "simulate" them?
Sure, there is assert and other tricks but nothing like try/catch, that also catch the raised exception. Thank you
C itself doesn't support exceptions but you can simulate them to a degree with setjmp and longjmp calls.
static jmp_buf s_jumpBuffer;
void Example() {
if (setjmp(s_jumpBuffer)) {
// The longjmp was executed and returned control here
printf("Exception happened here\n");
} else {
// Normal code execution starts here
Test();
}
}
void Test() {
// Rough equivalent of `throw`
longjmp(s_jumpBuffer, 42);
}
This website has a nice tutorial on how to simulate exceptions with setjmp and longjmp
http://www.di.unipi.it/~nids/docs/longjump_try_trow_catch.html
You use goto in C for similar error handling situations.
That is the closest equivalent of exceptions you can get in C.
Ok, I couldn't resist replying to this. Let me first say I don't think it's a good idea to simulate this in C as it really is a foreign concept to C.
We can use abuse the preprocessor and local stack variables to give use a limited version of C++ try/throw/catch.
Version 1 (local scope throws)
#include <stdbool.h>
#define try bool __HadError=false;
#define catch(x) ExitJmp:if(__HadError)
#define throw(x) {__HadError=true;goto ExitJmp;}
Version 1 is a local throw only (can't leave the function's scope). It does rely on C99's ability to declare variables in code (it should work in C89 if the try is first thing in the function).
This function just makes a local var so it knows if there was an error and uses a goto to jump to the catch block.
For example:
#include <stdio.h>
#include <stdbool.h>
#define try bool __HadError=false;
#define catch(x) ExitJmp:if(__HadError)
#define throw(x) {__HadError=true;goto ExitJmp;}
int main(void)
{
try
{
printf("One\n");
throw();
printf("Two\n");
}
catch(...)
{
printf("Error\n");
}
return 0;
}
This works out to something like:
int main(void)
{
bool HadError=false;
{
printf("One\n");
{
HadError=true;
goto ExitJmp;
}
printf("Two\n");
}
ExitJmp:
if(HadError)
{
printf("Error\n");
}
return 0;
}
Version 2 (scope jumping)
#include <stdbool.h>
#include <setjmp.h>
jmp_buf *g__ActiveBuf;
#define try jmp_buf __LocalJmpBuff;jmp_buf *__OldActiveBuf=g__ActiveBuf;bool __WasThrown=false;g__ActiveBuf=&__LocalJmpBuff;if(setjmp(__LocalJmpBuff)){__WasThrown=true;}else
#define catch(x) g__ActiveBuf=__OldActiveBuf;if(__WasThrown)
#define throw(x) longjmp(*g__ActiveBuf,1);
Version 2 is a lot more complex but basically works the same way. It uses a
long jump out of the current function to the try block. The try block then
uses an if/else to skip the code block to the catch block which check the local
variable to see if it should catch.
The example expanded again:
jmp_buf *g_ActiveBuf;
int main(void)
{
jmp_buf LocalJmpBuff;
jmp_buf *OldActiveBuf=g_ActiveBuf;
bool WasThrown=false;
g_ActiveBuf=&LocalJmpBuff;
if(setjmp(LocalJmpBuff))
{
WasThrown=true;
}
else
{
printf("One\n");
longjmp(*g_ActiveBuf,1);
printf("Two\n");
}
g_ActiveBuf=OldActiveBuf;
if(WasThrown)
{
printf("Error\n");
}
return 0;
}
This uses a global pointer so the longjmp() knows what try was last run.
We are using abusing the stack so child functions can also have a try/catch block.
Using this code has a number of down sides (but is a fun mental exercise):
It will not free allocated memory as there are no deconstructors being called.
You can't have more than 1 try/catch in a scope (no nesting)
You can't actually throw exceptions or other data like in C++
Not thread safe at all
You are setting up other programmers for failure because they will likely not notice the hack and try using them like C++ try/catch blocks.
In C99, you can use setjmp/longjmp for non-local control flow.
Within a single scope, the generic, structured coding pattern for C in the presence of multiple resource allocations and multiple exits uses goto, like in this example. This is similar to how C++ implements destructor calls of automatic objects under the hood, and if you stick to this diligently, it should allow you for a certain degree of cleanness even in complex functions.
While some of the other answers have covered the simple cases using setjmp and longjmp, in a real application there's two concerns that really matter.
Nesting of try/catch blocks. Using a single global variable for your jmp_buf will make these not work.
Threading. A single global variable for you jmp_buf will cause all kinds of pain in this situation.
The solution to these is to maintain a thread-local stack of jmp_buf that get updated as you go. (I think this is what lua uses internally).
So instead of this (from JaredPar's awesome answer)
static jmp_buf s_jumpBuffer;
void Example() {
if (setjmp(s_jumpBuffer)) {
// The longjmp was executed and returned control here
printf("Exception happened\n");
} else {
// Normal code execution starts here
Test();
}
}
void Test() {
// Rough equivalent of `throw`
longjump(s_jumpBuffer, 42);
}
You'd use something like:
#define MAX_EXCEPTION_DEPTH 10;
struct exception_state {
jmp_buf s_jumpBuffer[MAX_EXCEPTION_DEPTH];
int current_depth;
};
int try_point(struct exception_state * state) {
if(current_depth==MAX_EXCEPTION_DEPTH) {
abort();
}
int ok = setjmp(state->jumpBuffer[state->current_depth]);
if(ok) {
state->current_depth++;
} else {
//We've had an exception update the stack.
state->current_depth--;
}
return ok;
}
void throw_exception(struct exception_state * state) {
longjump(state->current_depth-1,1);
}
void catch_point(struct exception_state * state) {
state->current_depth--;
}
void end_try_point(struct exception_state * state) {
state->current_depth--;
}
__thread struct exception_state g_exception_state;
void Example() {
if (try_point(&g_exception_state)) {
catch_point(&g_exception_state);
printf("Exception happened\n");
} else {
// Normal code execution starts here
Test();
end_try_point(&g_exception_state);
}
}
void Test() {
// Rough equivalent of `throw`
throw_exception(g_exception_state);
}
Again a more realistic version of this would include some way to store error information into the exception_state, better handling of MAX_EXCEPTION_DEPTH (maybe using realloc to grow the buffer, or something like that).
DISCLAIMER: The above code was written without any testing whatsoever. It is purely so you get an idea of how to structure things. Different systems and different compilers will need to implement the thread local storage differently. The code probably contains both compile errors and logic errors - so while you're free to use it as you choose, TEST it before using it ;)
This is another way to do error handling in C which is more performant than using setjmp/longjmp. Unfortunately, it will not work with MSVC but if using only GCC/Clang is an option, then you might consider it. Specifically, it uses the "label as value" extension, which allows you to take the address of a label, store it in a value and and jump to it unconditionally. I'll present it using an example:
GameEngine *CreateGameEngine(GameEngineParams const *params)
{
/* Declare an error handler variable. This will hold the address
to jump to if an error occurs to cleanup pending resources.
Initialize it to the err label which simply returns an
error value (NULL in this example). The && operator resolves to
the address of the label err */
void *eh = &&err;
/* Try the allocation */
GameEngine *engine = malloc(sizeof *engine);
if (!engine)
goto *eh; /* this is essentially your "throw" */
/* Now make sure that if we throw from this point on, the memory
gets deallocated. As a convention you could name the label "undo_"
followed by the operation to rollback. */
eh = &&undo_malloc;
/* Now carry on with the initialization. */
engine->window = OpenWindow(...);
if (!engine->window)
goto *eh; /* The neat trick about using approach is that you don't
need to remember what "undo" label to go to in code.
Simply go to *eh. */
eh = &&undo_window_open;
/* etc */
/* Everything went well, just return the device. */
return device;
/* After the return, insert your cleanup code in reverse order. */
undo_window_open: CloseWindow(engine->window);
undo_malloc: free(engine);
err: return NULL;
}
If you so wish, you could refactor common code in defines, effectively implementing your own error-handling system.
/* Put at the beginning of a function that may fail. */
#define declthrows void *_eh = &&err
/* Cleans up resources and returns error result. */
#define throw goto *_eh
/* Sets a new undo checkpoint. */
#define undo(label) _eh = &&undo_##label
/* Throws if [condition] evaluates to false. */
#define check(condition) if (!(condition)) throw
/* Throws if [condition] evaluates to false. Then sets a new undo checkpoint. */
#define checkpoint(label, condition) { check(condition); undo(label); }
Then the example becomes
GameEngine *CreateGameEngine(GameEngineParams const *params)
{
declthrows;
/* Try the allocation */
GameEngine *engine = malloc(sizeof *engine);
checkpoint(malloc, engine);
/* Now carry on with the initialization. */
engine->window = OpenWindow(...);
checkpoint(window_open, engine->window);
/* etc */
/* Everything went well, just return the device. */
return device;
/* After the return, insert your cleanup code in reverse order. */
undo_window_open: CloseWindow(engine->window);
undo_malloc: free(engine);
err: return NULL;
}
A quick google search yields kludgey solutions such as this that use setjmp/longjmp as others have mentioned. Nothing as straightforward and elegant as C++/Java's try/catch. I'm rather partial to Ada's exception handling myself.
Check everything with if statements :)
This can be done with setjmp/longjmp in C. P99 has a quite comfortable toolset for this that also is consistent with the new thread model of C11.
In C, you can "emulate" exceptions along with automatic "object reclamation" through manual use of if + goto for explicit error handling.
I often write C code like the following (boiled down to highlight error handling):
#include <assert.h>
typedef int errcode;
errcode init_or_fail( foo *f, goo *g, poo *p, loo *l )
{
errcode ret = 0;
if ( ( ret = foo_init( f ) ) )
goto FAIL;
if ( ( ret = goo_init( g ) ) )
goto FAIL_F;
if ( ( ret = poo_init( p ) ) )
goto FAIL_G;
if ( ( ret = loo_init( l ) ) )
goto FAIL_P;
assert( 0 == ret );
goto END;
/* error handling and return */
/* Note that we finalize in opposite order of initialization because we are unwinding a *STACK* of initialized objects */
FAIL_P:
poo_fini( p );
FAIL_G:
goo_fini( g );
FAIL_F:
foo_fini( f );
FAIL:
assert( 0 != ret );
END:
return ret;
}
This is completely standard ANSI C, separates the error handling away from your mainline code, allows for (manual) stack unwinding of initialized objects much like C++ does, and it is completely obvious what is happening here. Because you are explicitly testing for failure at each point it does make it easier to insert specific logging or error handling at each place an error can occur.
If you don't mind a little macro magic, then you can make this more concise while doing other things like logging errors with stack traces. For example:
#include <assert.h>
#include <stdio.h>
#include <string.h>
#define TRY( X, LABEL ) do { if ( ( X ) ) { fprintf( stderr, "%s:%d: Statement '%s' failed! %d, %s\n", __FILE__, __LINE__, #X, ret, strerror( ret ) ); goto LABEL; } while ( 0 )
typedef int errcode;
errcode init_or_fail( foo *f, goo *g, poo *p, loo *l )
{
errcode ret = 0;
TRY( ret = foo_init( f ), FAIL );
TRY( ret = goo_init( g ), FAIL_F );
TRY( ret = poo_init( p ), FAIL_G );
TRY( ret = loo_init( l ), FAIL_P );
assert( 0 == ret );
goto END;
/* error handling and return */
FAIL_P:
poo_fini( p );
FAIL_G:
goo_fini( g );
FAIL_F:
foo_fini( f );
FAIL:
assert( 0 != ret );
END:
return ret;
}
Of course, this isn't as elegant as C++ exceptions + destructors. For example, nesting multiple error handling stacks within one function this way isn't very clean. Instead, you'd probably want to break those out into self contained sub functions that similarly handle errors, initialize + finalize explicitly like this.
This also only works within a single function and won't keep jumping up the stack unless higher level callers implement similar explicit error handling logic, whereas a C++ exception will just keep jumping up the stack until it finds an appropriate handler. Nor does it allow you to throw an arbitrary type, but instead only an error code.
Systematically coding this way (i.e. - with a single entry and single exit point) also makes it very easy to insert pre and post ("finally") logic that will execute no matter what. You just put your "finally" logic after the END label.
Warning: the following is not very nice but it does the job.
#include <stdio.h>
#include <stdlib.h>
typedef struct {
unsigned int id;
char *name;
char *msg;
} error;
#define _printerr(e, s, ...) fprintf(stderr, "\033[1m\033[37m" "%s:%d: " "\033[1m\033[31m" e ":" "\033[1m\033[37m" " ‘%s_error’ " "\033[0m" s "\n", __FILE__, __LINE__, (*__err)->name, ##__VA_ARGS__)
#define printerr(s, ...) _printerr("error", s, ##__VA_ARGS__)
#define printuncaughterr() _printerr("uncaught error", "%s", (*__err)->msg)
#define _errordef(n, _id) \
error* new_##n##_error_msg(char* msg) { \
error* self = malloc(sizeof(error)); \
self->id = _id; \
self->name = #n; \
self->msg = msg; \
return self; \
} \
error* new_##n##_error() { return new_##n##_error_msg(""); }
#define errordef(n) _errordef(n, __COUNTER__ +1)
#define try(try_block, err, err_name, catch_block) { \
error * err_name = NULL; \
error ** __err = & err_name; \
void __try_fn() try_block \
__try_fn(); \
void __catch_fn() { \
if (err_name == NULL) return; \
unsigned int __##err_name##_id = new_##err##_error()->id; \
if (__##err_name##_id != 0 && __##err_name##_id != err_name->id) \
printuncaughterr(); \
else if (__##err_name##_id != 0 || __##err_name##_id != err_name->id) \
catch_block \
} \
__catch_fn(); \
}
#define throw(e) { *__err = e; return; }
_errordef(any, 0)
Usage:
errordef(my_err1)
errordef(my_err2)
try ({
printf("Helloo\n");
throw(new_my_err1_error_msg("hiiiii!"));
printf("This will not be printed!\n");
}, /*catch*/ any, e, {
printf("My lovely error: %s %s\n", e->name, e->msg);
})
printf("\n");
try ({
printf("Helloo\n");
throw(new_my_err2_error_msg("my msg!"));
printf("This will not be printed!\n");
}, /*catch*/ my_err2, e, {
printerr("%s", e->msg);
})
printf("\n");
try ({
printf("Helloo\n");
throw(new_my_err1_error());
printf("This will not be printed!\n");
}, /*catch*/ my_err2, e, {
printf("Catch %s if you can!\n", e->name);
})
Output:
Helloo
My lovely error: my_err1 hiiiii!
Helloo
/home/naheel/Desktop/aa.c:28: error: ‘my_err2_error’ my msg!
Helloo
/home/naheel/Desktop/aa.c:38: uncaught error: ‘my_err1_error’
Keep on mind that this is using nested functions and __COUNTER__. You'll be on the safe side if you're using gcc.
Redis use goto to simulate try/catch, IMHO it is very clean and elegant:
/* Save the DB on disk. Return REDIS_ERR on error, REDIS_OK on success. */
int rdbSave(char *filename) {
char tmpfile[256];
FILE *fp;
rio rdb;
int error = 0;
snprintf(tmpfile,256,"temp-%d.rdb", (int) getpid());
fp = fopen(tmpfile,"w");
if (!fp) {
redisLog(REDIS_WARNING, "Failed opening .rdb for saving: %s",
strerror(errno));
return REDIS_ERR;
}
rioInitWithFile(&rdb,fp);
if (rdbSaveRio(&rdb,&error) == REDIS_ERR) {
errno = error;
goto werr;
}
/* Make sure data will not remain on the OS's output buffers */
if (fflush(fp) == EOF) goto werr;
if (fsync(fileno(fp)) == -1) goto werr;
if (fclose(fp) == EOF) goto werr;
/* Use RENAME to make sure the DB file is changed atomically only
* if the generate DB file is ok. */
if (rename(tmpfile,filename) == -1) {
redisLog(REDIS_WARNING,"Error moving temp DB file on the final destination: %s", strerror(errno));
unlink(tmpfile);
return REDIS_ERR;
}
redisLog(REDIS_NOTICE,"DB saved on disk");
server.dirty = 0;
server.lastsave = time(NULL);
server.lastbgsave_status = REDIS_OK;
return REDIS_OK;
werr:
fclose(fp);
unlink(tmpfile);
redisLog(REDIS_WARNING,"Write error saving DB on disk: %s", strerror(errno));
return REDIS_ERR;
}
If you're using C with Win32, you can leverage its Structured Exception Handling (SEH) to simulate try/catch.
If you're using C in platforms that don't support setjmp() and longjmp(), have a look at this Exception Handling of pjsip library, it does provide its own implementation
After studying the answers given above, I set up a system that automatically handles nested exceptions well. Here is the code I wrote to test my system:
#include "MyOtherTricks.h"
#include "Exceptions.h"
void Testing_InnerMethod();
void Testing_PossibleExceptionThrower();
void TestExceptionHandling()
{
try
{
Testing_InnerMethod();
Say("The inner method exited without an exception.");
}
catch (Exception)
{
Say("I caught an Exception that the inner method did not catch.");
}
end_try
}
void Testing_InnerMethod()
{
try
{
Say("I am in a try block.");
Testing_PossibleExceptionThrower();
Say("The possible exception thrower didn't throw an exception.");
}
catch (ExceptionSubtype1)
Say("I caught an exception, subtype 1.");
catch (ExceptionSubtype2)
{
Say("I caught an exception, subtype 2.");
Say("I will now rethrow it.");
throw(exception);
}
end_try
}
void Testing_PossibleExceptionThrower()
{
Say("Here is the possible exception thrower.");
throw(new(ExceptionSubtype2)); // To further test exception handling, replace ExceptionSubtype2 in this line with Exception or ExceptionSubtype1, or comment out this line entirely.
Say("No, I won't throw an exception!");
}
The example code relies on two files, Exceptions.h and Exceptions.c. Here is Exceptions.h:
#include <setjmp.h>
extern jmp_buf* Exception_Handler;
#define try do \
{ \
jmp_buf* outerExceptionHandler = Exception_Handler; \
jmp_buf exceptionHandler; \
Exception_Handler = &exceptionHandler; \
Exception exception = (Exception)setjmp(exceptionHandler); \
if (exception != 0) Exception_Handler = outerExceptionHandler; \
if (exception == 0) \
{ \
// The try block goes here. It must not include a return statement or anything else that exits the try...end_try block, because then the outer exception handler will not be restored.
#define catch(exceptionType) Exception_Handler = outerExceptionHandler; \
} \
else if (Object_IsSomeTypeOf(exception, exceptionType)) \
{
// The catch block goes here. It may include a return statement or anything else that exits the try...end_try block. A break statement will exit only the try...end_try block.
#define end_try } \
else \
throw(exception); \
} while(0);
void throw(Exception exception);
And here is Exceptions.c:
#include "MyOtherTricks.h"
#include "Exceptions.h"
jmp_buf* Exception_Handler = 0;
void throw(Exception exception)
{
if (Exception_Handler == 0) FailBecause("Uncaught exception.");
longjmp(*Exception_Handler, (int)exception);
}
Note that this code references some additional methods that I'm not including here (because class inheritance in C is off-topic). To make this code work for you, you'll have to understand this code well enough to replace a few things. In particular, if you want to distinguish between different types of exceptions, you'll need to realize that this code assumes that Object_IsSomeTypeOf(new(ExceptionSubtype1), Exception) returns true and Object_IsSomeTypeOf(new(ExceptionSubtype1), ExceptionSubtype2) returns false, and you'll need to either make your own version of my Object_IsSomeTypeOf macro or replace it with something else.
Perhaps not a major language (unfortunately), but in APL, theres the ⎕EA operation (stand for Execute Alternate).
Usage:
'Y' ⎕EA 'X'
where X and Y are either code snippets supplied as strings or function names.
If X runs into an error, Y (usually error-handling) will be executed instead.

Resources