Skip to content

Commit

Permalink
feat: update articles
Browse files Browse the repository at this point in the history
  • Loading branch information
wx-chevalier committed Jul 30, 2024
1 parent 47910f0 commit 9f0e95a
Show file tree
Hide file tree
Showing 29 changed files with 1,473 additions and 0 deletions.
Binary file modified .DS_Store
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# 《100个gcc小技巧》

一个关于gcc使用小技巧的文档。100,在这里可能只是表明很多;具体的数目取决于您的参与和贡献。

## 在线阅读
[开始阅读](<https://github.com/hellogcc/100-gcc-tips/blob/master/src/index.md>)

## 如何参与

直接发PULL REQUEST,或与我们联系。

增加一个小技巧的步骤:

1. 在src目录下新增一个md文件,参照现有文件的格式风格,编写一个小技巧
markdown语法参见 http://wowubuntu.com/markdown/
md文件编写可以使用在线所见即所得编辑器 https://www.zybuluo.com/mdeditor
2. 在index.md中为新md文件增加一个索引,可以放到已有分类中,或增加一个分类
3. 如果预览下没有问题,OK!

本地生成html的步骤:

1. 确保[go](http://code.google.com/p/go)[md2min](https://github.com/fairlyblank/md2min)已经安装并可用
2. 直接运行build.sh
3. 如果顺利,会在html目录下生成所有的html文件

## 联系方式

- [博客网站](http://www.hellogcc.org)
- 在线讨论问题:IRC, freenode, #hellogcc房间
- [邮件列表](http://www.freelists.org/list/hellogcc) (发信需要先订阅)

## 版权

本文档版权归贡献者所有。

## 授权许可

本文档使用的是[GNU Free Documentation License](http://www.gnu.org/licenses/fdl.html)

## 致谢

- 各位参与者

## 其它资源

- [GCC在线手册](https://gcc.gnu.org/onlinedocs/gcc)

Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
# 利用 Address Sanitizer 工具检查内存访问错误

## 例子

a.c:
#include <stdio.h>

int main(void) {
// your code goes here
int a[3] = {0};
a[3] = 1;

printf("%d\n", a[3]);
return 0;
}

b.c:
#include <stdio.h>
#include <malloc.h>

int main(void) {
int *p = NULL;

p = malloc(10 * sizeof(int));
free(p);
*p = 3;
return 0;
}

## 技巧

gcc 从`4.8`版本起,集成了`Address Sanitizer`工具,可以用来检查内存访问的错误(编译时指定“`-fsanitize=address`”)。以上面`a.c`程序为例:

gcc -fsanitize=address -g -o a a.c

执行`a`程序:

[root@localhost nan]# ./a
=================================================================
==539==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7fff3a152c9c at pc 0x4009b6 bp 0x7fff3a152c60 sp 0x7fff3a152c58
WRITE of size 4 at 0x7fff3a152c9c thread T0
#0 0x4009b5 in main /home/nan/a.c:6
#1 0x34e421ed1c in __libc_start_main (/lib64/libc.so.6+0x34e421ed1c)
#2 0x4007b8 (/home/nan/a+0x4007b8)

Address 0x7fff3a152c9c is located in stack of thread T0 at offset 44 in frame
#0 0x400907 in main /home/nan/a.c:3

This frame has 1 object(s):
[32, 44) 'a' <== Memory access at offset 44 overflows this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism or swapcontext
(longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow /home/nan/a.c:6 main
Shadow bytes around the buggy address:
0x100067422540: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100067422550: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100067422560: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100067422570: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100067422580: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 f1 f1
=>0x100067422590: f1 f1 00[04]f4 f4 f3 f3 f3 f3 00 00 00 00 00 00
0x1000674225a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x1000674225b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x1000674225c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x1000674225d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x1000674225e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Heap right redzone: fb
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack partial redzone: f4
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Contiguous container OOB:fc
ASan internal: fe
==539==ABORTING

可以看到,执行程序时检测出了`a`数组的越界访问(`a[3] = 1`)。

再看一下`b`程序:

gcc -fsanitize=address -g -o b b.c

执行`b`程序:

[root@localhost nan]# ./b
=================================================================
==1951==ERROR: AddressSanitizer: heap-use-after-free on address 0x60400000dfd0 at pc 0x4007f9 bp 0x7fff34277bb0 sp 0x7fff34277ba8
WRITE of size 4 at 0x60400000dfd0 thread T0
#0 0x4007f8 in main /home/nan/b.c:9
#1 0x34e421ed1c in __libc_start_main (/lib64/libc.so.6+0x34e421ed1c)
#2 0x400658 (/home/nan/b+0x400658)

0x60400000dfd0 is located 0 bytes inside of 40-byte region [0x60400000dfd0,0x60400000dff8)
freed by thread T0 here:
#0 0x7fbbb7a7d057 in __interceptor_free /opt/gcc-4.9.2/src/gcc-4.9.2/libsanitizer/asan/asan_malloc_linux.cc:62
#1 0x4007c1 in main /home/nan/b.c:8
#2 0x34e421ed1c in __libc_start_main (/lib64/libc.so.6+0x34e421ed1c)

previously allocated by thread T0 here:
#0 0x7fbbb7a7d26f in __interceptor_malloc /opt/gcc-4.9.2/src/gcc-4.9.2/libsanitizer/asan/asan_malloc_linux.cc:72
#1 0x4007b1 in main /home/nan/b.c:7
#2 0x34e421ed1c in __libc_start_main (/lib64/libc.so.6+0x34e421ed1c)

SUMMARY: AddressSanitizer: heap-use-after-free /home/nan/b.c:9 main
Shadow bytes around the buggy address:
0x0c087fff9ba0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c087fff9bb0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c087fff9bc0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c087fff9bd0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c087fff9be0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x0c087fff9bf0: fa fa fa fa fa fa fa fa fa fa[fd]fd fd fd fd fa
0x0c087fff9c00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c087fff9c10: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c087fff9c20: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c087fff9c30: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c087fff9c40: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Heap right redzone: fb
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack partial redzone: f4
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Contiguous container OOB:fc
ASan internal: fe
==1951==ABORTING

执行程序时检测出了访问释放内存的错误(`*p = 3`)。
详情参见[gcc 手册](https://gcc.gnu.org/onlinedocs/gcc-4.9.2/gcc/Debugging-Options.html#index-fsanitize_003daddress-593)

## 贡献者

nanxiao
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# error: cast from ... to ... loses precision

## 例子

#include <iostream>

class Foo {
public:
void print() const {
std::cout << (int)(this) << "\n";
}
};

int main()
{
class Foo foo;

foo.print();
return 0;
}

## 技巧

在 g++编译上面的例子,会报如下错误:

$ g++ foo.cc
foo.cc: In member function ‘void Foo::print() const’:
foo.cc:6:28: error: cast from ‘const Foo*’ to ‘int’ loses precision [-fpermissive]

这是一个强制类型转换的错误,你可以修改源代码为:

std::cout << (int*)(this) << "\n";

即可。

如果,你不想(或不能)去修改源程序,只是应为升级了 gcc 而带来了这样的错误,那么也可以使用`-fpermissive`选项,将错误降低为警告:

$ g++ foo.cc -fpermissive
foo.cc: In member function ‘void Foo::print() const’:
foo.cc:6:28: warning: cast from ‘const Foo*’ to ‘int’ loses precision [-fpermissive]

详情参见[gcc 手册](https://gcc.gnu.org/onlinedocs/gcc/C_002b_002b-Dialect-Options.html#index-fpermissive-166)
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# 在命令行中预定义宏

## 例子

#include <stdio.h>

int main (void)
{
int i, sum;

for (i = 1, sum = 0; i <= 10; i++)
{
sum += i;
#ifdef DEBUG
printf ("sum += %d is %d\n", i, sum);
#endif
}
printf ("total sum is %d\n", sum);

return 0;
}

## 技巧

使用`-D`选项可以在命令行中预定义一个宏,比如:

$ gcc -D DEBUG macro.c

中间可以没有空格:

$ gcc -DDEBUG macro.c

详情参见[gcc 手册](https://gcc.gnu.org/onlinedocs/gcc/Preprocessor-Options.html#Preprocessor-Options)
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# 打印彩色诊断信息

## 技巧

这是 gcc-4.9 新增的功能,可以通过定义环境变量`GCC_COLORS`来彩色打印诊断信息。

也可以使用选项`-fdiagnostics-color`来设定。

详情参见[gcc 手册](https://gcc.gnu.org/onlinedocs/gcc/Language-Independent-Options.html#Language-Independent-Options)
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# 信息显示
* [打印gcc预定义的宏信息](print-predefined-macros.md)
* [打印gcc执行的子命令](print-commands-only.md)
* [打印优化级别的对应选项](print-level-options.md)
* [打印彩色诊断信息](diagnostics-color.md)
* [打印头文件搜索路径](print-header-search-dir.md)
* [打印连接库的具体路径](print-file-name.md)

# 预处理
* [生成没有行号标记的预处理文件](inhibit-linemarkers.md)
* [在命令行中预定义宏](define-macro.md)
* [在命令行中取消宏定义](undefine-macro.md)

# 汇编
* [把选项传给汇编器](pass-options-to-assembler.md)
* [生成有详细信息的汇编文件](verbose-asm.md)

# 调试
* [利用Address Sanitizer工具检查内存访问错误](address-sanitizer.md)
* [利用Thread Sanitizer工具检查数据竞争的问题](thread-sanitizer.md)

# 连接
* [把选项传给连接器](pass-options-to-linker.md)
* [设置动态连接器](set-dynamic-linker.md)

# 函数属性
* [禁止函数被优化掉](must-emit-function-code.md)
* [强制函数inline](must-forceinline-function-code.md)

# 常见错误
* [error: cast from ... to ... loses precision](cast-lose-precision.md)
* [all warnings being treated as errors](warnings-treated-as-errors.md)
* [gdb无法调试gcc编译的程序](specify-dwarf-version.md)

# 其它
* [只做语法检查](syntax-only.md)
* [保存临时文件](save-temps.md)
* [打开警告信息](turn-on-warnings.md)
* [指定语言类型](specify-language.md)
* [改变结构体成员的字节对齐](pack-struct.md)

Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# 生成没有行号标记的预处理文件

## 技巧

有时编译程序会遇到如下类似的错误,

In file included from foo.c:15,
from a.h:45,
b.h:53: error: ... ...

如果错误是由于你所定义的一个很复杂的宏所引起的,你可能会需要先手动编译生成相应的预处理文件,查看下预处理文件中的宏扩展代码。比如,先运行

gcc -E foo.c -o foo.i

来生成 foo.i 预处理文件。然后,还可以尝试手动修改、编译这个预处理文件。

但是,由于生成的预处理文件中含有行号标记(linemarker),所以,运行

gcc -c foo.i -o foo.o

所得到的错误行号信息还是跟最初的一样,如果可以将预处理文件中的行号标记都去掉,似乎会有些帮助。

幸好,gcc 提供了这个选项:

> -P
> Inhibit generation of linemarkers in the output from the
> preprocessor. This might be useful when running the preprocessor on
> something that is not C code, and will be sent to a program which
> might be confused by the linemarkers.
运行

gcc -E -P foo.c -o foo.i

即可。

详情参见[gcc 手册](https://gcc.gnu.org/onlinedocs/gcc/Preprocessor-Options.html#Preprocessor-Options)
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# 禁止函数被优化掉

## 例子

#if (GCC_VERSION > 4000)
#define DEBUG_FUNCTION __attribute__ ((__used__))
#define DEBUG_VARIABLE __attribute__ ((__used__))
#else
#define DEBUG_FUNCTION
#define DEBUG_VARIABLE
#endif

DEBUG_FUNCTION void
debug_bb (basic_block bb)
{
dump_bb (bb, stderr, 0);
}

## 技巧

上面的例子是 gcc 的源码。使用 gcc 的扩展功能——函数属性`__attribute__ ((__used__))`,可以指定该函数是有用的,不能被优化掉。

详情参见[gcc 手册](https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html#Function-Attributes)
Loading

0 comments on commit 9f0e95a

Please sign in to comment.