[MUDFLAP] Is sizeof(ARRAY[0]) equivalent to sizeof(*ARRAY) ?

M

m.labanowicz

Hi,

I'm looking for the reason of the MUDFLAP violation
on my 'BIG' C project (no possibility to show),
system: Ubuntu:12.04, gcc:4.6.3.

NOTE: The same 'BIG' project has been successfully executed
on my old system: Ubuntu:10.04, gcc-(version don't remember).
Mudflap was silent.

My investigation shows that there
are called some functions before 'main', like:
_GLOBAL__sub_I_00099_0_<org_fun_name>

Currently MUDFLAP violates before calling 'main' in
_GLOBAL__sub_I_00099_0_<my_function>

if I change source code of <my_function>
from sizeof(*ARRAY)
to sizeof(ARRAY[0])
then violation source shifts to another
_GLOBAL__sub_I_00099_0_... function.

But this algoritm failed in case MUDFLAP violates
at function that has no usage of sizeof(ARRAY) operator.

Common for the all functions that MUDFLAP violates is the
static const ARRAY usage, example:

/*--EXAMPLE-BEG----------------*/
01: extern unsigned my_function_check(unsigned a, unsigned b, unsigned c);
02: void my_function(void)
03: {
04: unsigned const SCALE [] = { 0, 1, 2 };
05: unsigned const TOSTEP [][2] = {
06: { 10, 1},
07: { 100, 8}
08: };
09: unsigned s = sizeof(SCALE) / sizeof(SCALE[0]);
10: while (s--)
11: {
12: unsigned i = 0;
13: while (i < (sizeof(TOSTEP) / sizeof(TOSTEP[0])))
14: {
15: unsigned current = 0;
16: unsigned value = 0;
17: current = my_function_check(SCALE, TOSTEP[0], value);
18: if (current)
19: {
20: return;
21: }
22: ++i;
23: }
24: }
25: }
/*--EXAMPLE-BEG----------------*/

In this example I have not found any reason of
violate before calling the main.

There is amazing difference that depends
on usage of the sizeof operator:

--[TEST-BEG]------------------------------
+ uname -a
Linux ldrlinux 3.2.0-35-generic-pae #55-Ubuntu SMP Wed Dec 5 18:04:39 UTC 2012 i686 i686 i386 GNU/Linux
+ gcc --version
gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3
Copyright (C) 2011 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

+ gawk '{printf("%02u: %s\n", NR, $0);}'
+ cat bar.c
01: #include <stddef.h> /* size_t */
02: static int const BAR [] = {0,1,2,3,4};
03: size_t bar_element_sizeof(void) {
04: #if ASTERISK
05: return sizeof(*BAR);
06: #else
07: return sizeof(BAR[0]);
08: #endif
09: }
+ gcc -W -Wall -ansi -pedantic -Werror -fmudflap -DnotASTERISK -c bar.c -o bar_notASTERISK.o
+ gcc -W -Wall -ansi -pedantic -Werror -fmudflap -DASTERISK -c bar.c -o bar_ASTERISK.o
+ objdump -d bar_notASTERISK.o
+ objdump -d bar_ASTERISK.o
+ diff bar_notASTERISK.S bar_ASTERISK.S
2c2
< bar_notASTERISK.o: file format elf32-i386
---
bar_ASTERISK.o: file format elf32-i386
17c17
< d: 83 ec 08 sub $0x8,%esp
---
d: 83 ec 18 sub $0x18,%esp
19,20c19,28
< 15: c9 leave
< 16: c3 ret
---
15: c7 44 24 0c 14 00 00 movl $0x14,0xc(%esp)
1c: 00
1d: c7 44 24 08 04 00 00 movl $0x4,0x8(%esp)
24: 00
25: c7 44 24 04 14 00 00 movl $0x14,0x4(%esp)
2c: 00
2d: c7 04 24 00 00 00 00 movl $0x0,(%esp)
34: e8 fc ff ff ff call 35 <_GLOBAL__sub_I_00099_0_bar_element_sizeof+0x2b>
39: c9 leave
3a: c3 ret
--[TEST-EOF]------------------------------

Is there any clear reason of such difference ?

Best Regards
 
J

James Kuyper

On 01/09/2013 10:26 AM, (e-mail address removed) wrote:
....
+ cat bar.c
01: #include <stddef.h> /* size_t */
02: static int const BAR [] = {0,1,2,3,4};
03: size_t bar_element_sizeof(void) {
04: #if ASTERISK
05: return sizeof(*BAR);
06: #else
07: return sizeof(BAR[0]);
08: #endif
09: }
+ gcc -W -Wall -ansi -pedantic -Werror -fmudflap -DnotASTERISK -c bar.c -o bar_notASTERISK.o
+ gcc -W -Wall -ansi -pedantic -Werror -fmudflap -DASTERISK -c bar.c -o bar_ASTERISK.o
+ objdump -d bar_notASTERISK.o
+ objdump -d bar_ASTERISK.o

As far as C is concerned, with the above definition for BAR,
sizeof(*BAR) and sizeof(BAR[0]) are exactly equivalent (and the
parentheses are unnecessary). As implied by the extensive use of
"mudflap" and "MUDFLAP" throughout your message, this is a problem
specific to gcc's -fmudflap option - without that option, gcc generates
identical object code whether or not ASTERISK is #defined. Therefore,
the best place to get answers to this question are on a forum specific
to gcc. I don't know the answer.
 
E

Eric Sosman

I'm looking for the reason of the MUDFLAP violation
on my 'BIG' C project (no possibility to show),
system: Ubuntu:12.04, gcc:4.6.3.

I don't have mudflap available and can't help with it, so
my comments are limited to the C aspects of the question. I hope
they may be of some help anyhow ...
Currently MUDFLAP violates before calling 'main' in
_GLOBAL__sub_I_00099_0_<my_function>

Are you sure this is a C program, and not a C++ program?
In a C program, there's no way for any of your own code to run
before main() is called, whereas in C++ some of your code may
run during pre-main() initialization. I suppose the mudflap
instrumentation might do some non-C-ish things, but ...
if I change source code of <my_function>
from sizeof(*ARRAY)
to sizeof(ARRAY[0])
then violation source shifts to another
_GLOBAL__sub_I_00099_0_... function.

From the perspective of the C language, the two expressions
have identical meaning. That's because of the way C defines the
array subscript operator, in 6.5.2.1p2: "The definition of the
subscript operator [] is that E1[E2] is identical to (*((E1)+(E2)))."
In your case `E1' and `E2' are `ARRAY' and `0', so your second
expression is identical to `sizeof((*((ARRAY)+(0))))', which is
equivalent to `sizeof *ARRAY' after simplification.

Two points, though. First, the expression that is the operand
of `sizeof' isn't evaluated at all (not in this case, anyhow);
all that matters is the expression's type. Second, the compiler
is not required to evaluate two equivalent expressions the same
way; it's perfectly all right for the compiler to emit different
code for `x = 42' and for `x = 40 + 2', or even for `x = 052'.
C requires that `sizeof(*ARRAY)' and `sizeof(ARRAY[0])' produce
the same type and value, but does not require that they use the
same mechanisms to generate the result.
There is amazing difference that depends
on usage of the sizeof operator:
[... sizeof(*BAR) and sizeof(BAR[0]) generate different code ...]
Is there any clear reason of such difference ?

None that I can see -- although, as explained above, C does
not dictate any particular style of code generation. My wild
guess is that since mudflap is concerned with array bounds
checking, the difference may arise from the way mudflap adds
instrumentation: Perhaps it recognizes one construct as an array-
using expression but not the other, and therefore instruments
them differently.
 
K

Keith Thompson

Eric Sosman said:
On 1/9/2013 10:26 AM, (e-mail address removed) wrote: [...]
There is amazing difference that depends
on usage of the sizeof operator:
[... sizeof(*BAR) and sizeof(BAR[0]) generate different code ...]
Is there any clear reason of such difference ?

None that I can see -- although, as explained above, C does
not dictate any particular style of code generation. My wild
guess is that since mudflap is concerned with array bounds
checking, the difference may arise from the way mudflap adds
instrumentation: Perhaps it recognizes one construct as an array-
using expression but not the other, and therefore instruments
them differently.

Mudflap probably shouldn't be instrumenting code that's an argument
to sizeof in the first place, since it's never executed (barring
VLAs).

