GCC 11 gives -Wstringop-overflow when no string operation is used - arrays

Here is my code.
// test.c
#include <stdio.h>
#define ARRAY_SIZE 4
struct example_t {
int field0;
int field1;
int field2;
int field3;
int field4;
};
struct example_t func(int *in, int array[ARRAY_SIZE]) {
struct example_t out;
return out;
}
int main() {
int array[ARRAY_SIZE] = { 0, 0, 0, 0 };
int a = 0;
struct example_t col = func(&a, array);
return 0;
}
gcc 11.1.0 gave
$ gcc test.c -o test
test.c: In function ‘main’:
test.c:22:26: warning: ‘func’ accessing 16 bytes in a region of size 4 [-Wstringop-overflow=]
22 | struct example_t col = func(&a, array);
| ^~~~~~~~~~~~~~~
test.c:22:26: note: referencing argument 2 of type ‘int *’
test.c:14:18: note: in a call to function ‘func’
14 | struct example_t func(int *in, int array[ARRAY_SIZE]) {
| ^~~~
but g++ didn't.
I don't understand why the warning message is there, since there is no string operation in my code and I never read array in func.
If there are only 4 or fewer fields in struct example_t, GCC won't complain. Can someone please explain why is the message here and how can i fix it?
Thank you in advance.

Related

How to output a big structure to another module in c?

Is there a best practice for ouput function parameters of big structures that should not be changed? return pointer to struct or return whole structure?
Example:
I have a big data structure in file A that i will call from file B: (typedef struct is in header)
.h
typedef struct
{
int x1;
int x2;
int x3;
int x4;
...
} myStruct;
.c
static myStruct data = {...};
errorType myfunction1(mystruct *outData)
{
*outData = data; //copy data to output
...
}
errorType myfunction2(mystruct **outData)
{
*outData = &data; //just return pointer to structure
...
}
myfunction1 copies the whole structure, so the stack size will rise if i will call this function a lot and the processing time is rising, but the advantage is that the original data could not be changed outside of this file like with myfunction2.
Is there a best practice what of the both to use?
I would use the const keyword for the parameter in myfunction2 so that
Case 1: At compilation any changes on a struct used in the caller would definitely make an error if the argument is also a const struct ;
Case 2: And at least a warning if the argument of the caller is not a const.
Case 1:
foo.h
#ifndef FOO_H
#define FOO_H
typedef struct fooStruct
{
int a;
int b;
int c;
}t_fooStruct;
void cpy_foo(const t_fooStruct ** structToCpy);
#endif
foo.c
#include <stdio.h>
#include <stdlib.h>
#include "foo.h"
t_fooStruct myData = {0,1,2};
void cpy_foo(const t_fooStruct ** structToCpy){
*structToCpy = &myData;
}
main.c
#include <stdio.h>
#include <stdlib.h>
#include "foo.h"
int main(){
const t_fooStruct * mainData;
cpy_foo(&mainData);
printf("After cpy print %d %d %d\n", mainData->a, mainData->b, mainData->c);
mainData->a = 10;
mainData->b = 20;
mainData->c = 30;
printf("After changes print %d %d %d\n\n", mainData->a, mainData->b, mainData->c);
return 0;
}
At compilation this gives:
main.c: In function 'main':
main.c:12:15: error: assignment of member 'a' in read-only object
12 | mainData->a = 10;
| ^
main.c:13:15: error: assignment of member 'b' in read-only object
13 | mainData->b = 20;
| ^
main.c:14:15: error: assignment of member 'c' in read-only object
14 | mainData->c = 30;
|
Case 2:
And if the structure is not a const in the main :
main.c (version without the const)
int main(){
t_fooStruct * mainData;
cpy_foo(&mainData);
[...]
At compilation this outputs:
9 | cpy_foo(&mainData);
| ^~~~~~~~~
| |
| t_fooStruct ** {aka struct fooStruct **}
In file included from main.c:3:
foo.h:12:35: note: expected 'const t_fooStruct **' {aka 'const struct fooStruct **'} but argument is of type 't_fooStruct **' {aka 'struct fooStruct **'}
12 | void cpy_foo(const t_fooStruct ** structToCpy);

Define a function pointer to be32toh() function

I'm newly learned about function pointers here but I couldn't define a function pointer to be32toh() or other functions of endian.h header.
First of all, I can do what is told in the given thread:
#include <endian.h>
int addInt(int n, int m) {
return n+m;
}
int main(){
int (*functionPtr)(int,int);
functionPtr = addInt;
return 0;
}
But when I try to do the same for a function like be32toh(), I'll get a compilation error:
#include <stdint.h>
#include <endian.h>
int addInt(int n, int m) {
return n+m;
}
int main(){
int (*functionPtr)(int,int);
functionPtr = addInt;
uint32_t (*newptr)(uint32_t);
newptr = &be32toh;
return 0;
}
Compile as:
$ gcc test.c
Result is as below:
test.c: In function ‘main’:
test.c:15:15: error: ‘be32toh’ undeclared (first use in this function)
15 | newptr = &be32toh;
| ^~~~~~~
test.c:15:15: note: each undeclared identifier is reported only once for each function it appears in
What's the problem and how to fix it?
What's the problem
be32toh is a macro.
how to fix it?
Just write the function yourself.
uint32_t be32toh_func(uint32_t a) {
return be32toh(a);
}
....
newptr = &be32toh_func;

Please help me understand the warning generated in RefTest(). [-Wincompati

warning: returning 'struct example_str **' from a function with incompatible return type 'struct example_str *' [-Wincompatible-pointer-types]
return &(example1_str->member2[index]);
Please help understand why the warning is being generated. When example1_struct->member[index] is called, my understanding is it should return (struct example_struct*) Please help me understand the reason for warning. Thank you in advance.
#include <stdio.h>
#include "stdbool.h"
struct example_str{
int member1;
struct example_str* member2[5];
};
struct example_str* Reftest(int index);
void function2(int id, int* SigVal);
struct example_str* example1_str;
int main()
{
_Bool test;
int Val = (int) test;
function2(10,&Val);
return 0;
}
void function2(int id, int* SigVal){
struct example_str* ptr_to_str;
ptr_to_str = Reftest(1);
ptr_to_str -> member2[1] -> member1 = id;
printf("%d",ptr_to_str -> member2[1] -> member1);
}
struct example_str* Reftest(int index){
return &(example1_str->member2[index]);
}
struct example_str
{
int member1;
struct example_str* member2[5];
};
example_str has 2 members and
member1 is int
member2 is struct example_str*[5], a.k.a. an array of 5 pointers to struct example_str, from member2[0] to member2[4]. 5 pointers.
refTest returns struct example_str*, the same type of each member2
You can align the declarations to see better
struct example_str
{
int member1;
struct example_str* member2[5];
};
struct example_str* Reftest(int index);
So it is clear that whathever member2 is, it is the same that Reftest() returns.
So if you declare, as you did
struct example_str* Reftest(int index)
{
return &(example1_str->member2[index]);
}
As & is the operator address of, you are returning the address of member2[], that is itself a pointer --- struct example_str* --- and for sure its type is struct example_str**
The compilers says that
so0729.c:35:12: warning: returning 'struct example_str **' from a function
with incompatible return type
struct example_str *' [-Wincompatible-pointer-types]
35 | return &(example1_str->member2[index]);
| ^~~~~~~~~~~~~~
And it is what it is. Just take the & off.
Consider using typedef. It is usual and can lead to a code easier to read. And avoid global things declared outside main()
Example
This is a variation of your code using the pointers to pass references back and forth to the structs
#include <stdio.h>
typedef struct st_example_str
{
int member1;
struct st_example_str* member2[5];
} Example;
Example* Reftest(Example*, unsigned);
void function2(Example*, unsigned, int* SigVal);
int main()
{
Example A = {.member1 = 10};
Example B = {.member1 = 11};
Example C = {.member1 = 12};
Example D = {.member1 = 13};
Example E = {.member1 = 14};
Example ex1;
ex1.member1 = 1;
ex1.member2[0] = &A;
ex1.member2[1] = &B;
ex1.member2[2] = &C;
ex1.member2[3] = &D;
ex1.member2[4] = &E; // not used
C.member2[0] = &ex1; // cycle
D.member2[0] = &ex1; // cycle
E.member2[0] = &ex1; // cycle
char test = 42;
int Val = (int)test;
function2(&ex1, 2, &Val); // should set member1 of C to 42...
printf("ids (member1) pointed from the array inside ex1: ");
for (int i = 0; i < 5; i += 1)
printf("%d ", ex1.member2[i]->member1);
printf("\n");
printf("member1 for ex1: %d\n", ex1.member1);
return 0;
}
void function2(Example* E, unsigned id, int* SigVal)
{
// sets member1 of struct pointed by E->member[id] to
// the value pointed to by SigVal
Example* ptr_to_str = Reftest(E, id);
ptr_to_str->member2[0]->member1 = *SigVal;
}
Example* Reftest(Example* E, unsigned index)
{
return E->member2[index];
}
Example output
ids (member1) pointed from the array inside ex1: 10 11 12 13 14
member1 for ex1: 42
And you see that 42, the value of test, gets set in ex1 using a few references

Warning: data definition has no type or storage class despite including header

I am using GLib arrays. The code starts with the right include:
#include <gmodule.h>
I have an sorting function:
gint key_sort(gconstpointer a, gconstpointer b) {...}
And a function where the array is used:
GArray * score_keysizes( ... )
{
GArray * keys = g_array_new (FALSE, FALSE, sizeof(key_candidate));
for (...)
{
...
g_array_append_val(keys,temp);
...
}
g_array_sort(keys,key_sort);
}
However this does not compile.
gcc -c -g -Wall -Wextra -mms-bitfields -IC:/msys64/mingw64/include/glib-2.0 -IC:/msys64/mingw64/lib/glib-2.0/include -IC:/msys64/mingw64/include -o Crypto.o Crypto.c
Crypto.c:345:3: warning: data definition has no type or storage class
g_array_sort(keys,key_sort);
^~~~~~~~~~~~
Crypto.c:345:3: warning: type defaults to 'int' in declaration of 'g_array_sort' [-Wimplicit-int]
Crypto.c:345:3: warning: parameter names (without types) in function declaration
Crypto.c:345:3: error: conflicting types for 'g_array_sort'
In file included from C:/msys64/mingw64/include/glib-2.0/glib.h:31,
from C:/msys64/mingw64/include/glib-2.0/gmodule.h:28,
from Crypto.c:7:
C:/msys64/mingw64/include/glib-2.0/glib/garray.h:114:9: note: previous declaration of 'g_array_sort' was here
void g_array_sort (GArray *array,
^~~~~~~~~~~~
...
This makes it look like it finds the prototype for g_array_sort only after it assumed a prototype. What is happening?
MCVE Code:
#include <stdio.h>
#include <stdlib.h>
#include <gmodule.h>
float hamdist_keyscore(const unsigned char *txtdat, unsigned int txtsize, unsigned int keysize);
typedef struct{
unsigned int key;
float score;
}key_candidate;
gint key_sort(gconstpointer a, gconstpointer b)
{
if (((key_candidate *)a)->score > ((key_candidate *)(b))->score) return 1;
else if (((key_candidate *)a)->score < ((key_candidate *)(b))->score) return -1;
/* if (a.score == b.score)*/ return 0;
}
GArray * score_keysizes(unsigned char* crypt, unsigned int len, unsigned int minkeysize, unsigned int maxkeysize)
{
GArray * keys = g_array_new (FALSE, FALSE, sizeof(key_candidate));
for (unsigned int i = minkeysize; i <= maxkeysize; i++)
{
key_candidate temp;
temp.score = hamdist_keyscore(crypt, len, i);
temp.key = i;
g_array_append_val(keys,temp);
}
}
g_array_sort(keys,key_sort);
return keys;
}
MCVE error on compile:
gcc -c -g -Wall -Wextra -mms-bitfields -IC:/msys64/mingw64/include/glib-2.0 -IC:/msys64/mingw64/lib/glib-2.0/include -IC:/msys64/mingw64/include -o Crypto.test.o Crypto.test.c
Crypto.test.c:35:3: warning: data definition has no type or storage class
g_array_sort(keys,key_sort);
^~~~~~~~~~~~
Crypto.test.c:35:3: warning: type defaults to 'int' in declaration of 'g_array_sort' [-Wimplicit-int]
Crypto.test.c:35:3: warning: parameter names (without types) in function declaration
Crypto.test.c:35:3: error: conflicting types for 'g_array_sort'
In file included from C:/msys64/mingw64/include/glib-2.0/glib.h:31,
from C:/msys64/mingw64/include/glib-2.0/gmodule.h:28,
from Crypto.test.c:3:
C:/msys64/mingw64/include/glib-2.0/glib/garray.h:114:9: note: previous declaration of 'g_array_sort' was here
void g_array_sort (GArray *array,
^~~~~~~~~~~~
Crypto.test.c:37:2: error: expected identifier or '(' before 'return'
return keys;
^~~~~~
Crypto.test.c:38:1: error: expected identifier or '(' before '}' token
}
^
Crypto.test.c: In function 'score_keysizes':
Crypto.test.c:33:2: warning: control reaches end of non-void function [-Wreturn-type]
}
^
The problem becomes evident in your MCVE. Take note of the ### comments I added.
GArray * score_keysizes(unsigned char* crypt, unsigned int len, unsigned int minkeysize, unsigned int maxkeysize)
{ // ### 1
GArray * keys = g_array_new (FALSE, FALSE, sizeof(key_candidate));
for (unsigned int i = minkeysize; i <= maxkeysize; i++)
{ // ### 2
key_candidate temp;
temp.score = hamdist_keyscore(crypt, len, i);
temp.key = i;
g_array_append_val(keys,temp);
} // ### 2
} // ### 1
g_array_sort(keys,key_sort);
return keys;
}
They match opening an closing braces. So g_array_sort is pushed to file scope, and is taken as a function declaration.

Flexible array in C

Im trying to have an unlimited array in C to store some data. My header file stock.h looks like this
#ifndef STOCK_H
#define STOCK_H
typedef struct {
char* id;
char* descripcion;
int precio;
} tAppliance;
typedef struct {
int cantidad;
tAppliance electrodomestico;
} tElectroStock;
typedef struct {
int size;
int capacity;
tElectroStock *electrodomesticos;
} tStock;
void tstock_init(tStock *stock);
void tstock_add(tStock *stock, tAppliance item, int cantidad);
#endif
My stock.c file
#include <stdio.h>
#include "stock.h"
void tstock_init(tStock *stock) {
stock->size = 0;
stock->capacity = 10;
stock->electrodomesticos = malloc(sizeof(tElectroStock) * stock->capacity);
}
void tstock_add(tStock *stock, tAppliance item, int cantidad) {
if(stock->size >= stock->capacity) {
stock->capacity = stock->capacity * 2;
stock->electrodomesticos = realloc(stock->electrodomesticos, sizeof(tElectroStock) * stock->capacity);
}
tElectroStock t;
t.cantidad = cantidad;
t.electrodomestico = item;
stock->size++;
stock->electrodomesticos[stock->size] = t;
}
And finally my main function
#include <stdio.h>
#include "stock.h"
int main(int argc, char **argv)
{
tStock t; // Creamos nuestra variable de stock
tstock_init(&t); // Iniciamos el stock
tAppliance item;
item.descripcion = "Television SONY";
item.id = "apeid9";
item.precio = 20;
tstock_add(&t, item, 1);
tstock_add(&t, item, 1);
}
As you can see on my main function I try to add 2 items to tStock. however adding the second item seems to crash the whole applicattion and no idea why.
Enable all warnings, and treat every single one of them as error. That way you could've found the issue with the member not being a pointer that's already been mentioned yourself.
Check the return value of library functions like malloc and realloc for errors and handle them appropriately.
Finally, you'll want to swap these two lines:
stock->size++;
stock->electrodomesticos[stock->size] = t;
Compile with -Wall you'll be warn:
test.c: In function ‘tstock_init’:
test.c:634:5: warning: implicit declaration of function ‘malloc’ [-Wimplicit-function-declaration]
stock->electrodomesticos = malloc(sizeof(tElectroStock) * stock->capacity);
^
test.c:634:32: warning: incompatible implicit declaration of built-in function ‘malloc’
stock->electrodomesticos = malloc(sizeof(tElectroStock) * stock->capacity);
^
test.c: In function ‘tstock_add’:
test.c:640:9: warning: implicit declaration of function ‘realloc’ [-Wimplicit-function-declaration]
stock->electrodomesticos = realloc(stock->electrodomesticos, sizeof(tElectroStock) * stock->capacity);
^
test.c:640:36: warning: incompatible implicit declaration of built-in function ‘realloc’
stock->electrodomesticos = realloc(stock->electrodomesticos, sizeof(tElectroStock) * stock->capacity);
Add to stock.c:
#include <stdlib.h>
You must also switch instruction as below:
stock->electrodomesticos[stock->size] = t;
stock->size++;
Otherwise your code is UB when stock->size++ == stock->capacity

Resources