What environment you are in
Thru C programs run inside the Thru VM, not as normal hosted user-space processes. That means:- there is no conventional
main - there is no argv or environment-variable interface
- transaction, account, block, and shadow-stack data come from VM-mapped segments
- control flow ends through
tsdk_return,tsdk_revert, ortsys_exit
Memory model
Most of the public SDK reads are borrowed pointers into VM-managed memory:tsdk_get_txn()tsdk_get_account_meta(...)tsdk_get_account_data_ptr(...)tsdk_get_current_block_ctx()tsdk_get_shadow_stack()
Hosted vs freestanding assumptions
The SDK is designed for freestanding builds targeting RISC-V. The toolchain links against picolibc, a lightweight C library for embedded targets. What the build files clearly establish:- programs are compiled as freestanding C, not hosted user-space binaries
- the Thru VM machine config uses a picolibc sysroot
- normal process and OS facilities are not part of the program model
- that every familiar libc helper is available in every installed toolchain
- that POSIX-style APIs are present
- that you can treat the environment like a normal Linux process
- prefer SDK helpers first
- assume extra libc usage needs to be validated against the installed toolchain
- keep dependencies on non-SDK runtime facilities narrow and explicit
Facilities you should not assume exist
| Category | Notes |
|---|---|
| File I/O | No fopen, fread, printf (use tsdk_printf instead) |
| Dynamic memory | No malloc, free, calloc, realloc |
| Process/OS | No exit, fork, getenv, signal |
| Networking | No sockets or network calls |
| Threads | No pthread, no concurrency primitives |
| Hosted runtime behavior | No argv, environment variables, filesystem process model, or normal process startup/teardown |
Floating-point expectations
The default Thru VM build target does not enable the RISC-V floating-point ISA extensions in its-march flags.
Practical takeaway:
- do not assume a full normal libc or POSIX environment
- prefer SDK helpers and simple explicit code
- be careful with patterns that rely on hosted-process facilities
- prefer integer math unless you have validated that floating-point code is appropriate for your target and toolchain
- use stack allocation or the anonymous segment syscalls for temporary memory
Temporary memory
For simple programs, stack allocation is often enough. If you need structured scratch-space carving, the SDK exposes:TSDK_LAYOUT_INITTSDK_LAYOUT_APPENDTSDK_LAYOUT_FINITSDK_SCRATCH_ALLOC_INITTSDK_SCRATCH_ALLOC_APPENDTSDK_SCRATCH_ALLOC_FINI
Limits
| Limit | Value | Defined as |
|---|---|---|
| Max account data size | 16 MB | TSDK_ACCOUNT_DATA_SZ_MAX |
tsdk_printf buffer | 1024 bytes per call | Internal fixed buffer |
| Max CPI call depth | 17 frames | TSDK_SHADOW_STACK_FRAME_MAX |
Logging and output
There is no normal stdout or stderr channel in the usual process sense. Use:tsdk_printf(...)for formatted debugging output (capped at 1024 bytes per call)tsys_log(...)for raw log bytestsys_emit_event(...)for event payloads intended for downstream consumers
Alignment and raw byte parsing
When reading from raw instruction bytes or any layout with uncertain alignment:- prefer
TSDK_LOAD - prefer
TSDK_STORE
Notes
- If a task sounds like βnormal C application code,β the C SDK is probably the wrong layer.
- If a task sounds like βVM entrypoint, account mutation, CPI, proof parsing, or instruction decoding,β this environment model is the right one.