From 882d6062b0bec4708ec3f6db84b74503fec230cf Mon Sep 17 00:00:00 2001 From: Ajinkya Rajandekar Date: Thu, 29 Feb 2024 16:02:41 +0000 Subject: [PATCH] - Remove outdated installation and release guides. Keep only 1 README --- CONTRIBUTING.md | 101 +++++++++++++++++++------- MacInstallation.md | 111 ----------------------------- README.md | 24 +++---- Release-1.3.md | 173 --------------------------------------------- WELCOME.md | 91 ------------------------ 5 files changed, 86 insertions(+), 414 deletions(-) delete mode 100644 MacInstallation.md delete mode 100644 Release-1.3.md delete mode 100644 WELCOME.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 812927d3..6fb1d288 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,44 +1,91 @@ -# Contributing +The Exciting World of Ledger C +------------------------------ -## Hacking with [Nix](https://nixos.org/nix/) +Knowing C will help you in this adventure. But not as much as it should. There are some fun twists when it comes to Ledger C. Explore them below. Memorize them. There *will* be a quiz... -The `nix/` folder contains helper scripts for working with the ledger via Nix. +### Exceptions -### Installing -`nix/install.sh` will install both the wallet and baking apps. Use -`nix/install.sh s baking` to install just the baking app or -`nix/install.sh s wallet` to install just the wallet. +C doesn't have them. So you don't have to think about bracketing, exception safety, RAII, try/catch, all that. -### Developing -Use `nix/env.sh ` to enter a shell where you can run `make` and it will just work. You can also pass a command instead, e.g. `nix/env.sh s --run "make clean SHELL=bash"`. All `make` commands should be prefixed with `SHELL=bash`. Check the Makefile to see what options exist +Well not on the Ledger. You have exceptions! Which means you also have out-of-band code paths, and you now have to worry about exception safety. -For development, use `nix/watch.sh s make APP=` to incrementally build on every change. Be sure to `nix/env.sh s --run "make clean SHELL=bash"` if you start watching a different `APP`. +You can `THROW` a `uint16_t` like this `THROW(0x9000)`. -#### Debugging -Set `DEBUG=1` in the `Makefile` to so that the user-defined `parse_error()` macro provides a line-number. For `printf` style debugging see [Ledger's official instructions](https://ledger.readthedocs.io/en/latest/userspace/debugging.html) +Handling exceptions looks like this. -### Building -To do a full Nix build run `nix/build.sh`. You can pass `nix-build` arguments to this to build specific attributes, e.g. `nix/build.sh -A nano.s.wallet`. +```c +volatile int something = 0; +BEGIN_TRY { + TRY { + //do something; + } + CATCH(EXC_PARSE_ERROR) { + //do something on parse error + } + CATCH_OTHER(e) { + THROW(e); + } + FINALLY { } +} +END_TRY; +``` -### Using tezos-client -Set environment variable `TEZOS_LOG="client.signer.ledger -> debug"` when running tezos-client to get the byte-level IO being sent -directly to/from the ledger +Exceptions that make it all the way to the top of the application are caught and returned as status codes from the APDU. +#### Gotchas -### Editor Integration + 1. If a variable will be accessed both outside and inside the `BEGIN_TRY`/`END_TRY` block it must be `volatile`. The compiler doesn't expect these shenanigans and will optimize incorrectly if you don't. + 2. Do not `return` in the `TRY` block. It will cause the Ledger to crash. Instead use a `volatile` variable to capture the result you want to `return` at the end. + 3. Don't try to leave out blocks like `CATCH_OTHER(e)` and `FINALLY`. I don't know if that will work right and it's not worth the risk. -#### Visual Studio Code +#### Implications - 1. Install `llvm-vs-code-extensions.vscode-clangd` extension. - 2. Run `nix/setup-vscode.sh` to create local configuration. Note that these files are non-relocatable so you need to rerun this if you move the directory. - 3. Restart Visual Studio Code. + 1. If you have some global state and an exception is thrown then, unless you do something about it, that global state will remain. That might be a *very bad thing*. As long as you use globals our way (see Globals Our Way) you should be safe. -### Releasing -`nix/build.sh -A nano.s.release.all` +### Globals Our Way -`nix/build.sh -A nano.x.release.all` +`static const` globals are fine. `static` non-const are not fine for two reasons: -### Notes on testing + 1. If you try to initialize them (which you would want to do!) then the app will crash. For example `static int my_bool = 3;` crashes whenever you try to read or write `my_bool`... + 2. Instead of getting initialized to 0 like the C standard says, they are initialized to `0xA5`. Yes this can cause the compiler to incorrectly optimize your code. -See `test/README.md` +So just don't use `static` non-const globals. Instead we have `globals.h` which defines a large `struct` wher you can put your globals. At the beginning of the application we `memset(&global, 0, sizeof(global))` to clear it all to zeros. + +Anything inside of `global.apdu` will get cleared when an exception gets to the top of the app (see Exceptions). To benefit from this behavior you should never return an error code via the in-band way of sending bytes back. All errors should be sent via `THROW`. + +### Relocation + +When we said `static const` globals were fine, we meant that they were possible. There is +a major gotcha, however: if you initialize a `static const` value with a pointer to another +`static` or `static const` value, the pointers might be incorrect and require relocation. + +For example: + +``` +static const char important_string[] = "Important!"; +static const char **important_string_ptrs = { important_string, NULL }; +const char *str1 = important_string_ptrs[0]; +const char *str2 = important_string; +``` + +`str` will now have the wrong value. `str2` will not. The reason `str1` +has the wrong value is that the linker gets confused with a reference +from one `static const` variable to another `static` variable on this +platform. To resolve, you can use the `PIC` macro, which will fix broken +pointers but never break a good pointer. Because of this, you can use +it liberally and not have to worry about breaking anything: + +``` +static const char important_string[] = "Important!"; +static const char **important_string_ptrs = { important_string, NULL }; +const char *str1 = PIC(important_string_ptrs[0]); // necessary use of PIC +const char *str2 = PIC(important_string); // unnecessary but harmless use of PIC +``` + +Many of the UI functions call `PIC` for you, so just because a UI function +accepts a data structure, doesn't mean that data structure is valid. + +### Dynamic Allocation + +Nope. Don't even try. No `malloc`/`calloc`/`free`. Use globals (see Globals). diff --git a/MacInstallation.md b/MacInstallation.md deleted file mode 100644 index 78fc30f3..00000000 --- a/MacInstallation.md +++ /dev/null @@ -1,111 +0,0 @@ -# Installing Tezos Applications on the Ledger Nano S - -## Overview -These installation instructions have been adapted from our [README](https://github.com/obsidiansystems/ledger-app-tezos/blob/master/README.md) to be mac-specific. If you have questions regarding this installation, we recommend you refer to those instructions. - -**Note** - this guide makes 2 assumptions: -1. You have [XCode](https://developer.apple.com/xcode/) and [Homebrew](https://brew.sh/) installed. Both are available for free to download via those links. -2. You have updated your Ledger firmware to 1.4.2. You can do so through [Ledger Manager](https://www.ledgerwallet.com/apps/manager) or [Ledger Live](https://www.ledgerwallet.com/live). - -### Installing Python3 - -First, check if you have Python3 installed: - -`python3 --version` - -If this returns a version, such as `Python 3.6.5`, you can skip to the next section. If it returns nothing or you get an error, such as ‘command not found’, you’ll need to install it with homebrew: - -`brew install python` - -This step may take some time. When complete, you can confirm with `python3 --version`. It should now return a version. - -### Installing Virtualenv - -Check if you have virtualenv installed: - -`virtualenv --version` - -If this returns a version, such as `16.0.0`, you can skip to the next section. If it returns nothing or you get an error, such as ‘command not found’, you’ll need to install it: - -`pip3 install virtualenv` - -After that successfully installs, running `virtualenv --version` should now return it’s version number. - -### Clone This Repo - -Clone the Obsidian Systems Ledger App repo: - -`git clone https://github.com/obsidiansystems/ledger-app-tezos.git` - -This gives you all the tools to install the applications, but not the app files themselves. We’ll get those later. Enter the folder you just downloaded. - -`cd ledger-app-tezos` - -### Run virtualenv - -From within `/ledger-app-tezos`, run the following two commands: - -`virtualenv ledger -p python3` - -`source ledger/bin/activate` - -Your terminal session (and only that terminal session) will now be in the `virtualenv`. To have a new terminal session enter the `virtualenv`, run the above source command only in the same directory in the new terminal session. -In the shell that starts with (ledger), run (don’t use `sudo` or `pip3`!): - -`pip install ledgerblue` - -If you have to use `sudo` or `pip3` here, that is an indication that you have not correctly set up `virtualenv`. It will still work in such a situation, but please research other material on troubleshooting `virtualenv` setup. - -### Download the Application(s) - -Next you'll use the installation script to install the app on your Ledger Nano S. Let’s start by downloading the application(s) from here - `https://github.com/obsidiansystems/ledger-app-tezos/releases/`. Download the most recent version (currently 1.1 at the time of this writing). To download, use the `release.tar.gz` link - that’s where you’ll find the application hex files. Once you’ve downloaded them, move them into the `/ledger-app-tezos` folder. - -### Install the Application(s) - -We’re now ready to do the installation! The Ledger must be in the following state: -- Plugged into your computer -- Unlocked (enter your PIN) -- On the home screen (do not have any app open) -- Not asleep (you should not see vires in numeris is scrolling across the screen) - -In `virtualenv`, in the `/ledger-app-tezos` folder, run the following: -- To install the Baking app - `./install.sh "Tezos Baking" baking.hex` -- To install the Wallet App - `./install.sh "Tezos Wallet" wallet.hex` - -Pay attention to your Ledger during this process, as you’ll be prompted to confirm the installation. - -You should now see the applications on your Ledger! - -# Upgrading Applications - -Periodically, we’ll update these applications. To do the upgrade yourself, run the same commands you used for the installation! Just make sure to update the hex files you are upgrading to the new version by moving the new `baking.hex` or `wallet.hex` file to `/ledger-app-tezos`. The installation script will automatically remove the old version of the app. - -# Deleting Applications - -In that same `virtualenv` we created to install the applications, run the following command to delete them: - -`python -m ledgerblue.deleteApp --targetId 0x31100003 --appName "Tezos Baking"` - -**Note**: The part in quotes needs to be the name of the application you are trying to delete. So if you are trying to delete the Wallet App, you should change it to say “Tezos Wallet” - -# Troubleshooting - -### Ledger Prompt: “Allow unknown manager?” - -This prompt indicates that the application interacting with the Ledger is not the Ledger Manager or Ledger Live. It is expected, and not a cause for concern. - -### Ledger Prompt: “Open non-genuine app?” - -As these applications are not coming directly from Ledger Live or Ledger Manager, you should expect to see this prompt under all circumstances when following these instructions. If the ledger says “Open non-genuine app?” then freezes, this is a sign that the install was unsuccessful. You probably need to update your Ledger’s firmware to 1.4.2, then restart the process. - -### “Broken certificate chain - loading from user key” - -If you are running the installation script and you already have a version of the application on your Ledger, you will see this message. This is normal, and not a cause for concern. - -### Removing a virtualenv - -Each time you create a virtualenv, it makes a folder with that instance in it with the name you chose to call it. In these docs, we called it ledger. If you try and run virtualenv ledger and you’ve already made a ledger virtualenv, you’ll need to delete it first: - -`/ledger-app-tezos$ rm -rf ledger` - -Another alternative is to create future virtualenvs with a different name, such as ledger1. diff --git a/README.md b/README.md index 9fb89c27..9a28a58a 100644 --- a/README.md +++ b/README.md @@ -413,7 +413,7 @@ When you want to upgrade to a new version, whether you built it yourself from so or whether it's a new release of the `app.hex` files, use the same commands as you did to originally install it. As the keys are generated from the device's seeds and the derivation paths, you will have the same keys with every version of this Ledger hardware wallet app, -so there is no need to re-import the keys with `octez-client`. +so there is no need to re-import the keys with `octez-client`. You may need to run command `octez-client setup ledger to bake for ...` again as HWM and chain information would be erased after reinstalling the app. ### Special Upgrading Considerations for Bakers @@ -423,7 +423,7 @@ this command to remind the hardware wallet what key you intend to authorize for also set the HWM: ``` -$ octez-client setup ledger to bake for --main-hwm +$ octez-client setup ledger to bake for ledger_<...> --main-hwm ``` Alternatively, you can also set the High Watermark to the level of the most recently baked block with a separate command: @@ -451,7 +451,7 @@ You currently cannot directly import a fundraiser account to the Ledger device. ### Two Ledger Devices at the Same Time Two Ledger devices with the same seed should not ever be plugged in at the same time. This confuses -`tezos-client` and other client programs. Instead, you should plug only one of a set of paired +`octez-client` and other client programs. Instead, you should plug only one of a set of paired ledgers at a time. Two Ledger devices of different seeds are fine and are fully supported, and the computer will automatically determine which one to send information to. @@ -463,7 +463,7 @@ computer for wallet transactions. ### unexpected seq num ``` -$ client/bin/tezos-client list connected ledgers +$ octez-client list connected ledgers Fatal error: Header.check: unexpected seq num ``` @@ -472,7 +472,7 @@ This means you do not have the Tezos application open on your device. ### No device found ``` -$ tezos-client list connected ledgers +$ octez-client list connected ledgers No device found. Make sure a Ledger device is connected and in the Tezos Wallet app. ``` @@ -482,22 +482,22 @@ mean that your udev rules are not set up correctly. ### Unrecognized command -If you see an `Unrecognized command` error, it might be because there is no node for `tezos-client` +If you see an `Unrecognized command` error, it might be because there is no node for `octez-client` to connect to. Please ensure that you are running a node. `ps aux | grep tezos-node` should display the process information for the current node. If it displays nothing, or just displays a `grep` command, then there is no node running on your machine. ### Error "Unexpected sequence number (expected 0, got 191)" on macOS -If `tezos-client` on macOS intermittently fails with an error that looks like +If `octez-client` on macOS intermittently fails with an error that looks like ``` client.signer.ledger: APDU level error: Unexpected sequence number (expected 0, got 191) ``` -then your installation of `tezos-client` was built with an older version of HIDAPI that doesn't work well with macOS (see [#30](https://github.com/obsidiansystems/ledger-app-tezos/issues/30)). +then your installation of `octez-client` was built with an older version of HIDAPI that doesn't work well with macOS (see [#30](https://github.com/obsidiansystems/ledger-app-tezos/issues/30)). -To fix this you need to get the yet-unreleased fixes from the [HIDAPI library](https://github.com/signal11/hidapi) and rebuild `tezos-client`. +To fix this you need to get the yet-unreleased fixes from the [HIDAPI library](https://github.com/signal11/hidapi) and rebuild `octez-client`. If you got HIDAPI from Homebrew, you can update to the `master` branch of HIDAPI like this: @@ -505,7 +505,7 @@ If you got HIDAPI from Homebrew, you can update to the `master` branch of HIDAPI $ brew install hidapi --HEAD ``` -Then start a full rebuild of `tezos-client` with HIDAPI's `master` branch: +Then start a full rebuild of `octez-client` with HIDAPI's `master` branch: ```shell $ brew unlink hidapi # remove the current one @@ -518,10 +518,10 @@ Finally, rebuild `ocaml-hidapi` with Tezos. In the `tezos` repository: ```shell $ opam reinstall hidapi $ make all build-test -$ ./tezos-client list connected ledgers # should now work consistently +$ ./octez-client list connected ledgers # should now work consistently ``` -Note that you may still see warnings similar to `Unexpected sequence number (expected 0, got 191)` even after this update. The reason is that there is a separate, more cosmetic, issue in `tezos-client` itself which has already been fixed but may not be in your branch yet (see the [merge request](https://gitlab.com/tezos/tezos/merge_requests/600)). +Note that you may still see warnings similar to `Unexpected sequence number (expected 0, got 191)` even after this update. The reason is that there is a separate, more cosmetic, issue in `octez-client` itself which has already been fixed but may not be in your branch yet (see the [merge request](https://gitlab.com/tezos/tezos/merge_requests/600)). ### Command Line Installations: "This app is not genuine" diff --git a/Release-1.3.md b/Release-1.3.md deleted file mode 100644 index f4aacd01..00000000 --- a/Release-1.3.md +++ /dev/null @@ -1,173 +0,0 @@ -# Version 1.3 of the Tezos Wallet and Baking Applications for Ledger Nano S - -## Release Highlights - -### Ledger Nano S Wallet Application -- [x] Transactions now display with: source, destination, amount and fee -- [x] Delegations now display with: source, delegate, amount and fee -- [x] Account originations now display with: source, manager, fee, amount and delegation -- [x] Support for browser access through U2F - -In addition to the improved user experience, these changes are important security enablers, as it -can help a cautious user protect against a certain type of attack. There are also instances where the Ledger device will not display operation information listed above. See more details below. - -### Ledger Nano S Baking Application -- [x] High watermark feature extended to protect against double-endorsing as well as double-baking. - -## Ledger Nano S Wallet Application -- Release Details -### Operation Display -The new version of the Wallet App will display certain fields of most -transactions, delegations, and account origination in the prompt where -the user is asked to approve or reject the delegation. In addition to the -improved user experience, this is an important security improvement, as it -can help a cautious user protect against a certain type of attack. Without -this measure, an attacker with control over your computer can replace a -legitimate transaction with a falsified transaction, which could send -any amount of tez from any wallet on the Ledger hardware wallet (with any derivation -path) to the attacker, and the user would approve it thinking it was the -transaction they intended. The security benefit is only realized if the -user manually verifies the relevant fields. - -The fields are displayed in sequence, one after another. To verify all -the fields, you must wait for all of the fields to display in order. -The sequence is repeated 3 times, after which the app will default to -a rejection of the transaction. - -#### Transactions -* Source: -This is the account from which the tez are to be transferred. Because -the ledger embodies as many accounts as there are derivation paths, -it might be important to verify that the transaction originates from -the intended account. - -* Destination: -This is the account to which the tez are to be transferred. If this were -faked, the attacker could send to their own account instead. - -* Amount: -This is the amount of tez to be sent. If this were faked, an attacker -with a relationship with the recipient could cause more tez to be sent -than desired. - -* Fee: -This is the fee given to the baker of the block on which the transaction -will be included. If this were faked, a baker with a relationship to -the attacker could end up with the stolen tez, especially if the fee -were astronomical. - -#### Delegations -* Source: -This is which account is to be delegated. If this were faked, the attacker -could prevent the user from using a delegation service or registering -for delegation, or change the delegation on a different account to the -delegation service. - -* Delegate: -This is the address to which the user is delegating baking rights. If -this were faked, the attacker could substitute their own delegation -service for the intended one. We also indicate the distinction between -delegating and withdrawing delegation. - -* Fee: See above. - -#### Originations -* Source: -This is where the original funding of the originated account comes -from. If this were faked, an attacker could affect the allocation of -the user's tez between accounts. - -* Manager: -This is what key will be used to manage the originated account. If this -were faked, the attacker could set it to their own key, and gain control -over the new account and its tez. - -* Fee: See above. - -* Amount: -This is the amount that will be transferred into the new, originated -account. If this were faked, it could prevent the user from using the -new account as intended. - -* Delegation: -We display both whether the originated account is set up to allow -delegation, and which account it is originally set up to delegate to. If -it is set up to allow delegation but not set up with an initial delegate, -we display "Any" as the delegate. If it is set up to delegate but not -to change delegation, we display "Fixed Delegate" as the label for the -account. Any changes to the delegation settings on an originated account -could cause various inconveniences to the user, and potentially could -be useful in a sophisticated attack. - -### Unverified Operations - -Sometimes the wallet app will not be able to parse an operation, and -will prompt for an unverified signature. In this case, most users will -want to reject the operation. - -The wallet app may not capable of parsing the message because of -advanced features in it. In this case, it displays a special prompt: -"Unrecognized Operation, Sign Unverified?" This should not happen with -ordinary transactions and delegations, but may happen in the presence -of optional information like fields that will be sent to contracts or -smart contract originations. If you are not using these features, you -should reject the transaction. You should only approve it if you are -using these features, and are confident in your computer's security. -Among advanced features is included non-zero storage limits. This -is because storage limits can cost additional tez, and so we want -to make sure that users are not surprised by these additional costs. - -The wallet app also allows the signing of prehashed data, which it will -not be able to parse. In this situation, it will display "Pre-hashed -Operation, Sign Unverified?" You should not approve this transaction -unless you intentionally sent pre-hashed data to the ledger and are -confident in your computer's security. Pre-hashed data is not -exposed as a feature in `tezos-client`, and can only be sent -manually. Most users will never need to use this feature. - -### U2F Support - -The Wallet Application now supports U2F protocol, the standard method for enabling -browser access by 3rd party wallet providers for all tokens. Recent versions -of Ledger Nano S firmware (v1.4.1+) allow us to support browsers seamlessly without the need -to toggle it in settings; the app will automatically detect which protocol is -being used. - -#### APDU level error: Unexpected sequence number (expect 0, got 191) - -As a side effect of adding U2F support, users will see this error when sending operations -to the Wallet Application. There are two situations where this error will fire: - -* If you send an operation to the Tezos Wallet Application. `tezos-client` might interpret -the presence of U2F support as a sequence number error, but it will recover from this error -and successfully be able to communicate with the device over APDU protocol. In our experience, -the operation always succeeds despite this error. We intend to have the error message from `tezos-client` -adjusted to reflect the success of these operations. -* If you send an operation to the Ledger device and neither Tezos Application is open. -You'll be communicating with the ledger OS, not one of the Tezos Applications. - -## Baking Application -- Release Details -The new version of the Baking Application extends the concept of the high watermark to -endorsements as well as block headers, as a precaution against double -baking and double endorsing. No block header or endorsement will be signed at a lower block -level than a previous block or endorsement. Furthermore, only one block -and one endorsement is allowed at each level, and the block must come -before the endorsement. Both block headers and endorsements are -signed without prompting if they satisfy the high watermark requirement, -and rejected without prompting if they do not. - -This covers all legitimate operation of a baker in a single chain. -If a single baker has multiple endorsement slots at the same block -level, only one endorsement will actually need to be signed, and you -will receive the reward for all the endorsement slots at that level. - -As before, you may reset the high watermark with a reset command -(`tezos-client set ledger high watermark for to `), which -will prompt "Reset HWM" and the new value. Legitimate reasons to change the high -watermark include switching to a test network at a different block level or -restoring a baker after an attacker or software error caused a block to be signed -with too high a level. - -## Acknowledgements - -Thank you to everyone in the tezos-baking Slack channel, especially Tom -Knudsen and Tom Jack, for their testing and bug reports. diff --git a/WELCOME.md b/WELCOME.md deleted file mode 100644 index 6fb1d288..00000000 --- a/WELCOME.md +++ /dev/null @@ -1,91 +0,0 @@ -The Exciting World of Ledger C ------------------------------- - -Knowing C will help you in this adventure. But not as much as it should. There are some fun twists when it comes to Ledger C. Explore them below. Memorize them. There *will* be a quiz... - -### Exceptions - -C doesn't have them. So you don't have to think about bracketing, exception safety, RAII, try/catch, all that. - -Well not on the Ledger. You have exceptions! Which means you also have out-of-band code paths, and you now have to worry about exception safety. - -You can `THROW` a `uint16_t` like this `THROW(0x9000)`. - -Handling exceptions looks like this. - -```c -volatile int something = 0; -BEGIN_TRY { - TRY { - //do something; - } - CATCH(EXC_PARSE_ERROR) { - //do something on parse error - } - CATCH_OTHER(e) { - THROW(e); - } - FINALLY { } -} -END_TRY; -``` - -Exceptions that make it all the way to the top of the application are caught and returned as status codes from the APDU. - -#### Gotchas - - 1. If a variable will be accessed both outside and inside the `BEGIN_TRY`/`END_TRY` block it must be `volatile`. The compiler doesn't expect these shenanigans and will optimize incorrectly if you don't. - 2. Do not `return` in the `TRY` block. It will cause the Ledger to crash. Instead use a `volatile` variable to capture the result you want to `return` at the end. - 3. Don't try to leave out blocks like `CATCH_OTHER(e)` and `FINALLY`. I don't know if that will work right and it's not worth the risk. - -#### Implications - - 1. If you have some global state and an exception is thrown then, unless you do something about it, that global state will remain. That might be a *very bad thing*. As long as you use globals our way (see Globals Our Way) you should be safe. - - -### Globals Our Way - -`static const` globals are fine. `static` non-const are not fine for two reasons: - - 1. If you try to initialize them (which you would want to do!) then the app will crash. For example `static int my_bool = 3;` crashes whenever you try to read or write `my_bool`... - 2. Instead of getting initialized to 0 like the C standard says, they are initialized to `0xA5`. Yes this can cause the compiler to incorrectly optimize your code. - -So just don't use `static` non-const globals. Instead we have `globals.h` which defines a large `struct` wher you can put your globals. At the beginning of the application we `memset(&global, 0, sizeof(global))` to clear it all to zeros. - -Anything inside of `global.apdu` will get cleared when an exception gets to the top of the app (see Exceptions). To benefit from this behavior you should never return an error code via the in-band way of sending bytes back. All errors should be sent via `THROW`. - -### Relocation - -When we said `static const` globals were fine, we meant that they were possible. There is -a major gotcha, however: if you initialize a `static const` value with a pointer to another -`static` or `static const` value, the pointers might be incorrect and require relocation. - -For example: - -``` -static const char important_string[] = "Important!"; -static const char **important_string_ptrs = { important_string, NULL }; -const char *str1 = important_string_ptrs[0]; -const char *str2 = important_string; -``` - -`str` will now have the wrong value. `str2` will not. The reason `str1` -has the wrong value is that the linker gets confused with a reference -from one `static const` variable to another `static` variable on this -platform. To resolve, you can use the `PIC` macro, which will fix broken -pointers but never break a good pointer. Because of this, you can use -it liberally and not have to worry about breaking anything: - -``` -static const char important_string[] = "Important!"; -static const char **important_string_ptrs = { important_string, NULL }; -const char *str1 = PIC(important_string_ptrs[0]); // necessary use of PIC -const char *str2 = PIC(important_string); // unnecessary but harmless use of PIC -``` - -Many of the UI functions call `PIC` for you, so just because a UI function -accepts a data structure, doesn't mean that data structure is valid. - -### Dynamic Allocation - -Nope. Don't even try. No `malloc`/`calloc`/`free`. Use globals (see Globals).