Skip to content

Commit

Permalink
Mention allocations, null checks and logging apis ##doc
Browse files Browse the repository at this point in the history
  • Loading branch information
radare committed Jan 21, 2025
1 parent e7653cb commit 3288c54
Showing 1 changed file with 131 additions and 14 deletions.
145 changes: 131 additions & 14 deletions DEVELOPERS.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ For information about the git process, see
## IDE settings
### generate compile_commands.json
compile_commands.json records the dependency relationship between `.c/.h` file.
It is used by language server(ccls, clang, e.g.) to provide accurate code
It is used by language server(ccls, clang, e.g.) to provide accurate code
completion, syntax highlighting, and other intelligent code analysis features.

If you haven't built the project yet, you can do the following:
Expand All @@ -29,7 +29,7 @@ bear -- make install
`bear` is tool that will hook the usage of gcc and generate `compile_commands.json`.

### language server
Both of `ccls` and `clangd` supports `compile_commands.json`. You can add
Both of `ccls` and `clangd` supports `compile_commands.json`. You can add
corresponding plugin for your IDE.

## Documentation
Expand Down Expand Up @@ -63,15 +63,16 @@ with features.
During abi-stable seassons [x.y.0-x.y.8] it is not allowed to break the abi, this
is checked in the CI using the `abidiff` tool on every commit. Sometimes keeping
the abi/api stable implies doing ugly hacks. Those must be marked with the corresponding
to the next MAJOR.MINOR release of r2.
the abi/api stable implies doing ugly hacks. Those must be marked with the
corresponding to the next MAJOR.MINOR release of r2.
For example, during the development of 5.8.x we add a comment or use `#if R2_590` code
blocks to specify those lines need to be changed when 5.8.9 in git.
For example, during the development of 5.8.x we add a comment or use `#if R2_590`
code blocks to specify those lines need to be changed when 5.8.9 in git.
Only the even patch version numbers are considered a release. This means that if you have
an odd patch version of r2 it was built from git instead of the release tarball or binaries.
Only the even patch version numbers are considered a release. This means that if
you have an odd patch version of r2 it was built from git instead of the release
tarball or binaries.
For more details read [doc/abi.md](doc/abi.md)
Expand Down Expand Up @@ -440,19 +441,106 @@ The above is not very easy to read. Within radare2, use endianness helper
functions to interpret byte streams in a given endianness.

```c
val32 = r_read_be32(buffer) // reads 4 bytes from a stream in BE
val32 = r_read_le32(buffer) // reads 4 bytes from a stream in LE
val32 = r_read_ble32(buffer, isbig) // reads 4 bytes from a stream:
// if isbig is true, reads in BE
// otherwise reads in LE
val32 = r_read_be32 (buffer) // reads 4 bytes from a stream in BE
val32 = r_read_le32 (buffer) // reads 4 bytes from a stream in LE
val32 = r_read_ble32 (buffer, isbig) // reads 4 bytes from a stream:
// if isbig is true, reads in BE
// otherwise reads in LE
```

Such helper functions exist for 64, 32, 16, and 8 bit reads and writes.

* Note that 8 bit reads are equivalent to casting a single byte of the buffer
to a `ut8` value, i.e.: endian is irrelevant.

## Editor configuration
## Allocations

Instantiating structures in memory ends up depending on the standard malloc/free
provided by your system's libc. But radare2 provides some helper macros in order
to simplify the use of it.

Instead of:

```c
Foo *foo = malloc (sizeof (Foo));
memset (foo, 0, sizeof (Foo));
```
Use the following:
```c
Foo *foo = R_NEW0 (Foo);
```

Note that we could use `calloc` instead of the malloc+memset, but we can
avoid handwriting the sizeof byjust using `R_NEW` or `R_NEW0`.

### Null checks

When calling malloc we want to check if the allocation worked or not. But
checking for every allocation is kind of expensive and boring, we (recently)
decided to reduce the amount of valid allocations.

* If the allocation size is known at compile time we won't check for null.

This is, most mallocs of small sizes won't fail, and actually, most modern
libcs will never return null.

The only reason for a heap allocator to fail is when we are requesting large
areas or negative sizes, therefor, check for multiplication overflows before
computing the amount of memory necessary (see the integer overflow section)
and then check for null.

For example:

```c
if (ST32_ADD_OVFCHK (sizeof (Object), counter)) {
void *amount = calloc (sizeof (Object), counter);
if (!amount) {
R_LOG_DEBUG ("Cannot allocate %d objects", counter);
return;
}
```
### Stack allocations
Never ever do dynamic size stack allocations. With this I mean that it is
forbidden in r2land to use code like this:
```c
void foo(int amount) {
int array[amount];
}
```

Or constructions like this:

```c
void foo(int amount) {
int *array = alloca (amount * sizeof (int));
}
```
Instead you must use the heap. The reason is because there's no way to determine
if alloca is exhausting the stack given by the system. Also there's no portable
way to know how big the system stack is and the final reason is because you can
pass negative values to alloca, some implementations will decrement the frame
pointer causing a fatal corruption.
### Freeing nulls
Yes, this is totally legit and valid posix. Please don't submit code like this:
```c
if (maybenull) {
free (maybenull);
}
```

Just remove the conditional block, free is already checking for null and it's
not necessary to compare it two times.

## Editor setup

Vim/Neovim:

Expand Down Expand Up @@ -511,6 +599,35 @@ R_PACKED (typedef struct mystruct_t {
}) mystruct;
```

Note that we also have the `R_ALIGN` macro to define the alignment
requirements for struct fields or local stack variables. Use `git grep`
for some examples.

## Logging Messages

Use the `R_LOG_` APIs to display error, tracing, information or other
information to the user via the stderr file descriptor.

* Only use `eprintf` for draft/wip development reasons.

The `R_LOG` macros will end up calling the `r_log` functions which can
be configured with eval variables.

```console
[0x00000000]> e??log.
log.color: Should the log output use colors
log.cons: Log messages using rcons (handy for monochannel r2pipe)
log.file: Save log messages to given filename
log.filter: Filter only messages matching given origin
log.level: Target log level/severity (0:FATAL 1:ERROR 2:INFO 3:WARN 4:TODO 5:DEBUG)
log.origin: Show [origin] in log messages
log.quiet: Be quiet, dont log anything to console
log.source: Show source [file:line] in the log message
log.traplevel: Log level for trapping R2 when hit
log.ts: Show timestamp in log messages
[0x00000000]>
```

## Modules

radare2 is split into modular libraries in the `libr/` directory. The `binr/`
Expand Down

0 comments on commit 3288c54

Please sign in to comment.