473,398 Members | 2,120 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,398 software developers and data experts.

The canonical clc malloc idiom

The comp.lang.c-recommended way to invoke malloc() is, of course:

some_type *ptr;
ptr = malloc(count * sizeof *ptr);

But what if (in C99 only) ptr is a pointer to a VLA (variable-length
array) type? Consider this:

#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int n = 10;
typedef char VLA[n];
VLA *ptr = NULL;
ptr = malloc(3 * sizeof *ptr);
printf("sizeof *ptr = %d\n", (int)sizeof *ptr);
return 0;
}

As far as I can tell, this is legal in C99. The operand of sizeof in
the malloc call is *ptr, which is of a variable-length array type,
which means, according to C99 6.5.3.4p2, that it's evaluated. Since
ptr is a null pointer at that point, evaluating *ptr invokes undefined
behavior.

I'm not suggesting that we should drop the clc-approved method for the
normal case; I suspect that malloc calls involving VLA types are going
to be vanishingly rare. It's just an interesting quirk of the
language.

Incidentally, the above program compiles and executes without error
under gcc in its C99ish mode. That doesn't prove anything, since it's
one possible consequence of UB.

I think I'll post in comp.std.c asking just what C99 6.5.3.4p2 really
means and why the operand is evaluated.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Sep 20 '07 #1
7 1393
On Wed, 19 Sep 2007 21:20:17 -0700, Keith Thompson wrote:
The comp.lang.c-recommended way to invoke malloc() is, of course:

some_type *ptr;
ptr = malloc(count * sizeof *ptr);

But what if (in C99 only) ptr is a pointer to a VLA (variable-length
array) type? Consider this:

#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int n = 10;
typedef char VLA[n];
VLA *ptr = NULL;
ptr = malloc(3 * sizeof *ptr);
printf("sizeof *ptr = %d\n", (int)sizeof *ptr);
return 0;
}

As far as I can tell, this is legal in C99. The operand of sizeof in
the malloc call is *ptr, which is of a variable-length array type,
which means, according to C99 6.5.3.4p2, that it's evaluated. Since
ptr is a null pointer at that point, evaluating *ptr invokes undefined
behavior.

I'm not suggesting that we should drop the clc-approved method for the
normal case; I suspect that malloc calls involving VLA types are going
to be vanishingly rare. It's just an interesting quirk of the
language.

Incidentally, the above program compiles and executes without error
under gcc in its C99ish mode. That doesn't prove anything, since it's
one possible consequence of UB.

I think I'll post in comp.std.c asking just what C99 6.5.3.4p2 really
means and why the operand is evaluated.
And why the restriction to variable length array types?
Again with c99ish gcc this compiles and appears to run correctly:
#include <stdlib.h>
#include <stdio.h>
int main( int argc, char** argv)
{
struct odd
{ int b;
int a[argc];
};
struct odd* p;
printf( "sizeof odd %d\n", sizeof *p);
return EXIT_SUCCESS;
}
I'd have thought that if "evaluation" was required for your ptr, it would
be required for my p too.
Sep 20 '07 #2
On Wed, 19 Sep 2007 21:20:17 -0700, Keith Thompson wrote:
The comp.lang.c-recommended way to invoke malloc() is, of course:

some_type *ptr;
ptr = malloc(count * sizeof *ptr);

But what if (in C99 only) ptr is a pointer to a VLA (variable-length
array) type? Consider this:

#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int n = 10;
typedef char VLA[n];
VLA *ptr = NULL;
ptr = malloc(3 * sizeof *ptr);
printf("sizeof *ptr = %d\n", (int)sizeof *ptr);
return 0;
}

As far as I can tell, this is legal in C99. The operand of sizeof in
the malloc call is *ptr, which is of a variable-length array type,
which means, according to C99 6.5.3.4p2, that it's evaluated. Since
ptr is a null pointer at that point, evaluating *ptr invokes undefined
behavior.

I'm not suggesting that we should drop the clc-approved method for the
normal case; I suspect that malloc calls involving VLA types are going
to be vanishingly rare. It's just an interesting quirk of the
language.

Incidentally, the above program compiles and executes without error
under gcc in its C99ish mode. That doesn't prove anything, since it's
one possible consequence of UB.
But it is a strong clue that it doesn't actually read from *ptr,
since that would be likely to cause a SIGSEGV. I tried declaring
ptr as volatile VLA *, but it still doesn't crash. Whereas the UB
allows it not to actually read from there, the compiler would need
to do a serious amount of language lawyering to behave like that.
A more likely explanation is in http://gcc.gnu.org/c99status.html,
where the support for VLAs is marked as "Broken".

