Linux kernel: why does this call to kstrtol crash? - c

I am learning kernel programming and have a simple call to kstrtol I am using to convert a string to a number. However, everytime I compile this module and use insmod to place it in the kernel, I get "BUG: unable to handle kernel paging request at f862b026" and then a register and stack dump.
I'm following the definition from here: https://www.kernel.org/doc/htmldocs/kernel-api/API-kstrtol.html. It seems like a really simple call. What am I doing wrong here?
#include <linux/kernel.h>
static int __init convert(void)
{
long myLong;
char *myNumber = "342";
myNumber[2] = '\0'; //Overwriting the '2', just so I know for sure I have a terminating '\0'
if (kstrtol(myNumber, 10, &myLong) == 0)
{
printk("We have a number!\n");
}
return 0;
}
static void __exit convert_exit(void)
{
printk("Module unloaded\n");
}
module_init(convert);
module_exit(convert_exit);

You cannot modify string literals. Copy it into an array firstly.
edit: use this instead
char mystr[] = "abdc";
edit2:
the underlying reason for this is, that a char pointer to a string literal points to a data segment, usually readonly. If you alter this memory you might get a crash.
When you create an array of chars instead, the string literal gets copied into the array on the stack, where you safely can modify it.

Related

Freeing a buffer in C that was created in a function [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 months ago.
Improve this question
I'm having some problems trying to free a buffer created in a function from outside that function in C. What I'm doing is to create bufA, do some stuff with it, then call a function which creates bufB, whose length is calculated inside that function. Bytes in bufA are then copied to bufB with some additional bytes added, then the function returns. Some further processing is done with bufB back in main(), then both bufA and bufB are freed. The program runs correctly, but throws an error when free(bufB) is called.
For very much simplified code, I have something like this:
typedef unsigned char BYTE;
// -----
int main(void) {
// -----
BYTE bufA = NULL;
// Specify lenBufA
bufA = calloc(lenBufA, 1);
// Populate bufA with some stuff.
BYTE bufB = NULL;
int lenBufB = myFunction(bufA, &bufB);
// Do something with bufB.
free(bufA);
free(bufB); // <=== Throws an error here.
return 0;
}
Then in myFunction() I may have something like this:
int myFunction(BYTE* inBuf, BYTE** outBuf) {
// Initialization.
// Calculate the length that outBuf will have and put it in outLen.
*outBuf = (BYTE*)calloc(outLen, 1);
// Do stuff with outBuf.
return outLen;
}
inBuf is not specified as constant as some bytes may be changed. calloc() rather than malloc() is used in main() and in the function because I want the bytes in both buffers to be initialized to zero, as a few bytes in both are not given values.
I'm using visual Studio 2022 with Windows 10. Somehow the error caused by free(bufB) must be related to the fact that memory is allocated in the function, not in main(). How is this fixed?
Your code is incomplete and does not compile. The main issue appears to be that the type of bufA and bufB is BYTE but should be a pointer BYTE *. Here is working code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef unsigned char BYTE;
int myFunction(const BYTE *inBuf, BYTE **outBuf) {
int outLen = strlen(inBuf);
*outBuf = calloc(outLen, 1);
if(!*outBuf) {
printf("calloc failed\n");
exit(1);
}
return outLen;
}
int main(void) {
BYTE *bufA = NULL;
int lenBufA = 42;
bufA = calloc(lenBufA, 1);
if(!bufA) {
printf("calloc failed\n");
exit(1);
}
memset(bufA, !'\0', lenBufA - 1); // heh
BYTE *bufB = NULL;
int lenBufB = myFunction(bufA, &bufB);
free(bufA);
free(bufB);
return 0;
}
It checks the return code of calloc, clarifies with const BYTE *inBuf that function doesn't change that argument.
On Googling ntdll.dll, it appears to be a Windows file of some type, and based on some blurb, it might be corrupted.
Accordingly, I copied the source files to another Windows 10 computer that also has Visual Studio 2022 installed, created a project, then compiled the source code. On executing I get the same message with different hex codes, However the hex code for sixbit-encoding6.exe is the same. Unfortunately the copy and paste feature of the mouse doesn't work for the message on that computer, but it thus looks as if the dll is probably not corrupted, and there is a problem with my application.

C program : function not being called from main

I am programming the Renesas RX63N microcontroller, in C using Renesas High-performance Embedded Workshop. The problem that I face is that a function, connectWiFi(), is not being executed from main. Following is the function's prototype:
typedef char String[5000];
void connectWiFi(String id, int auth, String psk);
The function body is this:
void connectWiFi(String id, int auth, String psk)
{
printf("log 0.1\n");
char cwTemp2[10];
String one,two,three;
...
}
And I am calling the function from main as follows
void main(void)
{
initPhant("data.sparkfun.com", "Public_Key", "Private_Key");
xB_begin(XBEE_BAUD);//uart initialization
// Set up WiFi network
printf("Testing network\n");
// connectWiFi will attempt to connect to the given SSID,
//using encryption mode "encrypt", and the passphrase string given.
printf("log0\n");
connectWiFi("abcd", 2, "qwerty");
// Once connected, print out our IP address
printf("Connected!\n");
....
}
As you see, I am using the printf() calls to log the progress of the execution. But the debugger console prints only these:
Testing network
log0
The next printf() statement is not being printed. Thus I believe that the execution never reaches the function.
Another weird thing here is that the code actually stops running after printing "log0"- when I look at the program counter in the dissambler(a part of the debugger) at this point, the instruction it is stuck at, is labelled "???".
Thanks in advance for your help, I've been cracking my head for several hours on this problem.
The problem is the following:
void connectWiFi(String id, int auth, String psk)
{
printf("log 0.1\n");
char cwTemp2[10];
...
}
You didn't specify what ... contains but you had previously defined
typedef char String[5000];
So, because the line before the connectWiFi call is executed but the first line of the connectWiFi function is not executed, it looks like ... contains String declarations which cause the stack to overflow.
This is especially likely on microcontroller systems that have a limited stack space.
The solution is to not allocate such large strings from the stack. Allocating such large strings from the heap should be avoided too as microcontrollers have limited memory. Better to allocate exactly how many bytes you need.

protoc-c: Nested structure with optional string throws seg fault

Trying out Google protocol buffers for my code in C language.
messagefile.proto
===================
mesage othermessage
{
optional string otherstring = 1;
}
message onemessage
{
optional string messagestring = 1;
optional int32 aninteger = 2;
optional othermessage otr_message= 3;
}
==============================================
--> protoc-c messagefile.proto --c_out=./
this resulted in two files
--> messagefile.pb-c.c and messagefile.pb-c.h
Now my code file which would try to use the
simpleexample.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "messagefile.pb-c.h"
#include <stdbool.h>
int main(int argc, const char * argv[])
{
onemessage msg = ONE__MESSAGE__INIT; //from generated .h code file
void *buf;
unsigned int len;
char *ptr;
//integer initialization
msg.has_aninteger = true;
msg.aninteger = 1;
//accessing the string in onemessage
msg.messagestring = malloc(sizeof("a simple string"));
strncpy(msg.messagestring,"a simple string",strlen("a simple string"));
//trying to initialize the string in the nested structure othermessage
msg.otr_message = malloc(sizeof(othermessage));
msg.otr_message->otherstring = malloc(sizeof("a not so simple string"));
strncpy(msg.otr_message->otherstring,"a not so simple string",strlen("a not so simple string"));
//lets find the length of the packed structure
len = one_message__get_packed_size(&msg); //from generated .h code
//lets arrange for as much size as len
buf = malloc(len);
//lets get the serialized structure in buf
one_message__pack_to_buffer(&msg,buf); //from generated code
//write it to a stream, for now the screen
fwrite(buf,len,1,stdout);
//free buffer
free(buf);
return 0;
}
I compile it as gcc -o testout messagefile.pb-c.c simpleexample.c -lprotobuf-c
The Problem I am facing is when trying to initialize the nested othermessage variables and then call the get_packed_size it throws a segmentation fault.
I tried various combinations and I can say that whenever having strings in a nested class, I am facing problem to access those using google protoc.
Am i missing something? Is there anything wrong.
Can anyone please help.
note:There might be a few general syntax errors please ignore them.
ThankYou.
note:There might be a few general syntax errors please ignore them.
Err... they are kinda hard to ignore since your code does not compile :-)
Anyway, apart from the syntax errors, you need to make several corrections to your code. In order to use the field otr_message, it is not sufficient to just malloc() it. You also need to initialize it so the headers in the message get the right values. This is done with init(), like this:
//trying to initialize the string in the nested structure othermessage
msg.otr_message = malloc(sizeof(othermessage));
othermessage__init(msg.otr_message);
Then you use the wrong function to do the packing to your own array. As explained here, you need to use pack() as opposed to pack_to_buffer(), like this:
//lets get the serialized structure in buf
onemessage__pack(&msg,buf); //from generated code
Finally, your strncpy() invocations have a mistake. The length calculated with strlen() does not include the null terminator, which you do need. So you need to take strlen()+1 or use sizeof(), like this:
strncpy(msg.messagestring,"a simple string",sizeof("a simple string"));
After making those changes, the example worked for me:
$ ./testout
a simple string
a not so simple string