For example, given `int arr[10];` this expression: `sizeof arr[1000]`
is perfectly valid, and evaluates to the same value as `sizeof
(int)`.

"My code is fine, it must be a bug in the development tools" is
not the first thought you should have, but in this case it's a
distinct possibility.
 
S

Shao Miller

I'm looking for the reason of the MUDFLAP violation
on my 'BIG' C project (no possibility to show),
system: Ubuntu:12.04, gcc:4.6.3.

You don't need to show the big project, but it might help if you showed
the violation!

Are you linking with libmudflap by using '-lmudflap' with GCC?
NOTE: The same 'BIG' project has been successfully executed
on my old system: Ubuntu:10.04, gcc-(version don't remember).
Mudflap was silent.

My investigation shows that there
are called some functions before 'main', like:
_GLOBAL__sub_I_00099_0_<org_fun_name>

Currently MUDFLAP violates before calling 'main' in
_GLOBAL__sub_I_00099_0_<my_function>

if I change source code of <my_function>
from sizeof(*ARRAY)
to sizeof(ARRAY[0])
then violation source shifts to another
_GLOBAL__sub_I_00099_0_... function.

That suggests to me the possibility that you are running afoul of
undefined behaviour _before_ coming across your 'sizeof' usage, because
if you run afoul of undefined behaviour, anything can happen and the
precise nature of the weirdness can depend on things that _shouldn't_
make a difference, such as the difference between your two 'sizeof's.
But this algoritm failed in case MUDFLAP violates
at function that has no usage of sizeof(ARRAY) operator.

That's quite possible, since the undefined behaviour might be invoked
_before_ the 'sizeof' use. That's the thing about undefined
behaviour... While trying to track it down, you might think it's
because of "thing #1". (But it's not.) Then you change "thing #1" and
find that things change! (But you haven't fixed the undefined
behaviour.) But then later it looks like "thing #2" has a problem.
Common for the all functions that MUDFLAP violates is the
static const ARRAY usage, example:

/*--EXAMPLE-BEG----------------*/
01: extern unsigned my_function_check(unsigned a, unsigned b, unsigned c);
02: void my_function(void)
03: {
04: unsigned const SCALE [] = { 0, 1, 2 };
05: unsigned const TOSTEP [][2] = {
06: { 10, 1},
07: { 100, 8}
08: };
09: unsigned s = sizeof(SCALE) / sizeof(SCALE[0]);
10: while (s--)
11: {
12: unsigned i = 0;
13: while (i < (sizeof(TOSTEP) / sizeof(TOSTEP[0])))
14: {
15: unsigned current = 0;
16: unsigned value = 0;
17: current = my_function_check(SCALE, TOSTEP[0], value);
18: if (current)
19: {
20: return;
21: }
22: ++i;
23: }
24: }
25: }
/*--EXAMPLE-BEG----------------*/

In this example I have not found any reason of
violate before calling the main.

There is amazing difference that depends
on usage of the sizeof operator:


It's not that amazing, if undefined behaviour is involved.
--[TEST-BEG]------------------------------
+ uname -a
Linux ldrlinux 3.2.0-35-generic-pae #55-Ubuntu SMP Wed Dec 5 18:04:39 UTC 2012 i686 i686 i386 GNU/Linux
+ gcc --version
gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3
Copyright (C) 2011 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

+ gawk '{printf("%02u: %s\n", NR, $0);}'
+ cat bar.c
01: #include <stddef.h> /* size_t */
02: static int const BAR [] = {0,1,2,3,4};
03: size_t bar_element_sizeof(void) {
04: #if ASTERISK
05: return sizeof(*BAR);
06: #else
07: return sizeof(BAR[0]);
08: #endif
09: }
+ gcc -W -Wall -ansi -pedantic -Werror -fmudflap -DnotASTERISK -c bar.c -o bar_notASTERISK.o
+ gcc -W -Wall -ansi -pedantic -Werror -fmudflap -DASTERISK -c bar.c -o bar_ASTERISK.o
+ objdump -d bar_notASTERISK.o
+ objdump -d bar_ASTERISK.o
+ diff bar_notASTERISK.S bar_ASTERISK.S
2c2
< bar_notASTERISK.o: file format elf32-i386
---
bar_ASTERISK.o: file format elf32-i386
17c17
< d: 83 ec 08 sub $0x8,%esp
---
d: 83 ec 18 sub $0x18,%esp
19,20c19,28
< 15: c9 leave
< 16: c3 ret
---
15: c7 44 24 0c 14 00 00 movl $0x14,0xc(%esp)
1c: 00
1d: c7 44 24 08 04 00 00 movl $0x4,0x8(%esp)
24: 00
25: c7 44 24 04 14 00 00 movl $0x14,0x4(%esp)
2c: 00
2d: c7 04 24 00 00 00 00 movl $0x0,(%esp)
34: e8 fc ff ff ff call 35 <_GLOBAL__sub_I_00099_0_bar_element_sizeof+0x2b>
39: c9 leave
3a: c3 ret
--[TEST-EOF]------------------------------

Is there any clear reason of such difference ?

Yes. The difference is fully permitted, and even useful.

Furthermore, if the undefined behaviour theory is correct, whatever is
going wrong is simply accidentally running into this difference, but the
_difference_ is not the _cause_ of the undefined behaviour, surely.

I'd suggest reviewing _all_ code that is executed _before_ the first
mudflap violation.

- Shao Miller
 
M

m.labanowicz

Ok, after long investigation I have successfully prepared simple C program that illustrates the issue:
3 files:
- bar.h
- bar.c
- main.c

------------[TEST-BEG]-------------------------
+ gawk '{printf("%02u: %s\n", NR, $0);}' bar.h
01: typedef struct
02: {
03: char const * name;
04: int val;
05: } bar_cfg_t;
06: int bar_fun(void);
+ gawk '{printf("%02u: %s\n", NR, $0);}' bar.c
01: #include "bar.h"
02: #include <stddef.h> /* size_t */
03: int bar_fun(void)
04: {
05: int result = 0;
06: bar_cfg_t bar_cfg [] =
07: {
08: {"@", 0},
09: {"#", 0},
10: {"0", 0},
11: {"1", 0},
12: {"2", 0},
13: {"3", 0},
14: {"4", 0},
15: {"5", 0},
16: #ifdef WORKAROUND_FOR_MUDFLAP
17: {"6", 0},
18: #endif
19: {"7", 0}
20: };
21: bar_cfg_t * bc = bar_cfg;
22: size_t i = 0;
23: while (i++ < (sizeof(bar_cfg) / sizeof(bar_cfg[0])))
24: {
25: bc->val = 123 + (unsigned)(bc->name[0]);
26: result += bc->val;
27: ++bc;
28: }
29: return result;
30: }
+ gawk '{printf("%02u: %s\n", NR, $0);}' main.c
01: #include <stdio.h> /* printf, size_t */
02: #include <stdlib.h> /* EXIT_SUCCESS */
03: #include "bar.h"
04: static int foo_fun(void)
05: {
06: int result = 0;
07: unsigned int const TOSTEP [][2] =
08: {
09: { 100u, 1u},
10: { 100u, 8u},
11: { 0x2333445u, 123344u},
12: { 0x2333445u, 1233446u},
13: {0x00BFC000u, 0x20000u},
14: {0x00FFC000u, 0x20000u},
15: {0x01FFC000u, 0x20000u},
16: {0x02FFC000u, 0x20000u},
17: {0x06FFC000u, 0x10000u},
18: {0x0DFFC000u, 0x10000u}
19: };
20: size_t i = 0;
21: while (i < (sizeof(TOSTEP) / sizeof(TOSTEP[0])))
22: {
23: result = TOSTEP[0] + TOSTEP[1];
24: i++;
25: }
26: return result;
27: }
28: int main(void)
29: {
30: printf("Hello World !\r\n");
31: printf("foo_fun = %d\r\n", foo_fun());
32: printf("bar_fun = %d\r\n", bar_fun());
33: return EXIT_SUCCESS;
34: }
+ gcc -ansi -pedantic -Wall -W -Werror -fmudflap -c bar.c
+ gcc -ansi -pedantic -Wall -W -Werror -fmudflap -c main.c
+ gcc -Wl,-Map,a.map main.o bar.o -lmudflap
+ MUDFLAP_OPTIONS=-mode-check -viol-nop -verbose-trace -internal-checking -print-leaks -check-initialization -verbose-violations
+ ./a.out
01: *******
02: mudflap violation 1 (register): time=1357813939.099625 ptr=0xbfe56c28 size=72
03: pc=0xb767685e
04: /usr/lib/i386-linux-gnu/libmudflap.so.0(__mf_register+0x3e) [0xb767685e]
05: ./a.out() [0x8048ce0]
06: ./a.out() [0x8048d42]
07: Nearby object 1: checked region begins 8B into and ends 79B into
08: mudflap object 0x8cbf1e8: name=`constant'
09: bounds=[0xbfe56c20,0xbfe56c6f] size=80 area=static check=0r/0w liveness=0
10: alloc time=1357813939.099612 pc=0xb767685e
11: number of nearby objects: 1
12: mf: alloca stack level 0xbfe56b18
13: Hello World !
14: foo_fun = 234930176
15: bar_fun = 1564
16: *******
17: mudflap violation 2 (unregister): time=1357813939.100370 ptr=0x8cbfa20 size=0
18: pc=0xb76763d6
19: number of nearby objects: 0
20: number of leaked objects: 0
-----[with: WORKAORUND_FOR_MUDFLAP]------------
+ rm -fr bar.o main.o a.map a.out
+ gcc -ansi -pedantic -Wall -W -Werror -fmudflap -DWORKAROUND_FOR_MUDFLAP=1 -c bar.c
+ gcc -ansi -pedantic -Wall -W -Werror -fmudflap -c main.c
+ gcc -Wl,-Map,a.map main.o bar.o -lmudflap
+ MUDFLAP_OPTIONS=-mode-check -viol-nop -verbose-trace -internal-checking -print-leaks -check-initialization -verbose-violations
+ ./a.out
01: mf: harmless duplicate reg 0xbfe45950-0xbfe4599f `constant'
02: mf: alloca stack level 0xbfe45848
03: Hello World !
04: foo_fun = 234930176
05: bar_fun = 1741
06: number of leaked objects: 0
------------[TEST-EOF]-------------------------

Please note, that after applying additional element to array
the issue has gone.

So, if this is valid ANSI-C program then this
is an issue connected to GCC/MUDFLAP.
 
S

Shao Miller

Ok, after long investigation I have successfully prepared simple C program that illustrates the issue:
3 files:
- bar.h
- bar.c
- main.c

------------[TEST-BEG]-------------------------
+ gawk '{printf("%02u: %s\n", NR, $0);}' bar.h
01: typedef struct
02: {
03: char const * name;
04: int val;
05: } bar_cfg_t;
06: int bar_fun(void);

Maybe add a helper macro in here:

#if USE_ASTERISK
# define Countof(array) (sizeof (array) / sizeof *(array))
#else
# define Countof(array) (sizeof (array) / sizeof (array)[0])
#endif
+ gawk '{printf("%02u: %s\n", NR, $0);}' bar.c
01: #include "bar.h"
02: #include <stddef.h> /* size_t */
03: int bar_fun(void)
04: {
05: int result = 0;
06: bar_cfg_t bar_cfg [] =
07: {
08: {"@", 0},
09: {"#", 0},
10: {"0", 0},
11: {"1", 0},
12: {"2", 0},
13: {"3", 0},
14: {"4", 0},
15: {"5", 0},
16: #ifdef WORKAROUND_FOR_MUDFLAP
17: {"6", 0},
18: #endif
19: {"7", 0}
20: };
21: bar_cfg_t * bc = bar_cfg;
22: size_t i = 0;
23: while (i++ < (sizeof(bar_cfg) / sizeof(bar_cfg[0])))
24: {
25: bc->val = 123 + (unsigned)(bc->name[0]);
26: result += bc->val;
27: ++bc;
28: }
29: return result;
30: }

Note that 'i' is being used for iteration over 'bar_cfg', but by line
29, its index is _two_past_ the array. That's worth a bounds-checking
diagnostic, would you agree?

I don't know why you're not using a 'for' loop:

/* Circa line 22 */
size_t i;

for (i = 0; i < Countof(bar_cfg); ++i)
{
bc->val = 123 + (unsigned)(bc->name[0]);
result += bc->val;
++bc;
}
return result;
}
+ gawk '{printf("%02u: %s\n", NR, $0);}' main.c
01: #include <stdio.h> /* printf, size_t */
02: #include <stdlib.h> /* EXIT_SUCCESS */
03: #include "bar.h"
04: static int foo_fun(void)
05: {
06: int result = 0;
07: unsigned int const TOSTEP [][2] =
08: {
09: { 100u, 1u},
10: { 100u, 8u},
11: { 0x2333445u, 123344u},
12: { 0x2333445u, 1233446u},
13: {0x00BFC000u, 0x20000u},
14: {0x00FFC000u, 0x20000u},
15: {0x01FFC000u, 0x20000u},
16: {0x02FFC000u, 0x20000u},
17: {0x06FFC000u, 0x10000u},
18: {0x0DFFC000u, 0x10000u}
19: };
20: size_t i = 0;
21: while (i < (sizeof(TOSTEP) / sizeof(TOSTEP[0])))
22: {
23: result = TOSTEP[0] + TOSTEP[1];
24: i++;
25: }
26: return result;


/* Circa line 20 */
size_t i;

for (i = 0; i < Countof(TOSTEP); ++i)
result = TOSTEP[0] + TOSTEP[1];

return result;
27: }
28: int main(void)
29: {
30: printf("Hello World !\r\n");
31: printf("foo_fun = %d\r\n", foo_fun());
32: printf("bar_fun = %d\r\n", bar_fun());
33: return EXIT_SUCCESS;
34: }
+ gcc -ansi -pedantic -Wall -W -Werror -fmudflap -c bar.c
+ gcc -ansi -pedantic -Wall -W -Werror -fmudflap -c main.c
+ gcc -Wl,-Map,a.map main.o bar.o -lmudflap
+ MUDFLAP_OPTIONS=-mode-check -viol-nop -verbose-trace -internal-checking -print-leaks -check-initialization -verbose-violations
+ ./a.out
01: *******
02: mudflap violation 1 (register): time=1357813939.099625 ptr=0xbfe56c28 size=72
03: pc=0xb767685e
04: /usr/lib/i386-linux-gnu/libmudflap.so.0(__mf_register+0x3e) [0xb767685e]
05: ./a.out() [0x8048ce0]
06: ./a.out() [0x8048d42]
07: Nearby object 1: checked region begins 8B into and ends 79B into
08: mudflap object 0x8cbf1e8: name=`constant'
09: bounds=[0xbfe56c20,0xbfe56c6f] size=80 area=static check=0r/0w liveness=0
10: alloc time=1357813939.099612 pc=0xb767685e
11: number of nearby objects: 1
12: mf: alloca stack level 0xbfe56b18
13: Hello World !
14: foo_fun = 234930176
15: bar_fun = 1564
16: *******
17: mudflap violation 2 (unregister): time=1357813939.100370 ptr=0x8cbfa20 size=0
18: pc=0xb76763d6
19: number of nearby objects: 0
20: number of leaked objects: 0
-----[with: WORKAORUND_FOR_MUDFLAP]------------
+ rm -fr bar.o main.o a.map a.out
+ gcc -ansi -pedantic -Wall -W -Werror -fmudflap -DWORKAROUND_FOR_MUDFLAP=1 -c bar.c
+ gcc -ansi -pedantic -Wall -W -Werror -fmudflap -c main.c
+ gcc -Wl,-Map,a.map main.o bar.o -lmudflap
+ MUDFLAP_OPTIONS=-mode-check -viol-nop -verbose-trace -internal-checking -print-leaks -check-initialization -verbose-violations
+ ./a.out
01: mf: harmless duplicate reg 0xbfe45950-0xbfe4599f `constant'
02: mf: alloca stack level 0xbfe45848
03: Hello World !
04: foo_fun = 234930176
05: bar_fun = 1741
06: number of leaked objects: 0
------------[TEST-EOF]-------------------------

Please note, that after applying additional element to array
the issue has gone.

So, if this is valid ANSI-C program then this
is an issue connected to GCC/MUDFLAP.

MUDFLAP can diagnose stuff that's permitted by C90, such as warning you
that an index used for iteration has gone too far. Usually you want to
index one-past an array, at most. Do the 'for' loops have any problems?

- Shao Miller
 
S

Shao Miller

21: bar_cfg_t * bc = bar_cfg;
22: size_t i = 0;
23: while (i++ < (sizeof(bar_cfg) / sizeof(bar_cfg[0])))
24: {
25: bc->val = 123 + (unsigned)(bc->name[0]);
26: result += bc->val;
27: ++bc;
28: }
29: return result;
30: }