In the C99 rationale I can read:
Side effects in variable length array size expressions are guaranteed to be produced, except in
one context. If a size expression is part of the operand of a sizeof operator, and the result of
that sizeof operator does not depend on the value of the size expression, then it is unspecified
10 whether side effects are produced. In the following example:
{
int n = 5;
int m = 7;
size_t sz = sizeof(int (*)[n++]);
15 }
the value of the result of the sizeof operator is the same as in:
{
int n = 5;
int m = 7;
20 size_t sz = sizeof(int (*)[m++]);
}
Since the value stored in sz does not depend on the size expression, the side effect in n++ is
not guaranteed to occur. Requiring the side effect introduced a burden on some
implementations. Since side effects in this context seemed to have limited utility and are not
25 perceived to be a desired coding style, the Committee decided to make it unspecified whether
these size expressions are actually evaluated.

IOW, "don't do that".
--
Army1987 (Replace "NOSPAM" with "email")
If you're sending e-mail from a Windows machine, turn off Microsoft's
stupid “Smart Quotes” feature. This is so you'll avoid sprinkling garbage
characters through your mail. -- Eric S. Raymond and Rick Moen

Sep 20 '07 #3
Duncan Muirhead <dm***@csl.co.ukwrites:
On Wed, 19 Sep 2007 21:20:17 -0700, Keith Thompson wrote:
[...]
>I think I'll post in comp.std.c asking just what C99 6.5.3.4p2 really
means and why the operand is evaluated.

And why the restriction to variable length array types?
Again with c99ish gcc this compiles and appears to run correctly:
#include <stdlib.h>
#include <stdio.h>
int main( int argc, char** argv)
{
struct odd
{ int b;
int a[argc];
};
struct odd* p;
printf( "sizeof odd %d\n", sizeof *p);
return EXIT_SUCCESS;
}
I'd have thought that if "evaluation" was required for your ptr, it would
be required for my p too.
Yes, that looks like another flaw. I'll post to comp.std.c again.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Sep 20 '07 #4
On Thu, 20 Sep 2007 11:18:25 -0700, Keith Thompson wrote:
Duncan Muirhead <dm***@csl.co.ukwrites:
>On Wed, 19 Sep 2007 21:20:17 -0700, Keith Thompson wrote:
[...]
>>I think I'll post in comp.std.c asking just what C99 6.5.3.4p2 really
means and why the operand is evaluated.

And why the restriction to variable length array types? Again with
c99ish gcc this compiles and appears to run correctly: #include
<stdlib.h>
#include <stdio.h>
int main( int argc, char** argv)
{
struct odd
{ int b;
int a[argc];
};
struct odd* p;
printf( "sizeof odd %d\n", sizeof *p); return EXIT_SUCCESS;
}
I'd have thought that if "evaluation" was required for your ptr, it
would be required for my p too.

Yes, that looks like another flaw. I'll post to comp.std.c again.
You're not allowed to have VLA structure members, so there doesn't have
to be any way for sizeof to deal with VLA structure members. If an
implementation supports them as an extension, the implementation is also
allowed to evaluate them as an operand to sizeof, because it won't affect
any correct program.
Sep 20 '07 #5
Army1987 <ar******@NOSPAM.itwrites:
[...]
In the C99 rationale I can read:
Side effects in variable length array size expressions are
guaranteed to be produced, except in one context. If a size
expression is part of the operand of a sizeof operator, and the
result of that sizeof operator does not depend on the value of
the size expression, then it is unspecified 10 whether side
effects are produced. In the following example:
{
int n = 5;
int m = 7;
size_t sz = sizeof(int (*)[n++]); 15 }
the value of the result of the sizeof operator is the same as in:
{
int n = 5;
int m = 7; 20 size_t sz = sizeof(int (*)[m++]);
}
Since the value stored in sz does not depend on the size
expression, the side effect in n++ is not guaranteed to
occur. Requiring the side effect introduced a burden on some
implementations. Since side effects in this context seemed to have
limited utility and are not 25 perceived to be a desired coding
style, the Committee decided to make it unspecified whether these
size expressions are actually evaluated.

IOW, "don't do that".
I think this is an inconsistency between the Rationale and the
Standard. According to the standard, it's *not*
implementation-defined whether the side effect occurs. C99 6.5.3.4p2:

If the type of the operand is a variable length array type, the
operand is evaluated; otherwise, the operand is not evaluated and
the result is an integer constant.

In the case of

sizeof(int (*)[m++])

the operand is a pointer type, not a VLA type, so it's not evaluated
(assuming that evaluating a type makes sense).

I don't see anything in the standard that makes evaluation of a sizeof
operand implementation-defined; either it's evaluated or it isn't.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Sep 20 '07 #6
Duncan Muirhead <dm***@csl.co.ukwrites:
[...]
And why the restriction to variable length array types?
Again with c99ish gcc this compiles and appears to run correctly:
#include <stdlib.h>
#include <stdio.h>
int main( int argc, char** argv)
{
struct odd
{ int b;
int a[argc];
};
struct odd* p;
printf( "sizeof odd %d\n", sizeof *p);
return EXIT_SUCCESS;
}
I'd have thought that if "evaluation" was required for your ptr, it would
be required for my p too.
Your program contains a constraint violation that gcc is failing to
diagnose.