Why's _itoa causing my program to crash?

The following code just keeps on crashing when it reaches the part with _itoa, I've tried to implement that function instead and then it got even weirder, it just kept on crashing when I ran it without the debugger but worked fine while working with the debugger.
# include "HNum.h"
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <assert.h>
# define START_value 30
typedef enum {
HNUM_OUT_OF_MEMORY = -1,
HNUM_SUCCESS = 0,
} HNumRetVal;
typedef struct _HNum{
size_t Size_Memory;
char* String;
}HNum;
HNum *HNum_alloc(){
HNum* first = (HNum*)malloc(sizeof(HNum));
if(first==NULL){
return NULL;
}
first->String =(char*)malloc(sizeof(START_value));
if(first->String==NULL){
return NULL;
}
first->Size_Memory = START_value; // slash zero && and starting from zero index;
return first;
}
HNumRetVal HNum_setFromInt(HNum *hnum, int nn){
itoa(nn,hnum->String,10);
}
void main(){
HNum * nadav ;
int h = 13428637;
nadav = HNum_alloc();
nadav->String="1237823423423434";
HNum_setFromInt(nadav,h);
printf("nadav string : %s \n ",nadav->String);
//printf("w string %s\n",w->String);
//printf("nadav string %s\n",nadav->String);
HNum_free(nadav);
}
I've been trying to figure this out for hours and couldn't come up with anything...
The IDE I'm using is Visual Studio 2012 express, the crash shows the following:
"PROJECT C.exe has stopped working
windows can check online for a solution to the program."
first->String =(char*)malloc(sizeof(START_value));
should be
first->String = malloc(START_value);
The current version allocates space for sizeof(int)-1 characters (-1 to leave space for the nul terminator). This is too small to hold your target value so _itoa writes beyond memory allocated for first->String. This results in undefined behaviour; it is quite possible for different runs to fail in different places or debug/release builds to behave differently.
You also need to remove the line
nadav->String="1237823423423434";
which leaks the memory allocated for String in HNum_alloc, replacing it with a pointer to a string literal. This new pointer should be considered to be read-only; you cannot write it it inside _itoa
Since I'm not allowed to comment:
simonc's answer is correct. If you find the following answer useful, you should mark his answer as the right one:P
I tried that code myself and the only thing missing is lets say:
strcpy(nadav->String, "1237823423423434"); INSTEAD OF nadav->String="1237823423423434";
and
first->String = malloc(START_value); INSTEAD OF first->String =(char*)malloc(sizeof(START_value));
Also, maybe you'd have to use _itoa instead of itoa, that's one of the things I had to change in my case anyhow.
If that doesn't work, you should probably consider using a different version of VS.

