I'm at exercise 17 of Learn C the hard way,which require building a database and store it in a FILE.I have initialized a database as expected, but when I increased the number of rows (particularly over the threshold of 100) in the database, it returned
Exception: STATUS_ACCESS_VIOLATION at rip=0010040132C.
I used GDB to search for the error, and here's the result.
Thread 1 "ex17" received signal SIGSEGV, Segmentation fault.
0x000000010040132c in Database_create (conn=0x600049490, max_data=12, >max_rows=200) at ex17_1.c:87
87 (conn->db->rows +isizeof(struct Address)) =addr;
Here's the code I have used.
struct Address{
int id;
int set;
char *name;
char *email;
};
struct Database{
int MAX_ROWS;
int MAX_DATA;
struct Address *rows;
};
struct Connection{
FILE *file;
struct Database *db;
};
void Database_create(struct Connection *conn,int max_data,int max_rows){
conn->db->MAX_DATA =max_data;
conn->db->MAX_ROWS = max_rows;
conn->db->rows =malloc(max_rows*sizeof(struct Address));
for(int i=0;i<max_rows;i++){
struct Address addr = {.id =i,.set = 0};
*(conn->db->rows +i*sizeof(struct Address)) =addr;
}
}
I have done some research and I think that STATUS_ACCESS_VIOLATION occurs when
you access a part of memory you are not supposed to. But I have not seen the error in my code yet.
Can someone check what is the possible reason here?
The error is on this line
+i*sizeof(struct Address)
The compiler already multiplies by the size when adding to pointers so don't do it again. You want only
+i
Related
Is there a way to increase the size of ebpf stack getting "error looks like the bpf stack limit of 512 bytes is exeeded", so is there a ebpf helper function or command that I can use to increase the sizeof stack so won't get this error
On this page it says this, but it was posted some time ago; I wonder if there is any work around this limitation:
Currently, no. The stack size is limited to 512 bytes, and there is no kmalloc style dynamic allocation inside the bpf program either. One way you could try is with per-cpu map with value size of 4k and fill in the 4k map value and submit it with the map value. But I never tried this before.
This is my ebpf function
struct {
__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
__type(key, long);
__type(value, long);
__uint(max_entries, 1024);
} tcp_map SEC(".maps");
struct buffer2
{
char buffer[1024];
};
SEC("kprobe/__sys_sendto")
int bpf_prog3(struct pt_regs *ctx)
{
char buf[300];
struct buffer2 buf1;
int fd = (int)PT_REGS_PARM1(ctx);
//cha ptr=(char *)PT_REGS_PARM2(ctx);
//char *buffer=(char *)ptr;
bpf_probe_read(buf1.buffer,1023,(void *)PT_REGS_PARM2(ctx));
bpf_trace_printk("[fd = %d]\n",sizeof("[fd = %d]\n"),fd);
bpf_trace_printk("[buffer = %x]\n",sizeof("[buffer = %x]\n"),buf);
long ptr3=PT_REGS_PARM3(ctx);
if(ptr3>0)
bpf_trace_printk("***********************************************\n",sizeof("***********************************************\n"));
bpf_trace_printk("[count = %ld]\n",sizeof("[count = %d]\n"),ptr3);
long *value;
value = bpf_map_lookup_elem(&tcp_map, buf1.buffer);
bpf_map_update_elem(&tcp_map, 0, &buf1, BPF_ANY);
}
I like to read 1024 bytes from function parameter 2 using bpf_probe_read(buf1.buffer,1023,(void *)PT_REGS_PARM2(ctx)) and then share the buf1 struct object to userspace in this trace.
I have a client process that builds an IPC message struct queue_msg that is being sent to a server via the linux IPC msg queue. 68 bytes in size. struct is defined as:
struct FOO_TYPE {
long mtype;
struct {
int sev;
char msg[32];
char bt[32];
} foomsg;
};
the client declares a pointer to the a struct of FOO_TYPE locally in the function and mallocs space for it. the code then loads the sev, msg and bt fields.
static struct FOO_TYPE *FooEntry = NULL;
...code clipped
if (FooEntry == NULL)
FooEntry = malloc(sizeof(struct FOO_TYPE));
memset(FooEntry, 0, sizeof(struct FOO_TYPE));
...code clipped
MsgSize = sizeof(FooEntry) - sizeof(long);
FooEntry->mtype = CHANGESTATUS;
FooEntry->foomsg.sev = serr->serr_data->sev;
strcpy(FooEntry->syserrmsg.emsg, elog);
strcpy(FooEntry->syserrmsg.bt, btlog);
... code clipped
result = msg_snd(FooExchange, FooEntry, MsgSize, IPC_WAIT);
the server receiving the IPC msg is getting 68 bytes (ie: sizeof FOO_TYPE), however intermittently, the fields inside are either missing or garbage.
do I have to malloc space for the fields in the struct inside the structure as well??
This is at least one bug:
MsgSize = sizeof(FooEntry) - sizeof(long);
FooEntry is a pointer defined here:
static struct FOO_TYPE *FooEntry = NULL;
so sizeof(FooEntry) gives you the size of a pointer - not the size of a struct.
You probably want
MsgSize = sizeof(*FooEntry) - sizeof(long);
or perhaps just
MsgSize = sizeof(FooEntry->foomsg);
I'm new to C, and I'm trying to write simple schedule program. I have rooms and want to fill them with events.
static void create_dummy_data()
{
#define max_entries 5
struct event
{
char *event_name;
int duration_min; // duration in minutes
};
struct room
{
char *room_name;
struct event *events[10];
};
int i = 0;
char *names[] = {"Room1", "Room2", "Room3", "Room4", "Room5", "Room6"};
struct room *rooms[max_entries];
for ( i = 0; i < max_entries ; i++)
{
rooms[i]->room_name = names[i]; // The problem is here
}
}
I'm getting error "8263 segmentation fault (core dumped)"
When you declare struct room *rooms[max_entries]; you will have in the data segment an array of max_entries pointers that are initialized to NULL.
As you do not allocate memory for your room, it means that when you write rooms[i]->room_name you will have essentially done the same as NULL->room_name. The memory protection mechanism of you system detects that you want to access a memory portion that is not allowed and signals it to you with a segmentation fault.
you have to add:
rooms[i] = malloc(sizeof (struct room));
if(!rooms[i]) exit(EXIT_FAILURE); // example error handling, can be different
to your loop.
BTW: it is usage in C to define macros in all caps so that it is immediately visible that it is a macro. You should therefore use
#define MAX_ENTRIES 5
instead.
I am working on an embedded platform which does not have debugging features. So it is hard to say what is the error source.
I have defined in header file:
typedef struct cm_packet {
CM_Header Header; //header of packet 3 bytes
uint8_t *Data; //packet data 64 bytes
CM_Footer Footer; //footer of packet 3 bytes
} CM_Packet;
typedef struct cm_inittypedef{
uint8_t DeviceId;
CM_Packet Packet;
} CM_InitTypeDef;
extern CM_InitTypeDef cmHandler;
void CM_Init(CM_InitTypeDef *handler);
CM_AppendResult CM_AppendData(CM_InitTypeDef *handler, uint8_t identifier
, uint8_t *data, uint8_t length);
And somewhere in implementation I have:
uint8_t bufferIndex = 0;
void CM_Init(CM_InitTypeDef *cm_initer) { //init a handler
cmHandler.DeviceId = cm_initer->DeviceId;
CM_Packet cmPacket;
cmPacket.Header.DeviceId = cm_initer->DeviceId;
cmPacket.Header.PacketStart = CM_START;
cmPacket.Footer.PacketEnd = CM_END;
//initialize data array
uint8_t emptyBuffer[CM_MAX_DATA_SIZE] = {0x00};
cmPacket.Data = emptyBuffer;
cm_initer->Packet = cmPacket;
}
CM_AppendResult CM_AppendData(CM_InitTypeDef *handler, uint8_t identifier
, uint8_t *data, uint8_t length){
//some check to see if new data does not make Data overflow
uint8_t i;
/*** ERROR HAPPENS HERE!!!! ***/
handler->Packet.Data[bufferIndex++] = identifier;
//now add the data itself
for(i = 0; i < length; i++) {
handler->Packet.Data[bufferIndex++] = data[i];
}
//reset indexer
if(bufferIndex > 64) {
PacketReady(); //mark packet as ready
bufferIndex = 0
};
//return result
}
The idea is to update the Packet.Data from some other source codes which have access to the handler. For example some other sources can call that Append function to change Packet.Data. But as you see in the code, I have commented the place which causes the micro-controller to go in hard fault mode. I am not sure what is happening here. All I know is exactly at that line micro goes into hard fault mode and never recovers!
This might be a race condition but before anything else I want to know I have written correct c !!! code then I try to rule out other problems.
In function CM_Init, you are setting cmPacket.Data to point to a local array:
uint8_t emptyBuffer[CM_MAX_DATA_SIZE] = {0x00};
cmPacket.Data = emptyBuffer;
Accessing this memory address outside the scope of the function yields undefined behavior.
As #barak manos mentioned, the buffer supplied to Data is allocated on the stack.
When you get to CM_AppendData, you are writing over memory that is no longer dedicated to the buffer.
You may want to use malloc so that the buffer is allocated on the heap instead of on the stack. Just remember to call free so that you are not leaking memory.
If you can't use dynamic allocation, it's possible to dedicate some scratch memory for all the Data uses. It just needs to be static.
Hope that helps :)
I've been working with stm32f103, now I'm trying to lunch some codes on stm32f407.
To communicate through USART interface I use fifo query in form of structure, defined in header file:
#define FIFO_BUF_SIZE 128
typedef struct {
char data[FIFO_BUF_SIZE];
uint16_t startIndex;
uint16_t endIndex;
}FIFO, *ptrFIFO;
Global declaration of this structure in source file:
FIFO RX_Buff={{},0,0};
FIFO TX_Buff={{},0,0};
Now I want to put data from char array to fifo query:
void USART_PrintData(USART_TypeDef * USART, char str[]){
ptrFIFO pTX = &TX_Buff;
int i=0;
while(str[i]!='\0'){
FIFO_Put(pTX, str[i]);
i++;
}
//here in working program is code for sending data
//deleted from program for tests
}
void FIFO_Put(ptrFIFO fifo, char data){
uint16_t tmp;
tmp = fifo->startIndex;
fifo->data[tmp]=data;
tmp = (tmp+1)%(FIFO_BUF_SIZE-1);
fifo->startIndex=tmp;
}
This code has been worked on stm32f103 but won't on f407. After last sign passed to FIFO_Put() and write to fifo query, programm go to Default_Handler or strange address in memory (depends of humor), but when I using this structure directly it works fine:
void FIFO_Put(char data){
uint16_t tmp;
tmp = TX_Buff.startIndex;
TX_Buff.data[tmp]=data;
tmp = (tmp+1)%(FIFO_BUF_SIZE-1);
TX_Buff.startIndex=tmp;
}
I have no idea what's wrong.
Thanks for any help.
I've tried to debug, and the problem is in last line in function FIFO_Put():
fifo->startIndex=tmp;
When function putting last sign to fifo, after last line program jump to default_handler.
If I comment this line, program works fine.
Check the program stack size - from my experience, such kind of undefined behavior may be caused by stack overflow.