Note that 'i' is being used for iteration over 'bar_cfg', but by line
29, its index is _two_past_ the array. That's worth a bounds-checking
diagnostic, would you agree?

I don't know why you're not using a 'for' loop:

/* Circa line 22 */
size_t i;

for (i = 0; i < Countof(bar_cfg); ++i)
{
bc->val = 123 + (unsigned)(bc->name[0]);
result += bc->val;
++bc;
}
return result;
}

There is another "problem" here, and that's that you are indexing into
the array with two difference indices. I'd suggest either:

/* Circa line 21 */
size_t i;

for (i = 0; i < Countof(bar_cfg); ++i)
{
bar_cfg->val = 123 + (unsigned)(bar_cfg->name[0]);
result += bar_cfg->val;
}
return result;
}

Or:

/* Circa line 21 */
bar_cfg_t * const end = bar_cfg + Countof(bar_cfg);
bar_cfg_t * bc;

for (bc = bar_cfg; bc < end; ++bc)
{
bc->val = 123 + (unsigned)(bc->name[0]);
result += bc->val;
}
return result;
}

(By the way, I like your spaces surrounding your asterisk in the pointer
declaration. :) )

- Shao Miller
 
B

Ben Bacarisse

Ok, after long investigation I have successfully prepared simple C
program that illustrates the issue:
3 files:
- bar.h
- bar.c
- main.c