C99 6.7.2.1p8:

A member of a structure or union may have any object type other
than a variably modified type.

(I was almost finished with my comp.std.c post before I noticed this.)

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Sep 20 '07 #7
Keith Thompson wrote, On 20/09/07 20:12:
Army1987 <ar******@NOSPAM.itwrites:
[...]
>In the C99 rationale I can read:
Side effects in variable length array size expressions are
guaranteed to be produced, except in one context. If a size
expression is part of the operand of a sizeof operator, and the
result of that sizeof operator does not depend on the value of
the size expression, then it is unspecified 10 whether side
effects are produced. In the following example:
{
int n = 5;
int m = 7;
size_t sz = sizeof(int (*)[n++]); 15 }
the value of the result of the sizeof operator is the same as in:
{
int n = 5;
int m = 7; 20 size_t sz = sizeof(int (*)[m++]);
}
Since the value stored in sz does not depend on the size
expression, the side effect in n++ is not guaranteed to
occur. Requiring the side effect introduced a burden on some
implementations. Since side effects in this context seemed to have
limited utility and are not 25 perceived to be a desired coding
style, the Committee decided to make it unspecified whether these
size expressions are actually evaluated.

IOW, "don't do that".

I think this is an inconsistency between the Rationale and the
Standard. According to the standard, it's *not*
implementation-defined whether the side effect occurs. C99 6.5.3.4p2:

If the type of the operand is a variable length array type, the
operand is evaluated; otherwise, the operand is not evaluated and
the result is an integer constant.

In the case of

sizeof(int (*)[m++])

the operand is a pointer type, not a VLA type, so it's not evaluated
(assuming that evaluating a type makes sense).

I don't see anything in the standard that makes evaluation of a sizeof
operand implementation-defined; either it's evaluated or it isn't.
In N1124 and N1256 you have in 6.7.5.2 para 5:
If the size is an expression that is not an integer constant
expression: if it occurs in a declaration at function prototype
scope, it is treated as if it were replaced by *; otherwise,
each time it is evaluated it shall have a value greater than zero.
The size of each instance of a variable length array type does not
change during its lifetime. Where a size expression is part of the
operand of a sizeof operator and changing the value of the size
expression would not affect the result of the operator, it is
unspecified whether or not the size expression is evaluated.

which I believe is inconsistent with the paragraph you quoted. So I
think it is a defect in the standard.

Since my comment is about the standard itself I've cross-posted to
comp.std.c
--
Flash Gordon
Sep 20 '07 #8

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

17
by: Axel | last post by:
Hiho, here my Newbie question (Win32 GUI): I'm reading a file in binary mode to a char* named buffer. I used malloc(filesize) to make the needed space avaiable. The filedata in the buffer...
13
by: Richard | last post by:
vector<char*> m_Text; m_Text.resize(1); char* foo = "FOO"; char* bar = "BAR"; char* foobar = (char*)malloc(strlen(foo) + strlen(bar) + 1); if (foobar) { strcpy(foobar, foo); strcat(foobar,...
29
by: David Hill | last post by:
Is there a difference between: /* code 1 */ struct sample test; test = malloc(sizeof(struct sample)); memset(&test, 0, sizeof(test)); /* code 2 */ struct sample test; test = calloc(1,...
34
by: Richard Hunt | last post by:
I'm sorry for asking such a silly question, but I can't quite get my head around malloc. Using gcc I have always programmed in a lax C/C++ hybrid (which I suppose is actually c++). But I have...
9
by: relient | last post by:
Hi, I have a question about malloc. When I do this: char **p = malloc(12); does malloc implicitly do 12 * sizeof(char*) for me? or would I have to explicitly do it? If it does not...
2
by: dkumar142 | last post by:
Hello frnds, I have a question. I know answer is quite easy but i think i am missing some poiter or something..somewhere. I have to define an array of string char **s_array1; now i have...
318
by: jacob navia | last post by:
Rcently I posted code in this group, to help a user that asked to know how he could find out the size of a block allocated with malloc. As always when I post something, the same group of people...
10
by: Yevgen Muntyan | last post by:
Consider the following macro: #define ALLOCIT(Type) ((Type*) malloc (sizeof (Type))) The intent is to wrap raw memory allocation of N bytes into a macro which returns allocated chunk of memory...
101
by: Tinkertim | last post by:
Hi, I have often wondered if casting the return value of malloc() (or friends) actually helps anything, recent threads here suggest that it does not .. so I hope to find out. For instance : ...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.