Hi Alexander,
On 2009-04-18, at 06:33:21 -0400, Alexander Ost via RT wrote:
Show quoted text
Not a problem. A lot of people aren't aware of this.
Show quoted text> But still, I think there's a bug. I tried a little further, and it seems
> I was just lucky that it seems to work with "direct" parsing. It does
> not when re-parsing the output of sourcify. The behaviour should be the
> same in both cases I suppose.
And you're absolutely correct. Yes, there is a bug, albeit it's actually
affecting a subtly different feature: flexible array members.
Flexible array members have been introduced with the 1999 revision of
the C standard, and allow you to declare array members with "arbitrary
size" like this:
struct flex {
int a;
int array[];
};
The semantics of this is that the flexible array member does not contribute
to the actual size of a compound, and that it can grow arbitrarily large.
There's a section on flexible array members in the C::B::C documentation.
Due to the bug, what happens is that
struct flex {
int a;
int array[];
};
is going to be sourcified as
struct flex {
int a;
int array[0];
};
which isn't even valid ANSI/ISO-C.
What bothers me is that there was actually a test case for this in the
C::B::C test suite. However, the logic that evaluated the test result was
complete crap (instead of failing with at least one failed subtest it was
succeeding with at least one successful subtest).
Once I fixed up the logic, tests started failing right away. The fix was
pretty easy, though.
Show quoted text> Please try to decode something that involves such a const; as example,
> take a slighly modified version of your const.c:
>
> x [~/mac/ctest]> cat const.c
> static const int NUM = 2;
>
> struct foo {
> int i1;
> int bar[NUM];
> };
Actually, this is parsed as
struct foo {
int i1;
int bar[];
};
so you're accidentially making use of the "flexible array member" feature.
Show quoted text> and then
>
> A) decode a sample binary string from "direct" parsing:
>
> x [~/mac/ctest]> perl -MConvert::Binary::C -MData::Dumper -e'print
> Dumper(Convert::Binary::C->new->parse_file("const.c")->unpack("struct
> foo", pack("I*", 1, 2, 3 )))'
> $VAR1 = {
> 'i1' => 1,
> 'bar' => [
> 2,
> 3
> ]
> };
> $VAR2 = {
> 'i1' => 2,
> 'bar' => [
> 3
> ]
> };
> $VAR3 = {
> 'i1' => 3,
> 'bar' => []
> };
>
> The result as a whole is wrong, but _the first list element is exactly
> what you'd expect_ if C++ const handling was supported.
No, the result is perfectly correct. At least under the assumption that
the code is parsed as explained above. In list context, 'unpack' will
unpack an array of types, which is why it returns three elements:
mhx@r2d2 ~ $ cat const.c
#include <stdio.h>
struct foo {
int i1;
int bar[];
};
int main(void)
{
union {
int a1[3];
struct foo a2[3];
} a;
a.a1[0] = 1;
a.a1[1] = 2;
a.a1[2] = 3;
printf("%d %d %d\n", a.a2[0].i1, a.a2[0].bar[0], a.a2[0].bar[1]);
printf("%d %d\n", a.a2[1].i1, a.a2[1].bar[0]);
printf("%d\n", a.a2[2].i1);
return 0;
}
mhx@r2d2 ~ $ cc -o const const.c
mhx@r2d2 ~ $ ./const
1 2 3
2 3
3
Another hint that flexible array members are being used is if you stuff
in more input data:
mhx@r2d2 ~ $ perl -MConvert::Binary::C -MData::Dumper -e'print Dumper(scalar Convert::Binary::C->new->parse_file("const.c")->unpack("foo", pack "I*", 1 .. 5))'
$VAR1 = {
'i1' => 1,
'bar' => [
2,
3,
4,
5
]
};
This also shows the effect of scalar context on the "unpack" method.
Show quoted text> B) decode the same string after re-parsing sourcify's output:
>
> x [~/mac/ctest]> perl -MConvert::Binary::C -MData::Dumper -e'print
> Dumper(Convert::Binary::C->new->parse(Convert::Binary::C->new->parse_file("const.c")->sourcify())->unpack("struct
> foo", pack("I*", 1, 2, 3 )))'
> $VAR1 = {
> 'i1' => 1,
> 'bar' => []
> };
> $VAR2 = {
> 'i1' => 2,
> 'bar' => []
> };
> $VAR3 = {
> 'i1' => 3,
> 'bar' => []
> };
>
> ...which is in line with the specified behaviour.
More or less. As I said, this isn't really valid C, but it's easier not
to special-case arrays with no elements.
Show quoted text> Personally, I'd enjoy some fix that "extends" the current const handling
> in "A" to fully correct mode :) ...but I can fully understand that
> blurring up the current parser with C++ features doesn't look very
> attractive :-)
The parser doesn't even see your constant, and "A" is fully correct
(and probably what you expect if you just change it to scalar context).
I've uploaded Convert::Binary::C 0.74 this morning which fixes the
bug in "sourcify". You should now get "A" behaviour also after parsing
code that has been sourcified.
Show quoted text> I'll now work around my bad C++ consts by pre-processing the code and
> replacing all consts by preprocessor symbols.
Don't get me wrong, C++ constants aren't bad. It's just that they're
not compatible with C.
So, thanks for finding a bug that survived for more than five years!
Cheers,
Marcus
--
Isn't it strange that the same people that laugh at gypsy fortune
tellers take economists seriously?