A data point: your example compiles and runs clean with gcc 4.7.2 and
mudflap 4.7.

<snip>
 
M

m.labanowicz

Code without loops, issue is still present:

----------------------------------------------
+ uname -a
Linux ldrlinux 3.2.0-35-generic-pae #55-Ubuntu SMP Wed Dec 5 18:04:39 UTC 2012 i686 i686 i386 GNU/Linux
+ gcc --version
gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3
Copyright (C) 2011 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ gawk '{printf("%02u: %s\n", NR, $0);}' bar.h
01: int bar_fun(unsigned idx);
02: #define ARRAY_NO_OF_ELEMENTS(a) ((unsigned)(sizeof(a) / sizeof(*a)))
+ gawk '{printf("%02u: %s\n", NR, $0);}' bar.c
01: #include "bar.h"
02: int bar_fun(unsigned idx)
03: {
04: int bar_cfg [][2] =
05: {
06: {9, 0},
07: {8, 1},
08: {7, 2},
09: {6, 3},
10: {5, 4},
11: {4, 5},
12: {3, 6},
13: {2, 7},
14: #ifdef WORKAROUND_FOR_MUDFLAP
15: {1, 8},
16: #endif
17: {0, 9}
18: };
19: return (idx < ARRAY_NO_OF_ELEMENTS(bar_cfg)) ? bar_cfg[idx][1] : -1;
20: }
+ gawk '{printf("%02u: %s\n", NR, $0);}' main.c
01: #include <stdio.h> /* printf */
02: #include <stdlib.h> /* EXIT_SUCCESS */
03: #include "bar.h"
04: static int foo_fun(unsigned idx)
05: {
06: int const TOSTEP [][2] =
07: {
08: {0, 9},
09: {1, 8},
10: {2, 7},
11: {3, 6},
12: {4, 5},
13: {5, 4},
14: {6, 3},
15: {7, 2},
16: {8, 1},
17: {9, 0}
18: };
19: return (idx < ARRAY_NO_OF_ELEMENTS(TOSTEP)) ? TOSTEP[idx][1] : -1;
20: }
21: int main(void)
22: {
23: printf("Hello World !\r\n");
24: printf("foo_fun = %d\r\n", foo_fun(4));
25: printf("bar_fun = %d\r\n", bar_fun(4));
26: return EXIT_SUCCESS;
27: }
+ gcc -ansi -pedantic -Wall -W -Werror -fmudflap -c bar.c
+ gcc -ansi -pedantic -Wall -W -Werror -fmudflap -c main.c
+ gcc -Wl,-Map,a.map main.o bar.o -lmudflap
+ MUDFLAP_OPTIONS=-mode-check -viol-nop -verbose-trace -internal-checking -print-leaks -check-initialization -verbose-violations
+ ./a.out
+ gawk '{printf("%02u: %s\n", NR, $0);}'
01: *******
02: mudflap violation 1 (register): time=1357829219.568594 ptr=0xbfd9f6b8 size=72
03: pc=0xb762b85e
04: /usr/lib/i386-linux-gnu/libmudflap.so.0(__mf_register+0x3e) [0xb762b85e]
05: ./a.out() [0x8048979]
06: ./a.out() [0x80489e2]
07: Nearby object 1: checked region begins 8B into and ends 79B into
08: mudflap object 0x9a021e8: name=`constant'
09: bounds=[0xbfd9f6b0,0xbfd9f6ff] size=80 area=static check=0r/0w liveness=0
10: alloc time=1357829219.568588 pc=0xb762b85e
11: number of nearby objects: 1
12: mf: alloca stack level 0xbfd9f5a8
13: Hello World !
14: foo_fun = 5
15: bar_fun = 4
16: *******
17: mudflap violation 2 (unregister): time=1357829219.569060 ptr=0x9a02678 size=0
18: pc=0xb762b3d6
19: number of nearby objects: 0
20: number of leaked objects: 0
------------[with: WORKAROUND_FOR_MUDFLAP]--------------------
+ rm -fr bar.o main.o a.map a.out
+ gcc -ansi -pedantic -Wall -W -Werror -fmudflap -DWORKAROUND_FOR_MUDFLAP=1 -c bar.c
+ gcc -ansi -pedantic -Wall -W -Werror -fmudflap -c main.c
+ gcc -Wl,-Map,a.map main.o bar.o -lmudflap
+ MUDFLAP_OPTIONS=-mode-check -viol-nop -verbose-trace -internal-checking -print-leaks -check-initialization -verbose-violations
+ ./a.out
+ gawk '{printf("%02u: %s\n", NR, $0);}'
01: mf: harmless duplicate reg 0xbfbc1c50-0xbfbc1c9f `constant'
02: mf: alloca stack level 0xbfbc1b48
03: Hello World !
04: foo_fun = 5
05: bar_fun = 4
06: number of leaked objects: 0
----------------------------------------------