TCL_LINK_STRING causing segmentation fault (core dumped)

I'm trying to share a variable with c and tcl, the problem is when i try to read the variable in the c thread from tcl, it causes segmentation error, i'm not sure this is the right way to do it, but it seems to work for ints. The part that is causing the segmentation fault is this line is when i try to print "Var" but i want to read the variable to do the corresponding action when the variable changes.
Here is the C code that i'm using
void mode_service(ClientData clientData) {
while(1) {
char* Var = (char *) clientData;
printf("%s\n", Var);
usleep(100000); //100ms
}
}
static int mode_thread(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) {
Tcl_ThreadId id;
ClientData limitData;
limitData = cdata;
id = 0;
Tcl_CreateThread(&id, mode_service, limitData, TCL_THREAD_STACK_DEFAULT, TCL_THREAD_NOFLAGS);
printf("Tcl_CreateThread id = %d\n", (int) id);
// Wait thread process, before returning to TCL prog
int i, aa;
for (i=0 ; i<100000; i++) {aa = i;}
// Return thread ID to tcl prog to allow mutex use
Tcl_SetObjResult(interp, Tcl_NewIntObj((int)id));
printf("returning\n");
return TCL_OK;
}
int DLLEXPORT Modemanager_Init(Tcl_Interp *interp){
if (Tcl_InitStubs(interp, TCL_VERSION, 0) == NULL) {
return TCL_ERROR;
}
if (Tcl_PkgProvide(interp, "PCIe", "1.0") == TCL_ERROR) {
return TCL_ERROR;
}
// Create global Var
int *sharedPtr=NULL;
//sharedPtr = sharedPtr = (char *) Tcl_Alloc(sizeof(char));
Tcl_LinkVar(interp, "mode", (char *) &sharedPtr, TCL_LINK_STRING);
Tcl_CreateObjCommand(interp, "mode_thread", mode_thread, sharedPtr, NULL);
return TCL_OK;
}
In the tcl code, i'm changing the variable mode whenever the user presses a button for example:
set mode "Idle"
button .startSamp -text "Sample Start" -width 9 -height 3 -background $btnColor -relief flat -state normal -command {set mode "Sampling"}
set threadId [mode_thread]
puts "Created thread $threadId, waiting"
Your code is a complete mess! You need to decide what you are doing and then do just that. In particular, you are using Tcl_LinkVar so you need to decide what sort of variable you are linking to. If you get a mismatch between the storage, the C access pattern and the declared semantic type, you'll get crashes.
Because your code is in too complicated a mess for me to figure out exactly what you want to do, I'll illustrate with less closely related examples. You'll need to figure out from them how to change things in your code to get the result you need.
Linking Integer Variables
Let's do the simple case: a global int variable (declared outside any function).
int sharedVal;
You want your C code to read that variable and get the value. Easy! Just read it as it is in scope. You also want Tcl code to be able to write to that variable. Easy! In the package initialization function, put this:
Tcl_LinkVar(interp /* == the Tcl interpreter context */,
"sharedVal" /* == the Tcl name */,
(char *) &sharedVal /* == pointer to C variable */,
TCL_LINK_INT /* == what is it! An integer */);
Note that after that (until you Tcl_UnlinkVar) whenever Tcl code reads from the Tcl variable, the current value will be fetched from the C variable and converted.
If you want that variable to be on the heap, you then do:
int *sharedValPtr = malloc(sizeof(int));
C code accesses using *sharedValPtr, and you bind to Tcl with:
Tcl_LinkVar(interp /* == the Tcl interpreter context */,
"sharedVal" /* == the Tcl name */,
(char *) sharedValPtr /* == pointer to C variable */,
TCL_LINK_INT /* == what is it! An integer */);
Linking String Variables
There's a bunch of other semantic types as well as TCL_LINK_INT (see the documentation for a list) but they all follow that pattern except for TCL_LINK_STRING. With that, you do:
char *sharedStr = NULL;
Tcl_LinkVar(interp, "sharedStr", (char *) &sharedStr, TCL_LINK_STRING);
You also need to be aware that the string will always be allocated with Tcl_Alloc (which is substantially faster than most system memory allocators for typical Tcl memory usage patterns) and not with any other memory allocator, and so will also always be deallocated with Tcl_Free. Practically, that means if you set the string from the C side, you must use Tcl_Alloc to allocate the memory.
Posting Update Notifications
The final piece to note is when you set the variable from the C side but want Tcl to notice that the change has set (e.g., because a trace has been set or because you've surfaced the value in a Tk GUI), you should do Tcl_UpdateLinkedVar to let Tcl know that a change has happened that it should pay attention to. If you never use traces (or Tk GUIs, or the vwait command) to watch the variable for updates, you can ignore this API call.
Donal's answer is correct, but I try to show you what you did with your ClientData.
To clarify: All (or almost all, Idk) Tcl functions that take a function pointer also take a parameter of type ClientData that is passed to your function when Tcl calls it.
Let's take a look at this line:
Tcl_CreateObjCommand(interp, "mode_thread", mode_thread, NULL, NULL);
// ------------------------------------------------------^^^^
You always pass NULL as ClientData to the mode_thread function.
In the mode_thread function you use the passed ClientData (NULL) to pass it as ClientData to the new Thread:
limitData = cdata;
// ...
Tcl_CreateThread(&id, mode_service, limitData, TCL_THREAD_STACK_DEFAULT, TCL_THREAD_NOFLAGS);
In the mode_service function you use the ClientData (which is still NULL) as pointer to a char array:
char* Var = (char *) clientData;
Which is a pointer to the address 0x00.
And then you tell printf to dereference this NULL pointer:
printf("%s\n", Var);
Which obviously crashes your program.

Resources