Find Reserved Memory Size for Character Array in C

I am trying to learn C, and in the beginning, I started writing strcpy for my own practice. As we know, the strcpy source file easily resolves security problems, so I gave myself the task of writing "safe" strcpy.

The way I chose is to check if the source string (array of characters) really fits in the target memory. As I understand it, a string in C is nothing more than a pointer to an array of characters, 0x00 is complete.

So my task is to find out how much memory the compiler has reserved for the target string?

I tried:

sizeof(dest) 

but this will not work, as it will return (as I found out later) the dest size, which is actually a pointer and on my 64-bit machine, will always return 8.

I also tried:

 strlen(dest) 

but this does not work either because it simply returns the length until the first 0x0 is encountered, which does not necessarily reflect the reserved memory.

So, this all leads to the next question: how to find our memory that the compiler has reserved for my target "string" ???

Example:

 char s[80] = ""; int i = someFunction(s); // should return 80 

What is "someFunction"?

Thanks in advance!

+4
source share
8 answers

You can use sizeof to check at compile time:

 char s[80] = ""; int i = sizeof s ; // should return 80 

Note that this fails if s is a pointer:

 char *s = ""; int j = sizeof s; /* probably 4 or 8. */ 

Arrays are not pointers. To track the size allocated to a pointer, the program simply needs to track it. In addition, you cannot pass an array to a function. When you use an array as an argument to a function, the compiler converts it to a pointer to the first element, so if you want the size to be available for the called function, it must be passed as a parameter. For instance:

 char s[ SIZ ] = ""; foo( s, sizeof s ); 
+2
source

Once you pass the char pointer to the function you are writing, you will lose knowledge of how much memory is allocated for s. You need to pass this size as an argument to the function.

+4
source

So, this all leads to the next question: how to find our memory that the compiler has reserved for my target "string" ???

There is no portable way to find out how much memory is allocated. You must track this yourself.

The implementation should keep track of how much memory the malloc ed pointer has, and this can do something for you. For example, glibc malloc.h provides

 size_t malloc_usable_size (void *__ptr) 

which gives you access to about that kind of information, however it does not tell you how much you requested, but how much you can use. Of course, this only works with pointers you got from malloc (and friends). For an array, you can only use sizeof , where the array itself is in scope.

+2
source
 char s[80] = ""; int i = someFunction(s); // should return 80 

The expression s has a pointer to the first element of the array s . You cannot infer the size of an array with only information about the value of a pointer to its first element. The only thing you can do is to save information about the size of the array after declaring the array (here sizeof s ), and then pass this information to those functions that need it.

+1
source

There is no portable way to do this. However, the implementation, of course, must know this information domestically. Unix-oriented operating systems, such as Linux and OS X, provide functions for this task:

 // OS X #include <malloc/malloc.h> size_t allocated = malloc_size(somePtr); // Linux #include <malloc.h> size_t allocated = malloc_usable_size(somePtr); // Maybe Windows... size_t allocated = _msize(somePtr); 
+1
source

The way to mark the item returned by malloc is always malloc extra sizeof (size_t) bytes. Add this to the malloc address, and you have a place to store the actual length. Save the malloced size - sizeof (size_t), and you have the basis for your new feature set.

When you pass these two types of pointers to your new special strcpy, you can subtract sizeof (size_t) from the pointers and access dimensions directly. This allows you to decide whether it is safe to copy memory.

If you do strcat, then two sizes along with strlens calculation means that you can do the same check to see if the strcat results will overflow memory.

It is doable. This is probably more of a problem than it costs.

Consider what happens if you pass a pointer to a character that has not been split. It is assumed that the size is before the pointer. This assumption is incorrect. Trying to access the size in this case is undefined behavior. If you are lucky, you can get a signal.

Another consequence of this kind of implementation is that when you go to free memory, you need to pass exactly-the-malloc-returned pointer. If you do not receive this right, heap damage may occur.

In short ... Don't do it this way.

0
source

In situations where you use character buffers in your program, you can make smoke and mirrors to get the effect you want. Something like that.

 char input[] = "test"; char output[3]; if (sizeof(output) < sizeof(input)) { memcpy(output,input,sizeof(input) + 1); } else { printf("Overflow detected value <%s>\n",input); } 

You can improve the error message by erasing the code in the macro.

 #define STRCPYX(output,input) \ if (sizeof(output) < sizeof(input)) \ { \ memcpy(output,input,sizeof(input) + 1); \ } \ else \ { \ printf("STRCPYX would overflow %s with value <%s> from %s\n", \ #output, input, #input); \ } \ char input[] = "test"; char output[3]; STRCPYX(output,input); 

Although this gives you what you want, the same risks apply.

 char *input = "testing 123 testing"; char output[9]; STRCPYX(output,input); 

the input size is 8, and the output is 9, the output value ends as "Testing"

C was not intended to protect the programmer from malfunctioning. It is like trying to jump up the river :) This is a good exercise to think about.

0
source

Although arrays and pointers may seem interchangeable, they differ in one important aspect; the array has a size. However, due to the fact that the array passed to the function "decomposes" into a pointer, size information is lost.

The fact is that at some point you know the size of the object - because you selected it or declared it a specific size. C undertakes to maintain and disseminate this information as necessary. So after your example:

 char s[80] = ""; // sizeof(s) here is 80, because an array has size int i = someFunction(s, sizeof(s)) ; // You have to tell the function how big the array is. 

There is no β€œmagic” method for determining the size of an array within someFunction() , since this information is discarded (for performance and efficiency reasons) C is relatively low in this regard and does not add code or data that is not explicit); if information is needed, you must explicitly pass it on.

One of the ways that you can pass a string and save size information, and even pass a string by copying, rather than a link, is to wrap the string in the structure like this:

 typedef struct { char s[80] ; } charArray_t ; 

then

 charArray_t s ; int i = someFunction( &s ) ; 

with the definition of someFunction() as:

 int someFunction( charArray_t* s ) { return sizeof( s->s ) ; } 

However, you do not earn much, just avoid the extra option; in fact, you are losing some flexibility because someFunction() now only accepts the fixed length of the array defined by charrArray_t , and not any array. Sometimes such restrictions are useful. A feature of this approach is that you can pass by copy :

 int i = someFunction( s ) ; 

then

 int someFunction( charArray_t s ) { return sizeof( ss ) ; } 

since structures, unlike arrays, can be transferred this way. You can also return a copy. However, this may be somewhat ineffective. Sometimes convenience and safety outweigh inefficiency.

0
source

All Articles