Usage of sizeof(ARRAY[0]) or sizeof(*ARRAY) has no impact to the result,
issue is present.

Best Regards
 
M

m.labanowicz

W dniu czwartek, 10 stycznia 2013 15:37:45 UTC+1 użytkownik Ben Bacarisse napisał:
(e-mail address removed) writes:











A data point: your example compiles and runs clean with gcc 4.7.2 and

mudflap 4.7.

Thanks for information.
I'm going to update my system with newer GCC+MUDFLAP.
 
S

Shao Miller

02: mudflap violation 1 (register): time=1357829219.568594 ptr=0xbfd9f6b8 size=72
03: pc=0xb762b85e
04: /usr/lib/i386-linux-gnu/libmudflap.so.0(__mf_register+0x3e) [0xb762b85e]
05: ./a.out() [0x8048979]
06: ./a.out() [0x80489e2]
07: Nearby object 1: checked region begins 8B into and ends 79B into
08: mudflap object 0x9a021e8: name=`constant'
09: bounds=[0xbfd9f6b0,0xbfd9f6ff] size=80 area=static check=0r/0w liveness=0
10: alloc time=1357829219.568588 pc=0xb762b85e
11: number of nearby objects: 1
12: mf: alloca stack level 0xbfd9f5a8

Oops. Missed 'alloca', before. I'd guess that it has a bug. If you
change your arrays to 'static' storage duration, perhaps the problem
would disappear, as 'alloca' wouldn't be used. - Shao
 
M

m.labanowicz

A data point: your example compiles and runs clean with gcc 4.7.2 and
Upgraded GCC to 4.7:
Linux ldrlinux 3.2.0-35-generic-pae #55-Ubuntu SMP Wed Dec 5 18:04:39 UTC 2012 i686 i686 i386 GNU/Linux
gcc (Ubuntu/Linaro 4.7.2-11precise2) 4.7.2
libmudflap0-4.7-dev

Issue is still present - today I'm giving up :(
 
B

Ben Bacarisse

Upgraded GCC to 4.7:
Linux ldrlinux 3.2.0-35-generic-pae #55-Ubuntu SMP Wed Dec 5 18:04:39 UTC 2012 i686 i686 i386 GNU/Linux
gcc (Ubuntu/Linaro 4.7.2-11precise2) 4.7.2
libmudflap0-4.7-dev

Issue is still present - today I'm giving up :(

Just to confirm:

$ gcc -ansi -pedantic -Wall -W -Werror -fmudflap bar.c main.c -lmudflap
$ ./a.out
Hello World !
foo_fun = 234930176
bar_fun = 1564
$ gcc --version
gcc (Ubuntu/Linaro 4.7.2-2ubuntu1) 4.7.2
Copyright © 2012 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ dpkg -s libmudflap0
Package: libmudflap0
Status: install ok installed
Priority: optional
Section: libs
Installed-Size: 270
Maintainer: Ubuntu Core developers <[email protected]>
Architecture: amd64
Multi-Arch: same
Source: gcc-4.7
Version: 4.7.2-2ubuntu1
Depends: gcc-4.7-base (= 4.7.2-2ubuntu1), libc6 (>= 2.14)
Pre-Depends: multiarch-support
Breaks: gcc-4.1, gcc-4.3 (<< 4.3.6-1), gcc-4.4 (<< 4.4.6-4), gcc-4.5 (<< 4.5.3-2)
Description: GCC mudflap shared support libraries
The libmudflap libraries are used by GCC for instrumenting pointer and array
dereferencing operations.
Homepage: http://gcc.gnu.org/
Original-Maintainer: Debian GCC Maintainers <[email protected]>
$ uname -a
Linux tinky 3.5.0-21-generic-tuxonice #32~ppa1-Ubuntu SMP Tue Dec 18 20:29:04 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux
 
S

Shao Miller

Upgraded GCC to 4.7:
Linux ldrlinux 3.2.0-35-generic-pae #55-Ubuntu SMP Wed Dec 5 18:04:39 UTC 2012 i686 i686 i386 GNU/Linux
gcc (Ubuntu/Linaro 4.7.2-11precise2) 4.7.2
libmudflap0-4.7-dev

Issue is still present - today I'm giving up :(

I was unable to reproduce the violations with:
- gcc version 4.7.2 20120921 (Red Hat 4.7.2-2)
- libmudflap 4.7.2, release 2.fc17

- Shao Miller
 
M

m.labanowicz

I have executed this test on UBUNTU 12.04 on 64 bit machine and issue is not present.

BUT, after change the type of the elemnt array from int(4bytes) to long(8bytes) issue comes back:

--------------------------
+ uname -a
Linux qa-stream-server 3.2.0-29-generic #46-Ubuntu SMP Fri Jul 27 17:03:23 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux
+ gcc --version
gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3
Copyright (C) 2011 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

+ dpkg -s libmudflap0
Package: libmudflap0
Status: install ok installed
Multi-Arch: same
Priority: optional
Section: libs
Installed-Size: 266
Maintainer: Ubuntu Core developers <[email protected]>
Architecture: amd64
Source: gcc-4.6
Version: 4.6.3-1ubuntu5
Depends: gcc-4.6-base (= 4.6.3-1ubuntu5), libc6 (>= 2.14)
Pre-Depends: multiarch-support
Breaks: gcc-4.1, gcc-4.3 (<< 4.3.6-1), gcc-4.4 (<< 4.4.6-4), gcc-4.5 (<< 4.5.3-2)
Description: GCC mudflap shared support libraries
The libmudflap libraries are used by GCC for instrumenting pointer and array
dereferencing operations.
Homepage: http://gcc.gnu.org/
Original-Maintainer: Debian GCC Maintainers <[email protected]>
+ gawk '{printf("%02u: %s\n", NR, $0);}' bar.h
01: int bar_fun(unsigned idx);
02: #define ARRAY_NO_OF_ELEMENTS(a) ((unsigned)(sizeof(a) / sizeof(*a)))
+ gawk '{printf("%02u: %s\n", NR, $0);}' bar.c
01: #include "bar.h"
02: int bar_fun(unsigned idx)
03: {
04: long bar_cfg [][2] =
05: {
06: {9, 0},
07: {8, 1},
08: {7, 2},
09: {6, 3},
10: {5, 4},
11: {4, 5},
12: {3, 6},
13: {2, 7},
14: #ifdef WORKAROUND_FOR_MUDFLAP
15: {1, 8},
16: #endif
17: {0, 9}
18: };
19: return (idx < ARRAY_NO_OF_ELEMENTS(bar_cfg)) ? (int)(bar_cfg[idx][1]) : -1;
20: }
+ gawk '{printf("%02u: %s\n", NR, $0);}' main.c
01: #include <stdio.h> /* printf */
02: #include <stdlib.h> /* EXIT_SUCCESS */
03: #include "bar.h"
04: static int foo_fun(unsigned idx)
05: {
06: long const TOSTEP [][2] =
07: {
08: {0, 9},
09: {1, 8},
10: {2, 7},
11: {3, 6},
12: {4, 5},
13: {5, 4},
14: {6, 3},
15: {7, 2},
16: {8, 1},
17: {9, 0}
18: };
19: return (idx < ARRAY_NO_OF_ELEMENTS(TOSTEP)) ? (int)(TOSTEP[idx][1]) : -1;
20: }
21: int main(void)
22: {
23: printf("Hello World ! (c=%u,s=%u,i=%u,l=%u,p=%u)\r\n", \
24: (unsigned)sizeof(char), (unsigned)sizeof(short), \
25: (unsigned)sizeof(int), (unsigned)sizeof(long), \
26: (unsigned)sizeof(void *));
27: printf("foo_fun = %d\r\n", foo_fun(4));
28: printf("bar_fun = %d\r\n", bar_fun(4));
29: return EXIT_SUCCESS;
30: }
+ export 'MUDFLAP_OPTIONS=-mode-check -viol-nop -verbose-trace -internal-checking -print-leaks -check-initialization -verbose-violations'
+ MUDFLAP_OPTIONS='-mode-check -viol-nop -verbose-trace -internal-checking -print-leaks -check-initialization -verbose-violations'
+ gcc -ggdb -g3 -ansi -pedantic -Wall -W -Werror -fmudflap bar.c main.c -lmudflap
+ ./a.out
+ gawk '{printf("%02u: %s\n", NR, $0);}'
01: *******
02: mudflap violation 1 (register): time=1357902146.588238 ptr=0x7fff9312cfd0 size=160
03: pc=0x7ff09ad05291
04: /usr/lib/x86_64-linux-gnu/libmudflap.so.0(__mf_register+0x41) [0x7ff09ad05291]
05: ./a.out() [0x400d0f]
06: ./a.out(__libc_csu_init+0x5d) [0x400dbd]
07: Nearby object 1: checked region begins 16B before and ends 143B into
08: mudflap object 0x22d6370: name=`constant'
09: bounds=[0x7fff9312cfe0,0x7fff9312d06f] size=144 area=static check=0r/0w liveness=0
10: alloc time=1357902146.588237 pc=0x7ff09ad05291
11: number of nearby objects: 1
12: mf: alloca stack level 0x7fff9312cf20
13: Hello World ! (c=1,s=2,i=4,l=8,p=8)
14: foo_fun = 5
15: bar_fun = 4
16: *******
17: mudflap violation 2 (unregister): time=1357902146.588445 ptr=0x22d6970 size=0
18: pc=0x7ff09ad04e36
19: number of nearby objects: 0
20: number of leaked objects: 0
+ gcc -ggdb -g3 -ansi -pedantic -Wall -W -Werror -fmudflap -DWORKAROUND_FOR_MUDFLAP bar.c main.c -lmudflap
+ ./a.out
+ gawk '{printf("%02u: %s\n", NR, $0);}'
01: mf: harmless duplicate reg 0x7fff7ffebcc0-0x7fff7ffebd5f `constant'
02: mf: alloca stack level 0x7fff7ffebc20
03: Hello World ! (c=1,s=2,i=4,l=8,p=8)
04: foo_fun = 5
05: bar_fun = 4
06: number of leaked objects: 0
 
M

m.labanowicz

W dniu piątek, 11 stycznia 2013 12:03:51 UTC+1 użytkownik (e-mail address removed) napisał:
I have executed this test on UBUNTU 12.04 on 64 bit machine and issue is not present.
BUT, after change the type of the elemnt array from int(4bytes) to long(8bytes) issue comes back:
....

I'm going to check that issue on GCC 4.7.

GCC 4.7 (64bitMachine) issue still present:
$ uname -a
Linux qa-stream-server 3.2.0-29-generic #46-Ubuntu SMP Fri Jul 27 17:03:23 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux
$ gcc --version
gcc (Ubuntu/Linaro 4.7.2-11precise2) 4.7.2
Copyright (C) 2012 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ dpkg -s libmudflap0
Package: libmudflap0
Status: install ok installed
Multi-Arch: same
Priority: optional
Section: libs
Installed-Size: 270
Maintainer: Ubuntu Core developers <[email protected]>
Architecture: amd64
Source: gcc-4.7
Version: 4.7.2-11precise2
Depends: gcc-4.7-base (= 4.7.2-11precise2), libc6 (>= 2.14)
Pre-Depends: multiarch-support
Breaks: gcc-4.1, gcc-4.3 (<< 4.3.6-1), gcc-4.4 (<< 4.4.6-4), gcc-4.5 (<< 4.5.3-2)
Description: GCC mudflap shared support libraries
The libmudflap libraries are used by GCC for instrumenting pointer and array
dereferencing operations.
Homepage: http://gcc.gnu.org/
Original-Maintainer: Debian GCC Maintainers <[email protected]>
 
J

James Kuyper

On 01/11/2013 07:14 AM, (e-mail address removed) wrote:
[more on problems with gcc -mudflap]

I'm curious - why haven't you followed up yet on my suggestion that you
take this question to a gcc forum, such as gnu.gcc.help, where you're
likely to get better answers to your question?

Also, see <http://gcc.gnu.org/bugs/>. <http://gcc.gnu.org/bugzilla/>
lists 64 open bugs containing the word "mudflap". I'd recommend checking
whether any of those bugs matches your problem, before filing a new one.
 
K

Keith Thompson

Shao Miller said:
MUDFLAP can diagnose stuff that's permitted by C90, such as warning you
that an index used for iteration has gone too far. Usually you want to
index one-past an array, at most. Do the 'for' loops have any problems?

As I'm sure you know, it's legal to construct a pointer one element
past the end of an array, but not to dererence it. Constructing a
pointer before the beginning of an array or more than one element
past the end of it, or deferencing a pointer one past the end of it,
has undefined behavior. I'm not aware of any relevant changes in
this area from C90 to C99 to C11.

Are you saying that Mudflap complains about stuff that's legal *and
has defined behavior* in C90? If it complained about something
like this:

int arr[N];
int *ptr;
for (ptr = arr; ptr < arr + N; ptr ++) {
/* ... */
}

that would IMHO be a serious bug in Mudflap.

(I haven't analyzed the posted code, but from the discussion I don't
think that's what's going on.)
 
S

Shao Miller

Shao Miller said:
MUDFLAP can diagnose stuff that's permitted by C90, such as warning you
that an index used for iteration has gone too far. Usually you want to
index one-past an array, at most. Do the 'for' loops have any problems?

As I'm sure you know, it's legal to construct a pointer one element
past the end of an array, but not to dererence it. Constructing a
pointer before the beginning of an array or more than one element
past the end of it, or deferencing a pointer one past the end of it,
has undefined behavior. I'm not aware of any relevant changes in
this area from C90 to C99 to C11.

Are you saying that Mudflap complains about stuff that's legal *and
has defined behavior* in C90? If it complained about something
like this:

int arr[N];
int *ptr;
for (ptr = arr; ptr < arr + N; ptr ++) {
/* ... */
}

that would IMHO be a serious bug in Mudflap.

(I haven't analyzed the posted code, but from the discussion I don't
think that's what's going on.)

Nah, I tried to be careful and chose to type "index" instead of "point".
The code I was criticizing used both an integer index as well as a
pointer. Their pointer would never point more than one past the array,
but their integer would index two past the array. That seems to be
permitted by C90.

I seem to recall some bit about this situation being easily detectable
and reportable as a bonus diagnostic, perhaps in the hopes of alerting
the programmer that there's a better way to write their loop without
stepping out of bounds, conceptually.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,704
Messages
2,569,334
Members
44,615
Latest member
neveseexick

Latest Threads

Top