I am trying to test linux kernel stack size in 64 bit.
I found this weird behaviour.
I wrote following code to crash the kernel but strange thing is that
it crashes only if printk is uncommented,
otherwise runs fine with no errors/warnings!!.
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
static int __init crash_stack_init(void)
{
long arr[1024];
long *a;
a = &arr[0];
//printk("%p\n", &arr[0]);
return 0;
}
enter code here
static void __exit crash_stack_exit(void)
{
}
module_init(crash_stack_init);
module_exit(crash_stack_exit);
Here is the "make" output without the printk,
make -C /lib/modules/4.4.0-53-generic/build
M=/home/naveenvc/work/ker/crash_stack modules
make[1]: Entering directory '/usr/src/linux-headers-4.4.0-53-generic'
CC [M] /home/naveenvc/work/ker/crash_stack/crash_stack.o
Building modules, stage 2.
MODPOST 1 modules
CC /home/naveenvc/work/ker/crash_stack/crash_stack.mod.o
LD [M] /home/naveenvc/work/ker/crash_stack/crash_stack.ko
make[1]: Leaving directory '/usr/src/linux-headers-4.4.0-53-generic'
And make output with printk,
make -C /lib/modules/4.4.0-53-generic/build
M=/home/naveenvc/work/ker/crash_stack modules make[1]: Entering
directory '/usr/src/linux-headers-4.4.0-53-generic' CC [M]
/home/naveenvc/work/ker/crash_stack/crash_stack.o
> /home/naveenvc/work/ker/crash_stack/crash_stack.c: In function
‘crash_stack_init’:
/home/naveenvc/work/ker/crash_stack/crash_stack.c:14:1: warning: the
frame size of 8200 bytes is larger than 1024 bytes
[-Wframe-larger-than=] } ^
Building modules, stage 2. MODPOST 1
modules CC
/home/naveenvc/work/ker/crash_stack/crash_stack.mod.o LD [M]
/home/naveenvc/work/ker/crash_stack/crash_stack.ko make[1]: Leaving
directory '/usr/src/linux-headers-4.4.0-53-generic'
What could be causing this?
The stack size is well documented and the above is not the right way to test, in particular in older kernels which used hugepages to back the stack the aforementioned code would jump over to the next stack.
The func __crash_stack_init with prink commented out is a leaf function - it does not call anything, so the compiler knows exactly what happens with local vars. In particular in this code it sees the full array is not needed and thus its not being allocated. However, the call to printk passes arr in. The compiler does not know what the func is going to do with it, thus it has to reserve 1024 * sizeof(long) on the stack which results in the warning.
Stacks got bumped to 16KB years ago, you can start reading here https://lwn.net/Articles/600644/
Related
For what I understand, if there are more than one program using a shared library, the shared library won't get unloaded untill all program finishes.
I am reading The Linux Programming Interface:
42.4 Initialization and Finalization Functions It is possible to define one or more functions that are executed automatically when a
shared library is loaded and unloaded. This allows us to perform
initialization and finalization actions when working with shared
libraries. Initialization and finalization functions are executed
regardless of whether the library is loaded automatically or loaded
explicitly using the dlopen interface (Section 42.1).
Initialization and finalization functions are defined using the gcc
constructor and destructor attributes. Each function that is to be
executed when the library is loaded should be defined as follows:
void __attribute__ ((constructor)) some_name_load(void)
{
/* Initialization code */
}
Unload functions are similarly defined:
void __attribute__ ((destructor)) some_name_unload(void)
{
/* Finalization code */
} The function names `some_name_load()` and `some_name_unload()` can be replaced by any desired names. ....
Then I wrote 3 files to test:
foo.c
#include <stdio.h>
void __attribute__((constructor)) call_me_when_load(void){
printf("Loading....\n");
}
void __attribute__((destructor)) call_me_when_unload(void){
printf("Unloading...\n");
}
int xyz(int a ){
return a + 3;
}
main.c
#include <stdio.h>
#include <unistd.h>
int main(){
int xyz(int);
int b;
for(int i = 0;i < 1; i++){
b = xyz(i);
printf("xyz(i) is: %d\n", b);
}
}
main_while_sleep.c
#include <stdio.h>
#include <unistd.h>
int main(){
int xyz(int);
int b;
for(int i = 0;i < 10; i++){
b = xyz(i);
sleep(1);
printf("xyz(i) is: %d\n", b);
}
}
Then I compile a shared library and 2 executables:
gcc -g -Wall -fPIC -shared -o libdemo.so foo.c
gcc -g -Wall -o main main.c libdemo.so
gcc -g -Wall -o main_while_sleep main_while_sleep.c libdemo.so
finally run LD_LIBRARY_PATH=. ./main_while_sleep in a shell and run LD_LIBRARY_PATH=. ./main in another:
main_while_sleep output:
Loading....
xyz(i) is: 3
xyz(i) is: 4
xyz(i) is: 5
xyz(i) is: 6
xyz(i) is: 7
xyz(i) is: 8
xyz(i) is: 9
xyz(i) is: 10
xyz(i) is: 11
xyz(i) is: 12
Unloading...
main output:
Loading....
xyz(i) is: 3
Unloading...
My question is, while main_while_sleep is not finished, why Unloading is printed in main, which indicates the shared library has been unloaded? The shared library shouldn't be unloaded yet, main_while_sleep is still running!
Do I get something wrong?
My question is, while main_while_sleep is not finished, why Unloading is printed in main, which indicates the shared library has been unloaded? The shared library shouldn't be unloaded yet, main_while_sleep is still running!
You are confusing/conflating initialization/deinitialization with load/unload.
A constructor is an initialization function that is called after a shared library has been mapped into a given process's memory.
It does not affect any other process (which is in a separate, per-process address space).
Likewise, the mapping (or unmapping) of a shared library in a given process does not affect any other process.
When a process maps a library, nothing is "loaded". When the process tries to access a memory page that is part of the shared library, it receives a page fault and the given page is mapped, the page is marked resident, and the faulting instruction is restarted.
There is much more detail in my answers:
How does mmap improve file reading speed?
Which segments are affected by a copy-on-write?
read line by line in the most efficient way *platform specific*
Is Dynamic Linker part of Kernel or GCC Library on Linux Systems?
Malloc is using 10x the amount of memory necessary
The purpose of this module is to basically do the same thing as what happens when you type into your linux command line cat /proc/buddyinfo
Code
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/mmzone.h>
#define DRIVER_AUTHOR "Matthew James Barnes <mbarnes2k5#Gmail.com>"
#define DRIVER_DESC "A driver that does the same thing as /proc/buddyinfo"
/***
*GLOBAL VARIABLES
***/
extern struct pglist_data *first_online_pgdat(void);
extern struct pglist_data *next_online_pgdat(struct pglist_data*pgdat);
struct pglist_data *pgdat;
extern struct zone *zone;
int init_module(void)
{
int order;
for(pgdat = first_online_pgdat(); pgdat; pgdat = next_online_pgdat(pgdat))
{
for(zone = pgdat->node_zones; zone; zone = next_zone(zone)){
printk(KERN_INFO "Node %d, zone %8s ",pgdat->node_id, zone->name);
printk(KERN_INFO "Node %d", pgdat->node_id);
printk(KERN_CONT "Zone %s",zone->name);
for( order = 0; order < MAX_ORDER; ++order)
printk(KERN_CONT "%6lu ", zone->free_area[order].nr_free);
printk(KERN_CONT "\n");
}
}
return 0;
}
void cleanup_module(void){
printk(KERN_INFO "Zones have been feenished.\n");
}
MODULE_LICENSE("GPL");
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
~
~
~
~
~
~
~
I decided to go lean and create a makefile as well as a folder within my kernel called module-edits.
In module edits when I run the makefile, I run into a compilation error.
The command line returns the following:
make -C /lib/modules/5.4.0-26-generic/build M=/usr/local/share/source_code/version1/module-edits modules
make[1]: Entering directory '/usr/src/linux-headers-5.4.0-26-generic'
Building modules, stage 2.
MODPOST 1 modules
ERROR: "next_online_pgdat" [/usr/local/share/source_code/version1/module-edits/printbuddy.ko] undefined!
ERROR: "next_zone" [/usr/local/share/source_code/version1/module-edits/printbuddy.ko] undefined!
ERROR: "zone" [/usr/local/share/source_code/version1/module-edits/printbuddy.ko] undefined!
ERROR: "first_online_pgdat" [/usr/local/share/source_code/version1/module-edits/printbuddy.ko] undefined!
make[2]: [scripts/Makefile.modpost:94: __modpost] Error 1
make[1]: [Makefile:1632: modules] Error 2
make[1]: Leaving directory '/usr/src/linux-headers-5.4.0-26-generic'
make: [makefile:5: all] Error 2
Now, what is baffling about this is that when I typed
#include <linux/mmzone.h>
there are a number of structs.
pgdat is a struct that allows access to the current page data.
*first_online_pgdat(void); is a function that points to the first page.
*next_online_pgdat(struct pglist_data*pgdat); points to the next page.
struct pglist_data *pgdat;
is basically the representation of my page.
and extern struct zone *zone is the representation of the zone type of the pages.
All of this is included in mmzone, but it's as if the functions in mmzone.h are not even being referenced.
I don't really understand what is going on, but I would appreciate assistance from experienced linux programmers.
I have a project that I recently split up into headers + sources, and now clang-tidy wont "actually" check my test files that include these headers. Below is an example of the situation:
File Structure:
src/
main.c
a.h
a.c
test/
test.c
Code:
// src/main.c
#include "src/a.h"
int main(void) {
a();
return 0;
}
// src/a.h
void a(void);
// src/a.c
#include <stdlib.h>
#include "src/a.h"
void a(void) {
malloc(1); // obvious memory leak
}
// test/test.c
#include "src/a.h"
int main(void) {
// do test stuff
a();
return 0;
}
Compile src: cc src/*.c -I. -o main
Compile test: cc src/a.c test/test.c -I. -o test
Running does nothing, but the code does compile.
Then, I run the code through clang-tidy:
clang-tidy src/* -- -I.
This works:
1 warning generated.
1 warning generated.
1 warning generated.
/src/a.c:8:1: warning: Potential memory leak [clang-analyzer-unix.Malloc]
}
^
/src/a.c:7:2: note: Memory is allocated
malloc(1);
^
/src/a.c:8:1: note: Potential memory leak
}
^
But if I do:
clang-tidy test/test.c -- -I.
Nothing is outputed (ive tried to add the header-filter flag as well).
I pressume that the headers are being included, and the test code has no knowledge of the source. So, how can I make sure my tests are actually being checked if this is the case? These headers and sources are in my project, so it would only make sense that clang-tidy would be able to pick up on this?
Edit:
I can do the following, and it seems to only partially fix the problem:
// test/test.c
#include "src/a.h"
#include "src/a.c" //added this line
int main(void) {
// do test stuff
a();
return 0;
}
Now, clang-tidy picks up on the actual .c file, and thus finds the issue. But, now I cant compile my code. There is supposed to be a __clang_analyzer__ define that gets set when the code is being analyzed, but it seems to just ignore it:
#ifdef __clang_analyzer__
#include "src/a.c" // doesnt include file, thus the malloc() call is never detected
#endif
clang-tidy is only a static analyser tool, said differently a linter. It does not try to build or run an executable: it just analyses the C source files it has been given after processing the include parts.
Static analysis and testing are different parts of a quality assurance process:
the former only reads source files searching for common errors and runs nothing
the latter runs (parts of) a code base with known inputs and controls that outputs have expected values
That means that clang-tidy is expected to be run on your main sources, not only on the test ones.
To be clear, it can make sense to pass test sources to the linter, because they could contain problems that clang-tidy would detect. But only running clang-tidy on the test folder will not detect problem in main folder, whatever the coverage.
I recoded malloc free and realloc in c using mmap and munmap. I compiled them as a shared library .so file.
Here is a simple test:
#include <stdlib.h>
int main() {
int i;
char *addr;
i = 0;
while (i < 1024)
{
addr = (char*)malloc(1024);
addr[0] = 42;
i++;
}
return (0);
}
Here is a run.sh that must replace the stdlib by my shared library:
#/bin/sh
export DYLD_LIBRARY_PATH=.
export DYLD_INSERT_LIBRARIES="libft_malloc.so"
export DYLD_FORCE_FLAT_NAMESPACE=1
$#
The problem is that when i am compiling directly the test file with my shared library and replacing the header in it, it is working well:
-> gcc test1.c libft_malloc.so
-> ./a.out
-> no error
But when i am running it with the run.sh that should just replace the official malloc library by my libft_malloc.so file, i am getting a segfault:
-> gcc test1.c
-> ./run.sh ./a.out
-> ./run.sh: line 5: 73502 Segmentation fault: 11 $#
I know the error is in my code and not in the run.sh or in the test.c because they are the officials files i must use to test my library in my school and those files are working well on other malloc repositories, but i can't find what can be the problem.
Here is my repository: https://github.com/Shirakawa42/malloc.git
I tried debugged by placing write() everywhere but the segfault don't seems to be in the malloc, so i'm lost.
edit:
It also segfault if we run a test without any malloc, but just by loading my library:
#include <stdlib.h>
int main() {
int i;
i = 0;
while (i < 1024)
{
i++;
}
return (0);
}
-> gcc test1.c
-> ./run.sh ./a.out
-> ./run.sh: line 5: 74764 Segmentation fault: 11 $#
edit 2:
Compiling with flag fsanitize=address repair the segfault, but it's absolutely not optimal
edit 3:
Setting the 2 first export manually in shell tell me:
dyld: warning: could not load inserted library 'libft_malloc.so' into library validated process because no suitable image found. Did find:
libft_malloc.so: code signing blocked mmap() of 'libft_malloc.so'
and after setting the third export all my actions make me segfault, like ls and vim, cd made me abort
dyld: warning: could not load inserted library 'libft_malloc.so' into library validated process because no suitable image found. Did find:
libft_malloc.so: code signing blocked mmap() of 'libft_malloc.so'
This error append when there are a segfault in your malloc or free, repairing free made it work.
You can debug it in gdb. First build your code with debug options:
gcc -g -O0
Above options should be used for both your lib and test program. Then you can try running you program in gdb:
gdb a.out
(gdb) r <arguments to a.out>
(gdb) bt <-- when it crashes
Linux loads you program in the memory and calls the entry point main. Startup code that compiler adds for the platform may have calls to malloc. Hence, the crash without malloc in your test code.
Im working on a project for stm32f4 to my school. Im using CooCox IDE.
I wanted to add new files "przerwania.c" and "przerwania.h" to write some functions there - not in "main.c". But I have no idea why CooCox is showing me errors.
Earlier I wanted to move some of functions from main.c to pwm.c and them work! But I would like to make a new files couse i have more functions.
Errors in CooCox look like this:
[mkdir] Created dir: D:\CooCox\CoIDE\workspace\testowy2\testowy2\Debug\obj
[cc] 12 total files to be compiled.
[cc] arm-none-eabi-gcc -mcpu=cortex-m4 -mthumb -Wall -ffunction-sections -g -O0 -c -DSTM32F407VG -DSTM32F4XX -DUSE_STDPERIPH_DRIVER -D__ASSEMBLY__ -ID:\CooCox\CoIDE\workspace\testowy2 -ID:\CooCox\CoIDE\workspace\testowy2\cmsis_boot -ID:\CooCox\CoIDE -ID:\CooCox\CoIDE\workspace\testowy2\cmsis_lib\include -ID:\CooCox\CoIDE\workspace\testowy2\cmsis -ID:\CooCox\CoIDE\workspace\testowy2\cmsis_lib -ID:\CooCox\CoIDE\workspace D:\CooCox\CoIDE\workspace\testowy2\cmsis_lib\source\stm32f4xx_syscfg.c D:\CooCox\CoIDE\workspace\testowy2\pwm.c D:\CooCox\CoIDE\workspace\testowy2\dupa.c D:\CooCox\CoIDE\workspace\testowy2\cmsis_boot\startup\startup_stm32f4xx.c D:\CooCox\CoIDE\workspace\testowy2\main.c D:\CooCox\CoIDE\workspace\testowy2\cmsis_lib\source\stm32f4xx_rcc.c D:\CooCox\CoIDE\workspace\testowy2\cmsis_lib\source\stm32f4xx_adc.c D:\CooCox\CoIDE\workspace\testowy2\cmsis_lib\source\stm32f4xx_gpio.c D:\CooCox\CoIDE\workspace\testowy2\cmsis_boot\system_stm32f4xx.c D:\CooCox\CoIDE\workspace\testowy2\cmsis_lib\source\stm32f4xx_exti.c D:\CooCox\CoIDE\workspace\testowy2\cmsis_lib\source\misc.c D:\CooCox\CoIDE\workspace\testowy2\cmsis_lib\source\stm32f4xx_tim.c
[cc] Starting link
[cc] arm-none-eabi-gcc -mcpu=cortex-m4 -mthumb -g -nostartfiles -Wl,-Map=testowy2.map -O0 -Wl,--gc-sections -LD:\CooCox\CoIDE\configuration\ProgramData\testowy2 -Wl,-TD:\CooCox\CoIDE\configuration\ProgramData\testowy2/arm-gcc-link.ld -g -o testowy2.elf ..\obj\stm32f4xx_syscfg.o ..\obj\pwm.o ..\obj\dupa.o ..\obj\startup_stm32f4xx.o ..\obj\main.o ..\obj\stm32f4xx_rcc.o ..\obj\stm32f4xx_adc.o ..\obj\stm32f4xx_gpio.o ..\obj\system_stm32f4xx.o ..\obj\stm32f4xx_exti.o ..\obj\misc.o ..\obj\stm32f4xx_tim.o
[cc] ..\obj\main.o: In function `main':
[cc] D:\CooCox\CoIDE\workspace\testowy2/main.c:336: undefined reference to `Nowafunkcja'
[cc] collect2.exe: error: ld returned 1 exit status
main.c is quite long becouse i have some definitions of few long functions there, so I paste here only a part
#include "stm32f4xx.h"
#include "misc.h"
#include "stm32f4xx_syscfg.h"
#include "stm32f4xx_adc.h"
#include "stm32f4xx_exti.h"
#include "przerwania.h"//here is the problem
#include "pwm.h"
int main(void)
{
SystemInit();
//IniDiody();
//TimConfig();
//NVIC_Config();
//IniDiodyPWM();
LEDInit();
EXTILine0_Config();
PWM2();//wiwo
GPIO();//wiwo
Nowafunkcja();//PROBLEM
RCC_Konfiguracja_Adc12();
GPIO_Configuration_Adc1();
ADC1_Configuration();
GPIO_Configuration_Adc1();
GPIO_Configuration_Adc2();
ADC2_Configuration();
IniDiody(GPIO_Pin_14);
IniTimerPrzerwanie1();
while(1)
{
ADC_SoftwareStartConv(ADC1);
ADC_SoftwareStartConv(ADC2);
while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
wynikADC1 = (float)ADC_GetConversionValue(ADC1);
while(ADC_GetFlagStatus(ADC2, ADC_FLAG_EOC) == RESET);
wynikADC2 = (float)ADC_GetConversionValue(ADC2);
wartosc = (int)(wynikADC2 * 15);
//doPWM=(((float)ADCResult) / 41);
//wartosc = (int) doPWM;
//TIM2->CCR3 = (int) doPWM;
TIM3->CCR2 = 65535;
TIM3->CCR1 = wartosc;//(int)(wynikADC2 * 15);
wartoscPrescalera=(int)SystemCoreClock;
}
}
and files:
przerwania.h
#ifndef __przerwaniah
#define __przerwaniah
void Nowafunkcja(void);
#endif
przerwania.c
#include "przerwania.h"
void Nowafunkcja(void)
{
//nothing here - just for test
}
Do you have any idea what is the problem? I'm thinking about this since yesterday and its wird :/
I'll appreciate your help!
Take a look at the line under [cc] 12 total files to be compiled.
When you added pwm.c, you also informed the compiler to include this file. You'll see it listed there. przerwania.c is not.
If you add przerwania the same way you added pwm, your IDE will take care of making sure it is included in the build.
I'm not sure what your current file/folder structure looks like:
http://www.coocox.org/CoIDE/Project_management_config.html can help you determine how to pull those new files into the build.
FWIW:
The (anthropomorphized) compiler step says: Is this valid code? So it looks though your main.c, sees that you included przerwania.h, and comes to the conclusion that you correctly used the Nowafunkcja function (just matched the signature). Even though at this point, it has NOT looked into przerwania.c to find out what it does. The compiler goes on to do this for all of your files and keeps track of what functions are defined in each file. Note that it never found the definition Nowafunkcja, because the compiler never compiled przerwania.c. It did however find the declaration in the .h (because main.c told it exactly where to find the .h)
The linker then gets this stuff from the compiler, including what functions have been defined in all your .c files. That's the first point where something tries to answer the question "Now what code do I actually need to run when he asked me to Nowafunkcja()?". So that's the first point in the build when the tools realized, I never found code for Nowafunkcja in any of the .c files I was looking in.
So, I think that roughly answers "Why", but we need to know more about your project organization to give you a "fix" to make it work.