Return statement does not get executed in c
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}
So, I have a curious case and can't quite figure out what I've done wrong. Here's the scenario:
I have written a creator function that should return a pointer to a function. To fill the structure with data, I read in a text file. Depending on what text file I use as input, the error either occurs or it doesn't occur. (The error occurs for a text file with ~4000 lines and not for a file with ~200 if that makes a difference). The strange thing is that the code executes until right before the return
statement. But it then does not return but just hangs. No errors, no compiler warnings (intel compiler). I wonder if anyone has experienced something similar or has an idea what could be going wrong.
The code below is simplified to illustrate the problem. The actual code is somewhat more complex since I'm using Schreiner's Approach to play with objects in C.
struct Somestruct {
int A;
int B;
int C;
}
static void *Somestruct_ctor(void *_self) {
struct Somestruct *self = _self;
fillDataFromFile(self);
printf("This line gets executed.n");
return self; // <- this one doesn't
}
int main(int argc, char *argv) {
void *myObject;
myObject = Somestruct_ctor(myObject);
printf("The code does NOT get until heren");
return 0;
}
c return intel icc
add a comment |
So, I have a curious case and can't quite figure out what I've done wrong. Here's the scenario:
I have written a creator function that should return a pointer to a function. To fill the structure with data, I read in a text file. Depending on what text file I use as input, the error either occurs or it doesn't occur. (The error occurs for a text file with ~4000 lines and not for a file with ~200 if that makes a difference). The strange thing is that the code executes until right before the return
statement. But it then does not return but just hangs. No errors, no compiler warnings (intel compiler). I wonder if anyone has experienced something similar or has an idea what could be going wrong.
The code below is simplified to illustrate the problem. The actual code is somewhat more complex since I'm using Schreiner's Approach to play with objects in C.
struct Somestruct {
int A;
int B;
int C;
}
static void *Somestruct_ctor(void *_self) {
struct Somestruct *self = _self;
fillDataFromFile(self);
printf("This line gets executed.n");
return self; // <- this one doesn't
}
int main(int argc, char *argv) {
void *myObject;
myObject = Somestruct_ctor(myObject);
printf("The code does NOT get until heren");
return 0;
}
c return intel icc
5
void * myObject;
is uninitialized. Reading its value (to pass it as an arg by value toSomestruct_ctor(myObject)
is undefined behaviour. If your compiler doesn't warn about this by default, then enable warnings likegcc -Wall
. You may need to enable optimization for the compiler to notice, e.g.gcc -Og -Wall
. It may happen to be pointing somewhere on the stack, causing a buffer overflow that ends up in an infinite loop.
– Peter Cordes
Jan 3 at 3:17
C11 Standard - 6.3.2.1 Lvalues, arrays, and function designators(p1) An lvalue is an expression (with an object type other than void) that potentially designates an object;64) if an lvalue does not designate an object when it is evaluated, the behavior is undefined.
– David C. Rankin
Jan 3 at 3:38
add a comment |
So, I have a curious case and can't quite figure out what I've done wrong. Here's the scenario:
I have written a creator function that should return a pointer to a function. To fill the structure with data, I read in a text file. Depending on what text file I use as input, the error either occurs or it doesn't occur. (The error occurs for a text file with ~4000 lines and not for a file with ~200 if that makes a difference). The strange thing is that the code executes until right before the return
statement. But it then does not return but just hangs. No errors, no compiler warnings (intel compiler). I wonder if anyone has experienced something similar or has an idea what could be going wrong.
The code below is simplified to illustrate the problem. The actual code is somewhat more complex since I'm using Schreiner's Approach to play with objects in C.
struct Somestruct {
int A;
int B;
int C;
}
static void *Somestruct_ctor(void *_self) {
struct Somestruct *self = _self;
fillDataFromFile(self);
printf("This line gets executed.n");
return self; // <- this one doesn't
}
int main(int argc, char *argv) {
void *myObject;
myObject = Somestruct_ctor(myObject);
printf("The code does NOT get until heren");
return 0;
}
c return intel icc
So, I have a curious case and can't quite figure out what I've done wrong. Here's the scenario:
I have written a creator function that should return a pointer to a function. To fill the structure with data, I read in a text file. Depending on what text file I use as input, the error either occurs or it doesn't occur. (The error occurs for a text file with ~4000 lines and not for a file with ~200 if that makes a difference). The strange thing is that the code executes until right before the return
statement. But it then does not return but just hangs. No errors, no compiler warnings (intel compiler). I wonder if anyone has experienced something similar or has an idea what could be going wrong.
The code below is simplified to illustrate the problem. The actual code is somewhat more complex since I'm using Schreiner's Approach to play with objects in C.
struct Somestruct {
int A;
int B;
int C;
}
static void *Somestruct_ctor(void *_self) {
struct Somestruct *self = _self;
fillDataFromFile(self);
printf("This line gets executed.n");
return self; // <- this one doesn't
}
int main(int argc, char *argv) {
void *myObject;
myObject = Somestruct_ctor(myObject);
printf("The code does NOT get until heren");
return 0;
}
c return intel icc
c return intel icc
edited Jan 3 at 4:16
chqrlie
62.5k848107
62.5k848107
asked Jan 3 at 3:07
Nathan FollyNathan Folly
223
223
5
void * myObject;
is uninitialized. Reading its value (to pass it as an arg by value toSomestruct_ctor(myObject)
is undefined behaviour. If your compiler doesn't warn about this by default, then enable warnings likegcc -Wall
. You may need to enable optimization for the compiler to notice, e.g.gcc -Og -Wall
. It may happen to be pointing somewhere on the stack, causing a buffer overflow that ends up in an infinite loop.
– Peter Cordes
Jan 3 at 3:17
C11 Standard - 6.3.2.1 Lvalues, arrays, and function designators(p1) An lvalue is an expression (with an object type other than void) that potentially designates an object;64) if an lvalue does not designate an object when it is evaluated, the behavior is undefined.
– David C. Rankin
Jan 3 at 3:38
add a comment |
5
void * myObject;
is uninitialized. Reading its value (to pass it as an arg by value toSomestruct_ctor(myObject)
is undefined behaviour. If your compiler doesn't warn about this by default, then enable warnings likegcc -Wall
. You may need to enable optimization for the compiler to notice, e.g.gcc -Og -Wall
. It may happen to be pointing somewhere on the stack, causing a buffer overflow that ends up in an infinite loop.
– Peter Cordes
Jan 3 at 3:17
C11 Standard - 6.3.2.1 Lvalues, arrays, and function designators(p1) An lvalue is an expression (with an object type other than void) that potentially designates an object;64) if an lvalue does not designate an object when it is evaluated, the behavior is undefined.
– David C. Rankin
Jan 3 at 3:38
5
5
void * myObject;
is uninitialized. Reading its value (to pass it as an arg by value to Somestruct_ctor(myObject)
is undefined behaviour. If your compiler doesn't warn about this by default, then enable warnings like gcc -Wall
. You may need to enable optimization for the compiler to notice, e.g. gcc -Og -Wall
. It may happen to be pointing somewhere on the stack, causing a buffer overflow that ends up in an infinite loop.– Peter Cordes
Jan 3 at 3:17
void * myObject;
is uninitialized. Reading its value (to pass it as an arg by value to Somestruct_ctor(myObject)
is undefined behaviour. If your compiler doesn't warn about this by default, then enable warnings like gcc -Wall
. You may need to enable optimization for the compiler to notice, e.g. gcc -Og -Wall
. It may happen to be pointing somewhere on the stack, causing a buffer overflow that ends up in an infinite loop.– Peter Cordes
Jan 3 at 3:17
C11 Standard - 6.3.2.1 Lvalues, arrays, and function designators(p1) An lvalue is an expression (with an object type other than void) that potentially designates an object;64) if an lvalue does not designate an object when it is evaluated, the behavior is undefined.
– David C. Rankin
Jan 3 at 3:38
C11 Standard - 6.3.2.1 Lvalues, arrays, and function designators(p1) An lvalue is an expression (with an object type other than void) that potentially designates an object;64) if an lvalue does not designate an object when it is evaluated, the behavior is undefined.
– David C. Rankin
Jan 3 at 3:38
add a comment |
1 Answer
1
active
oldest
votes
void * myObject;
is uninitialized, and not pointing at valid storage. Reading its value (to pass it as an arg by value to Somestruct_ctor(myObject)
) is undefined behaviour.
The fact that your code doesn't always crash tells us that in ICC's code-gen it happens to be pointing somewhere valid, probably somewhere on the stack. With a larger file, we presumably get a buffer overflow that overwrites a local variable and/or a return address and ends up in an infinite loop. It's pretty amazing that this managed to still not crash given that it happened by accident. (In the x86-64 asm from ICC with optimization disabled, it just loads some uninitialized stack memory as an arg for Somestruct_ctor
.)
Or maybe its a pointer to a stdio data structure, left over from init of stdio before main
. Perhaps having fillDataFromFile
scribble all over the data that FILE *stdout
points to (for example) left it in a "locked" state, so your single thread is stuck waiting for something else to unlock a mutex. If you know asm, it might be interesting to single-step the infinite loop or "deadlock" inside printf
and see exactly what happened.
If you compile with gcc -O3
, the compiler zeros a register as an arg for fillDataFromFile
(after inlining Somestruct_ctor
), so it's passing a NULL pointer. That would presumably crash always, assuming the function dereferences the pointer.
clang chooses to leave rdi
(the first arg-passing register in the x86-64 System V calling conventino) uninitialized, so it still holds argc
when main
calls fillDataFromFile
. That would also reliably crash.
You forgot to enable compiler warnings.
All the major x86 compilers (gcc, clang, MSVC, ICC) have warnings for this, but they aren't on by default in all compilers (only in MSVC). Probably because there can be cases where the compiler isn't sure about a var being uninitialized if there's some conditional stuff. In this case it's 100% certain that it's definitely used uninitialized, but if the init and the use were inside different if()
blocks, the compiler might not be able to prove that the use only happened if the init happened.
With clang and gcc, you should usually use -Wall
and silence all the warnings.
With ICC, -diag-enable:warn
is closer to gcc -Wall
. (ICC's -Wall
doesn't enable this very important warning. Don't be fooled into thinking you've enabled all important warnings with icc -Wall
.)
# from icc -diag-enable:warn on your code
<source>(21): warning #592: variable "myObject" is used before its value is set
myObject = Somestruct_ctor(myObject);
^
how to turn on icc/icpc warnings? has some info. It ways that icc's -Wall
is very minimalisitc compared to gcc's. So maybe -Wall -Wextra
would be useful with icc. It recommends -w2
or -w3
as potentially-useful warning levels.
Clang usually has the nicest warnings, in this case:
<source>:21:30: warning: variable 'myObject' is uninitialized when used here [-Wuninitialized]
myObject = Somestruct_ctor(myObject);
^~~~~~~~
<source>:19:18: note: initialize the variable 'myObject' to silence this warning
void * myObject;
^
= NULL
1 warning generated.
I got the above outputs by compiling your source on the Godbolt compiler explorer (after fixing the syntax errors: missing semicolon after the struct, and the capitalization of the Struct
keyword.) -xc
tells the C++ compilers on Godbolt to compile as C.
It turns out that you don't need to enable optimization for icc and gcc to notice this error. Some warnings only work with optimization enabled, where the compiler does more analysis of program logic and can notice more, but they track uninitialized even at -O0
.
constructor code that would make more sense:
// C
int main(void){
struct Somestruct myObject; // automatic storage for the object value
Somestruct_ctor(&myObject); // pass a pointer to that storage
}
The object needs to live somewhere. We can get space for it with automatic (a local), static (a static
local, or a global), or dynamic storage (malloc
).
Automatic storage + calling the constructor is equivalent to C++ like this, if struct Somestruct
has a C++ default constructor declared in the struct/class definition.
// C++
int main(void){
Somestruct myObject; // calls the default constructor, if there is one
// destructor will be called at some point when myObject goes out of scope
}
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54015817%2freturn-statement-does-not-get-executed-in-c%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
void * myObject;
is uninitialized, and not pointing at valid storage. Reading its value (to pass it as an arg by value to Somestruct_ctor(myObject)
) is undefined behaviour.
The fact that your code doesn't always crash tells us that in ICC's code-gen it happens to be pointing somewhere valid, probably somewhere on the stack. With a larger file, we presumably get a buffer overflow that overwrites a local variable and/or a return address and ends up in an infinite loop. It's pretty amazing that this managed to still not crash given that it happened by accident. (In the x86-64 asm from ICC with optimization disabled, it just loads some uninitialized stack memory as an arg for Somestruct_ctor
.)
Or maybe its a pointer to a stdio data structure, left over from init of stdio before main
. Perhaps having fillDataFromFile
scribble all over the data that FILE *stdout
points to (for example) left it in a "locked" state, so your single thread is stuck waiting for something else to unlock a mutex. If you know asm, it might be interesting to single-step the infinite loop or "deadlock" inside printf
and see exactly what happened.
If you compile with gcc -O3
, the compiler zeros a register as an arg for fillDataFromFile
(after inlining Somestruct_ctor
), so it's passing a NULL pointer. That would presumably crash always, assuming the function dereferences the pointer.
clang chooses to leave rdi
(the first arg-passing register in the x86-64 System V calling conventino) uninitialized, so it still holds argc
when main
calls fillDataFromFile
. That would also reliably crash.
You forgot to enable compiler warnings.
All the major x86 compilers (gcc, clang, MSVC, ICC) have warnings for this, but they aren't on by default in all compilers (only in MSVC). Probably because there can be cases where the compiler isn't sure about a var being uninitialized if there's some conditional stuff. In this case it's 100% certain that it's definitely used uninitialized, but if the init and the use were inside different if()
blocks, the compiler might not be able to prove that the use only happened if the init happened.
With clang and gcc, you should usually use -Wall
and silence all the warnings.
With ICC, -diag-enable:warn
is closer to gcc -Wall
. (ICC's -Wall
doesn't enable this very important warning. Don't be fooled into thinking you've enabled all important warnings with icc -Wall
.)
# from icc -diag-enable:warn on your code
<source>(21): warning #592: variable "myObject" is used before its value is set
myObject = Somestruct_ctor(myObject);
^
how to turn on icc/icpc warnings? has some info. It ways that icc's -Wall
is very minimalisitc compared to gcc's. So maybe -Wall -Wextra
would be useful with icc. It recommends -w2
or -w3
as potentially-useful warning levels.
Clang usually has the nicest warnings, in this case:
<source>:21:30: warning: variable 'myObject' is uninitialized when used here [-Wuninitialized]
myObject = Somestruct_ctor(myObject);
^~~~~~~~
<source>:19:18: note: initialize the variable 'myObject' to silence this warning
void * myObject;
^
= NULL
1 warning generated.
I got the above outputs by compiling your source on the Godbolt compiler explorer (after fixing the syntax errors: missing semicolon after the struct, and the capitalization of the Struct
keyword.) -xc
tells the C++ compilers on Godbolt to compile as C.
It turns out that you don't need to enable optimization for icc and gcc to notice this error. Some warnings only work with optimization enabled, where the compiler does more analysis of program logic and can notice more, but they track uninitialized even at -O0
.
constructor code that would make more sense:
// C
int main(void){
struct Somestruct myObject; // automatic storage for the object value
Somestruct_ctor(&myObject); // pass a pointer to that storage
}
The object needs to live somewhere. We can get space for it with automatic (a local), static (a static
local, or a global), or dynamic storage (malloc
).
Automatic storage + calling the constructor is equivalent to C++ like this, if struct Somestruct
has a C++ default constructor declared in the struct/class definition.
// C++
int main(void){
Somestruct myObject; // calls the default constructor, if there is one
// destructor will be called at some point when myObject goes out of scope
}
add a comment |
void * myObject;
is uninitialized, and not pointing at valid storage. Reading its value (to pass it as an arg by value to Somestruct_ctor(myObject)
) is undefined behaviour.
The fact that your code doesn't always crash tells us that in ICC's code-gen it happens to be pointing somewhere valid, probably somewhere on the stack. With a larger file, we presumably get a buffer overflow that overwrites a local variable and/or a return address and ends up in an infinite loop. It's pretty amazing that this managed to still not crash given that it happened by accident. (In the x86-64 asm from ICC with optimization disabled, it just loads some uninitialized stack memory as an arg for Somestruct_ctor
.)
Or maybe its a pointer to a stdio data structure, left over from init of stdio before main
. Perhaps having fillDataFromFile
scribble all over the data that FILE *stdout
points to (for example) left it in a "locked" state, so your single thread is stuck waiting for something else to unlock a mutex. If you know asm, it might be interesting to single-step the infinite loop or "deadlock" inside printf
and see exactly what happened.
If you compile with gcc -O3
, the compiler zeros a register as an arg for fillDataFromFile
(after inlining Somestruct_ctor
), so it's passing a NULL pointer. That would presumably crash always, assuming the function dereferences the pointer.
clang chooses to leave rdi
(the first arg-passing register in the x86-64 System V calling conventino) uninitialized, so it still holds argc
when main
calls fillDataFromFile
. That would also reliably crash.
You forgot to enable compiler warnings.
All the major x86 compilers (gcc, clang, MSVC, ICC) have warnings for this, but they aren't on by default in all compilers (only in MSVC). Probably because there can be cases where the compiler isn't sure about a var being uninitialized if there's some conditional stuff. In this case it's 100% certain that it's definitely used uninitialized, but if the init and the use were inside different if()
blocks, the compiler might not be able to prove that the use only happened if the init happened.
With clang and gcc, you should usually use -Wall
and silence all the warnings.
With ICC, -diag-enable:warn
is closer to gcc -Wall
. (ICC's -Wall
doesn't enable this very important warning. Don't be fooled into thinking you've enabled all important warnings with icc -Wall
.)
# from icc -diag-enable:warn on your code
<source>(21): warning #592: variable "myObject" is used before its value is set
myObject = Somestruct_ctor(myObject);
^
how to turn on icc/icpc warnings? has some info. It ways that icc's -Wall
is very minimalisitc compared to gcc's. So maybe -Wall -Wextra
would be useful with icc. It recommends -w2
or -w3
as potentially-useful warning levels.
Clang usually has the nicest warnings, in this case:
<source>:21:30: warning: variable 'myObject' is uninitialized when used here [-Wuninitialized]
myObject = Somestruct_ctor(myObject);
^~~~~~~~
<source>:19:18: note: initialize the variable 'myObject' to silence this warning
void * myObject;
^
= NULL
1 warning generated.
I got the above outputs by compiling your source on the Godbolt compiler explorer (after fixing the syntax errors: missing semicolon after the struct, and the capitalization of the Struct
keyword.) -xc
tells the C++ compilers on Godbolt to compile as C.
It turns out that you don't need to enable optimization for icc and gcc to notice this error. Some warnings only work with optimization enabled, where the compiler does more analysis of program logic and can notice more, but they track uninitialized even at -O0
.
constructor code that would make more sense:
// C
int main(void){
struct Somestruct myObject; // automatic storage for the object value
Somestruct_ctor(&myObject); // pass a pointer to that storage
}
The object needs to live somewhere. We can get space for it with automatic (a local), static (a static
local, or a global), or dynamic storage (malloc
).
Automatic storage + calling the constructor is equivalent to C++ like this, if struct Somestruct
has a C++ default constructor declared in the struct/class definition.
// C++
int main(void){
Somestruct myObject; // calls the default constructor, if there is one
// destructor will be called at some point when myObject goes out of scope
}
add a comment |
void * myObject;
is uninitialized, and not pointing at valid storage. Reading its value (to pass it as an arg by value to Somestruct_ctor(myObject)
) is undefined behaviour.
The fact that your code doesn't always crash tells us that in ICC's code-gen it happens to be pointing somewhere valid, probably somewhere on the stack. With a larger file, we presumably get a buffer overflow that overwrites a local variable and/or a return address and ends up in an infinite loop. It's pretty amazing that this managed to still not crash given that it happened by accident. (In the x86-64 asm from ICC with optimization disabled, it just loads some uninitialized stack memory as an arg for Somestruct_ctor
.)
Or maybe its a pointer to a stdio data structure, left over from init of stdio before main
. Perhaps having fillDataFromFile
scribble all over the data that FILE *stdout
points to (for example) left it in a "locked" state, so your single thread is stuck waiting for something else to unlock a mutex. If you know asm, it might be interesting to single-step the infinite loop or "deadlock" inside printf
and see exactly what happened.
If you compile with gcc -O3
, the compiler zeros a register as an arg for fillDataFromFile
(after inlining Somestruct_ctor
), so it's passing a NULL pointer. That would presumably crash always, assuming the function dereferences the pointer.
clang chooses to leave rdi
(the first arg-passing register in the x86-64 System V calling conventino) uninitialized, so it still holds argc
when main
calls fillDataFromFile
. That would also reliably crash.
You forgot to enable compiler warnings.
All the major x86 compilers (gcc, clang, MSVC, ICC) have warnings for this, but they aren't on by default in all compilers (only in MSVC). Probably because there can be cases where the compiler isn't sure about a var being uninitialized if there's some conditional stuff. In this case it's 100% certain that it's definitely used uninitialized, but if the init and the use were inside different if()
blocks, the compiler might not be able to prove that the use only happened if the init happened.
With clang and gcc, you should usually use -Wall
and silence all the warnings.
With ICC, -diag-enable:warn
is closer to gcc -Wall
. (ICC's -Wall
doesn't enable this very important warning. Don't be fooled into thinking you've enabled all important warnings with icc -Wall
.)
# from icc -diag-enable:warn on your code
<source>(21): warning #592: variable "myObject" is used before its value is set
myObject = Somestruct_ctor(myObject);
^
how to turn on icc/icpc warnings? has some info. It ways that icc's -Wall
is very minimalisitc compared to gcc's. So maybe -Wall -Wextra
would be useful with icc. It recommends -w2
or -w3
as potentially-useful warning levels.
Clang usually has the nicest warnings, in this case:
<source>:21:30: warning: variable 'myObject' is uninitialized when used here [-Wuninitialized]
myObject = Somestruct_ctor(myObject);
^~~~~~~~
<source>:19:18: note: initialize the variable 'myObject' to silence this warning
void * myObject;
^
= NULL
1 warning generated.
I got the above outputs by compiling your source on the Godbolt compiler explorer (after fixing the syntax errors: missing semicolon after the struct, and the capitalization of the Struct
keyword.) -xc
tells the C++ compilers on Godbolt to compile as C.
It turns out that you don't need to enable optimization for icc and gcc to notice this error. Some warnings only work with optimization enabled, where the compiler does more analysis of program logic and can notice more, but they track uninitialized even at -O0
.
constructor code that would make more sense:
// C
int main(void){
struct Somestruct myObject; // automatic storage for the object value
Somestruct_ctor(&myObject); // pass a pointer to that storage
}
The object needs to live somewhere. We can get space for it with automatic (a local), static (a static
local, or a global), or dynamic storage (malloc
).
Automatic storage + calling the constructor is equivalent to C++ like this, if struct Somestruct
has a C++ default constructor declared in the struct/class definition.
// C++
int main(void){
Somestruct myObject; // calls the default constructor, if there is one
// destructor will be called at some point when myObject goes out of scope
}
void * myObject;
is uninitialized, and not pointing at valid storage. Reading its value (to pass it as an arg by value to Somestruct_ctor(myObject)
) is undefined behaviour.
The fact that your code doesn't always crash tells us that in ICC's code-gen it happens to be pointing somewhere valid, probably somewhere on the stack. With a larger file, we presumably get a buffer overflow that overwrites a local variable and/or a return address and ends up in an infinite loop. It's pretty amazing that this managed to still not crash given that it happened by accident. (In the x86-64 asm from ICC with optimization disabled, it just loads some uninitialized stack memory as an arg for Somestruct_ctor
.)
Or maybe its a pointer to a stdio data structure, left over from init of stdio before main
. Perhaps having fillDataFromFile
scribble all over the data that FILE *stdout
points to (for example) left it in a "locked" state, so your single thread is stuck waiting for something else to unlock a mutex. If you know asm, it might be interesting to single-step the infinite loop or "deadlock" inside printf
and see exactly what happened.
If you compile with gcc -O3
, the compiler zeros a register as an arg for fillDataFromFile
(after inlining Somestruct_ctor
), so it's passing a NULL pointer. That would presumably crash always, assuming the function dereferences the pointer.
clang chooses to leave rdi
(the first arg-passing register in the x86-64 System V calling conventino) uninitialized, so it still holds argc
when main
calls fillDataFromFile
. That would also reliably crash.
You forgot to enable compiler warnings.
All the major x86 compilers (gcc, clang, MSVC, ICC) have warnings for this, but they aren't on by default in all compilers (only in MSVC). Probably because there can be cases where the compiler isn't sure about a var being uninitialized if there's some conditional stuff. In this case it's 100% certain that it's definitely used uninitialized, but if the init and the use were inside different if()
blocks, the compiler might not be able to prove that the use only happened if the init happened.
With clang and gcc, you should usually use -Wall
and silence all the warnings.
With ICC, -diag-enable:warn
is closer to gcc -Wall
. (ICC's -Wall
doesn't enable this very important warning. Don't be fooled into thinking you've enabled all important warnings with icc -Wall
.)
# from icc -diag-enable:warn on your code
<source>(21): warning #592: variable "myObject" is used before its value is set
myObject = Somestruct_ctor(myObject);
^
how to turn on icc/icpc warnings? has some info. It ways that icc's -Wall
is very minimalisitc compared to gcc's. So maybe -Wall -Wextra
would be useful with icc. It recommends -w2
or -w3
as potentially-useful warning levels.
Clang usually has the nicest warnings, in this case:
<source>:21:30: warning: variable 'myObject' is uninitialized when used here [-Wuninitialized]
myObject = Somestruct_ctor(myObject);
^~~~~~~~
<source>:19:18: note: initialize the variable 'myObject' to silence this warning
void * myObject;
^
= NULL
1 warning generated.
I got the above outputs by compiling your source on the Godbolt compiler explorer (after fixing the syntax errors: missing semicolon after the struct, and the capitalization of the Struct
keyword.) -xc
tells the C++ compilers on Godbolt to compile as C.
It turns out that you don't need to enable optimization for icc and gcc to notice this error. Some warnings only work with optimization enabled, where the compiler does more analysis of program logic and can notice more, but they track uninitialized even at -O0
.
constructor code that would make more sense:
// C
int main(void){
struct Somestruct myObject; // automatic storage for the object value
Somestruct_ctor(&myObject); // pass a pointer to that storage
}
The object needs to live somewhere. We can get space for it with automatic (a local), static (a static
local, or a global), or dynamic storage (malloc
).
Automatic storage + calling the constructor is equivalent to C++ like this, if struct Somestruct
has a C++ default constructor declared in the struct/class definition.
// C++
int main(void){
Somestruct myObject; // calls the default constructor, if there is one
// destructor will be called at some point when myObject goes out of scope
}
edited Jan 3 at 4:07
answered Jan 3 at 3:48
Peter CordesPeter Cordes
134k18203342
134k18203342
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54015817%2freturn-statement-does-not-get-executed-in-c%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
5
void * myObject;
is uninitialized. Reading its value (to pass it as an arg by value toSomestruct_ctor(myObject)
is undefined behaviour. If your compiler doesn't warn about this by default, then enable warnings likegcc -Wall
. You may need to enable optimization for the compiler to notice, e.g.gcc -Og -Wall
. It may happen to be pointing somewhere on the stack, causing a buffer overflow that ends up in an infinite loop.– Peter Cordes
Jan 3 at 3:17
C11 Standard - 6.3.2.1 Lvalues, arrays, and function designators(p1) An lvalue is an expression (with an object type other than void) that potentially designates an object;64) if an lvalue does not designate an object when it is evaluated, the behavior is undefined.
– David C. Rankin
Jan 3 at 3:38