Skip to content

Project 1

P1 Meme

Overview

This project is intended to serve as an introduction to the project template, build tools, and process to complete projects during this semester. This project demonstrates the only officially supported tools and programming languages.

We are going to review the following topics:

  1. How to setup your project with the provided starter code
  2. How to use the build system
  3. How to write unit tests
  4. Demonstrate address sanitizer output
  5. How to use the debugger
  6. Submitting the project over email

Learning Outcomes

  • 5.1 Compile your code with a build system
  • 5.2 Use a professional unit test framework (win32, posix)
  • 5.3 Use a professional version control system (git)
  • 5.4 Explore compiling and running code on at least 2 different systems (Codespaces and the CS Lab)
  • 5.5 Explore how to setup a continuous integration and testing project

Grading Rubric

Make sure and review the class grading rubric so you know how your project will be graded.

Task 1 - Setup

Follow the steps below to get your repository all setup and ready to use. The steps below show you how to use and setup GitHub codespaces. You are not required to use codespaces, all the steps below can be completed in the CS Lab or on your personal machine if you prefer.

Fork the starter repository

  1. Fork the starter repository into your personal GitHub account: https://github.com/shanep/makefile-project-starter

fork repo

  1. In the new fork name the repository cs452-p1

fork name

Start a new Codespace

We will use GitHub Codespaces to do most of our coding. Codespaces is just VSCode in the cloud. This makes it really easy to setup a developer environment and code from any computer that has a browser and internet connection!

Start Codespace

  1. If you are asked to install recommended extensions click "install". You may not be asked to install extensions if you are already syncing your account.

Codespace extensions

You now should have a new repository (forked from the starter template) that is ready to use.

Task 2 - Prepare your repository

The starter repository is a bare bones template that you will need to update with the starter code below.

src/lab.h

c
#ifndef LAB_H
#define LAB_H
#include <stdlib.h>
#include <stdbool.h>

#define MAX_VERSION_STRING 10
#define lab_VERSION_MAJOR 1
#define lab_VERSION_MINOR 0
#define UNUSED(x) (void)(x)

#ifdef __cplusplus
extern "C"
{
#endif

  /**
   * @brief Returns a string containing the version of the library.
   * This string has been allocated using malloc and must be freed
   * by the caller.
   *
   * @return char* The version string
   */
  char *getVersion(void);

  /**
   * @brief This function causes a segfault to demo Address Sanitizer
   *
   */
  int segfault(void);

  /**
   * @brief This function causes an array out of bounds error to
   * demo Address Sanitizer
   *
   */
  void outOfBounds(void);

#ifdef __cplusplus
} // extern "C"
#endif

#endif

src/lab.c

c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <readline/readline.h>
#include "lab.h"

char *getVersion(void)
{
  char *version = (char *)malloc(MAX_VERSION_STRING);
  snprintf(version, MAX_VERSION_STRING, "%d.%d", lab_VERSION_MAJOR, lab_VERSION_MINOR);
  return version;
}

int segfault(void)
{
  // add volatile because clang will optimize out the segfault
  volatile int *foo = NULL;
  int bar = *foo;
  return bar;
}

void outOfBounds(void)
{
  int arr[5] = {0, 1, 2, 3, 4};
  int i = 0;
  for (i = 0; i < 6; i++)
    {
      arr[i] = i;
    }
  UNUSED(arr);
}

app/main.c

c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <readline/readline.h>
#include "../src/lab.h"

int main(void)
{
  char *line = (char *)NULL;
  char *version = getVersion();
  line = readline("What is your name?");
  printf("Hello %s! This is the starter template version: %s\n", line, version);
  return 0;
}

tests/test-lab.c

c
#include "harness/unity.h"
#include "../src/lab.h"


void setUp(void) {
    // set stuff up here
}

void tearDown(void) {
    // clean stuff up here
}

void test_leak(void) {
  char *version = getVersion();
  TEST_ASSERT_EQUAL_STRING("1.0", version);
}

void test_segfault(void) {
  segfault();
}

void test_bounds(void){
  outOfBounds();
}

int main(void) {
    UNITY_BEGIN();
    RUN_TEST(test_leak);
    RUN_TEST(test_segfault);
    RUN_TEST(test_bounds);
    return UNITY_END();
}

Once you have updated all the starter code lets make your first commit so everything is saved. Open up a terminal and lets make a commit!

bash
git add --all
git commit -m "Added in starter code"

Here is what it should look like.

bash
$ git add --all
$ git commit -m "Added in starter code"
[master 9c0e920] Added in starter code
 4 files changed, 101 insertions(+), 12 deletions(-)
@BSU-ShanePanter /workspaces/cs452-p1 (master) $ git push
Enumerating objects: 17, done.
Counting objects: 100% (16/16), done.
Delta compression using up to 2 threads
Compressing objects: 100% (8/8), done.
Writing objects: 100% (9/9), 1.67 KiB | 1.67 MiB/s, done.
Total 9 (delta 1), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (1/1), completed with 1 local object.
To https://github.com/BSU-ShanePanter/cs452-p1
   d21d6bc..9c0e920  master -> master

Task 3 - Compile

You can compile the project by typing make in the terminal. Once you have successfully compiled the project you can run the executable like this:

bash
@BSU-ShanePanter /workspaces/cs452-p1 (master) $ make
mkdir -p build/src/
cc -Wall -Wextra -fno-omit-frame-pointer -fsanitize=address -g -MMD -MP -c src/lab.c -o build/src/lab.c.o
mkdir -p build/app/
cc -Wall -Wextra -fno-omit-frame-pointer -fsanitize=address -g -MMD -MP -c app/main.c -o build/app/main.c.o
cc -Wall -Wextra -fno-omit-frame-pointer -fsanitize=address -g -MMD -MP build/src/lab.c.o build/app/main.c.o -o myprogram -pthread -lreadline
mkdir -p build/tests/harness/
cc -Wall -Wextra -fno-omit-frame-pointer -fsanitize=address -g -MMD -MP -c tests/harness/unity.c -o build/tests/harness/unity.c.o
mkdir -p build/tests/
cc -Wall -Wextra -fno-omit-frame-pointer -fsanitize=address -g -MMD -MP -c tests/test-lab.c -o build/tests/test-lab.c.o
cc -Wall -Wextra -fno-omit-frame-pointer -fsanitize=address -g -MMD -MP build/src/lab.c.o build/tests/harness/unity.c.o build/tests/test-lab.c.o  -o test-lab -pthread -lreadline
@BSU-ShanePanter /workspaces/cs452-p1 (master) $ ./myprogram
What is your name?shane
Hello shane! This is the starter template version: 1.0

=================================================================
==8990==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 10 byte(s) in 1 object(s) allocated from:
    #0 0x7f0014924808 in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cc:144
    #1 0x5646c7cd62be in getVersion src/lab.c:9
    #2 0x5646c7cd6660 in main app/main.c:10
    #3 0x7f00145d6082 in __libc_start_main ../csu/libc-start.c:308

Direct leak of 6 byte(s) in 1 object(s) allocated from:
    #0 0x7f0014924808 in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cc:144
    #1 0x7f001480300c in xmalloc (/lib/x86_64-linux-gnu/libreadline.so.8+0x3c00c)

SUMMARY: AddressSanitizer: 16 byte(s) leaked in 2 allocation(s).

Well that is not good! We have a memory leak in the starter code that we need to fix. Open up the file app/main.c and free the line and version variables after the printf call.

c
free(line);
free(version);

Now compile and run the program again to see the fix.

bash
@BSU-ShanePanter /workspaces/cs452-p1 (master) $ make
mkdir -p build/app/
cc -Wall -Wextra -fno-omit-frame-pointer -fsanitize=address -g -MMD -MP -c app/main.c -o build/app/main.c.o
cc -Wall -Wextra -fno-omit-frame-pointer -fsanitize=address -g -MMD -MP build/src/lab.c.o build/app/main.c.o -o myprogram -pthread -lreadline
@BSU-ShanePanter /workspaces/cs452-p1 (master) $ ./myprogram
What is your name?shane
Hello shane! This is the starter template version: 1.0

Lets commit our work so far.

bash
git add app/main.c
git commit -m "Fixed leak in main.c"
git push

So far so good. We now have a working executable that is bug free. Lets move on to the tests.

Task 4 - Test

The starter template is setup with a testing harness that will make it easy to write and run tests. You can compile all the tests and then run them by typing make check. The project template is setup to compile your code with Address Sanitizer. This approach will allow us to write high quality code and catch bugs early so when we are working on larger projects we can focus on the project requirements instead of the low level details of memory errors. Address sanitizer can detect the following types of bugs:

  • Out-of-bounds accesses to heap, stack and globals
  • Use-after-free
  • Use-after-return (clang flag -fsanitize-address-use-after-return=(never|runtime|always) default: runtime)
  • Enable runtime with: ASAN_OPTIONS=detect_stack_use_after_return=1
  • Use-after-scope (clang flag -fsanitize-address-use-after-scope)
  • Double-free, invalid free
  • Memory leaks (experimental and currently only on linux)

You should see a bunch of tests fail. You need to fix all the issues in the project before proceeding to the next task. There should be no build warnings, no disabled tests, and everything should pass.

INFO

This is just a warm-up project. The functions that are failing can be fixed in any number of ways. I am not looking for any specific fix, I am just looking for you to make the tests pass instead.

Fix all the tests in the file tests/test-lab.c to pass just like we did in the previous step. Once you have all the tests passing make sure and do a git add, git commit and git push just like the previous task.

Once you have fixed all the broken tests you should see a clean test run will all tests passing.

bash
@BSU-ShanePanter /workspaces/cs452-p1 (master) $ make check
mkdir -p build/tests/
cc -Wall -Wextra -fno-omit-frame-pointer -fsanitize=address -g -MMD -MP -c tests/test-lab.c -o build/tests/test-lab.c.o
cc -Wall -Wextra -fno-omit-frame-pointer -fsanitize=address -g -MMD -MP build/src/lab.c.o build/tests/harness/unity.c.o build/tests/test-lab.c.o  -o test-lab -pthread -lreadline
ASAN_OPTIONS=detect_leaks=1 ./test-lab
tests/test-lab.c:29:test_leak:PASS
tests/test-lab.c:30:test_segfault:PASS
tests/test-lab.c:31:test_bounds:PASS

-----------------------
3 Tests 0 Failures 0 Ignored
OK

Task 5 - Run the debugger

This starter template should work out of the box for both unit tests and the executable. Open the debugger view in VSCode and set a breakpoint in the main function and a breakpoint in one of the functions in the tests/test-lab.c file. Run the debugger and verify that the debugger stops at the breakpoints. You will need to run the debugger separately for the unit tests and the executable.

Debugger

DANGER

While this task is not graded it is important that you are able to use the debugger, so don't skip this task. Make sure you can use the debugger now instead of at 11:45pm the night the project is due and there is no one around to help you.

Debugger example

Final Task - Submit your code

Now that you have completed all the tasks the only thing left to do is to submit your code as a patch so you can receive a grade for all your hard work.

Turn on Two Factor

Turn on Two factor authentication for your Boise State provided email account

DANGER

Do NOT skip this step. Boise State University uses Gmail as their email provider and Gmail requires you to use two factor authentication in order to generate an app password.

You need to use your Boise State University issued email account to send the email and you must have two factor authentication turned on.

Generate an app password

INFO

If you are working in GitHub codespaces you will need to setup SMTP for EACH project. This is because each codespace is tied to a specific repository and the settings are not shared. However, if you are working on your own personal machine or in the CS Lab then you will only have to setup SMTP once!

In order to use git send-email you will need to generate an app password. Navigate to https://security.google.com/settings/security/apppasswords and generate a new app password. Make sure and copy the password before you close the window because you will not be able to see it again.

generate app password

I can't generate a password

If you get the error shown below it typically means that you have not enabled two factor authentication. Follow these steps to resolve the issue:

  1. Go back and ensure you have two factor authentication enabled.
  2. Log out of your Gmail account
  3. Log back into your Gmail account and make sure you did have to use two factor authentication
  4. If the steps above fail then open an incognito tab and go back to the first step
  5. If you still have issues reboot your machine and go back to the first step

app password error

Setup SMTP

  1. Open up a terminal in codespaces

Open Terminal

  1. In the terminal type git config --global --edit and modify the file with the info listed below. You will need to change the info listed below to match your own name, email and App Password that you generated in the previous step.
text
[User]
	name =  YOUR NAME
	email = YOURNAME@u.boisestate.edu
[sendemail]
	smtpserver = smtp.gmail.com
	smtpuser = YOURNAME@u.boisestate.edu
	smtpPass = xxxx xxxx xxxx xxxx
	smtpencryption = ssl
	smtpserverport = 465

Edit config

Congrats you should be all setup to send code patch's over email. Now lets create a patch!

Create a patch file

We are now going to do what is called a squash merge and then create a patch file with all our changes in one commit.

  1. First lets fetch the upstream branch. This is the branch that you originally forked from at the start of the project
bash
git fetch upstream
  1. Checkout a new branch named submit from the upstream/master branch.
bash
git checkout upstream/master -b submit
  1. Now we will do a squash merge all the commits we did onto our new submit branch.
bash
git merge --squash master
  1. Now commit those new changes to your submit branch
bash
git commit -m "Submit project"
  1. Push your submit branch to GitHub
bash
git push -u origin
  1. Open up a web browser and navigate to your repository on GitHub and confirm that your submit branch is correctly pushed. Open up the files and make sure that everything looks good before going to the next step.

submit-branch

Install Libraries

If you are working on codespaces you will need to install the required dependencies before you attempt to email out your patch file.

bash
make install-deps

Email Patch File

First make sure you are still on the submit branch that you created. If you type git branch you should see a star next to the submit branch that indicates you are currently on the submit branch.

bash
$ git branch
  master
* submit

WARNING

You MUST test your patch by emailing it to yourself first! You will go through all the steps below with your own email. After you have sent the email to yourself and tested it you can then email your submission to the class mailing list!

Finally we can create our patch to email out!

bash
git send-email --to youremail@u.boisestate.edu HEAD^

You should see results similar to what is show below.

bash
$ git send-email --to youremail@u.boisestate.edu HEAD^
/tmp/T/NWEw4f1sIj/0001-Submit-project-2.patch

From: youremail@u.boisestate.edu
To:  youremail@u.boisestate.edu
Subject: [PATCH] Submit project
Date: Thu,  7 Dec 2023 20:31:55 -0700
Message-Id: <20231208033155.83099-1-shanepanter@boisestate.edu>
X-Mailer: git-send-email 2.39.3 (Apple Git-145)
MIME-Version: 1.0
Content-Transfer-Encoding: 8bit

The Cc list above has been expanded by additional
addresses found in the patch commit message. By default
send-email prompts before sending whenever this occurs.
This behavior is controlled by the sendemail.confirm
configuration setting.

For additional information, run 'git send-email --help'.
To retain the current behavior, but squelch this message,
run 'git config --global sendemail.confirm auto'.

Send this email? ([y]es|[n]o|[e]dit|[q]uit|[a]ll): y
OK. Log says:
Server: smtp.gmail.com
MAIL FROM:  youremail@u.boisestate.edu
RCPT TO:  youremail@u.boisestate.edu
RCPT TO:  youremail@u.boisestate.edu
From: youremail@u.boisestate.edu
To:  youremail@u.boisestate.edu
Subject: [PATCH] Submit project 2
Date: Thu,  7 Dec 2023 20:31:55 -0700
Message-Id: <20231208033155.83099-1-shanepanter@boisestate.edu>
X-Mailer: git-send-email 2.39.3 (Apple Git-145)
MIME-Version: 1.0
Content-Transfer-Encoding: 8bit

Result: 250

You should now be able to check your email and see your patch. Be aware that sometimes email delivery is slightly delayed so you may have to wait a few minutes for it to show up. Make sure and check your spam folder if you don't see any mail.

Test your patch

You can now get your patch from Gmail and test it to make sure that everything works and your patch was correct.

  1. Checkout a new branch named test-patch from the upstream/master branch
bash
git checkout upstream/master -b test-patch
  1. Push your new test-patch branch to your repo instead of the upstream
bash
 git push -u origin
  1. Get the patch file from Gmail

download gmail

  1. Copy the email to your clip board

copy to clipboard

  1. Create a new file and paste the contents that you just copied and save it in the root folder in a file named my-patch.txt.

new file

  1. Make sure you saved the file correctly. It should show up in the file explorer as shown below.

created file

  1. Now apply that patch to your new test-patch branch
bash
git am my-patch.txt
  1. Commit your patch
bash
git commit -m "Testing my email patch"
  1. Push your test patch branch to your Github Account
bash
git push
  1. After you have successfully applied the patch you can delete the file my-patch.txt. Don't commit the file my-patch.txt it is just a temporary file that you don't want to save.

  2. Finally open up the browser again and make sure you have 3 branches master, submit, and test-patch. The submit and test-patch branches should be identical. Each should have exactly 1 commit from you with all your changes.

final state

Submit your Patch for grading

Assuming you have successfully completed all the steps above with your own email and everything looked good you can now submit your patch for grading.

DANGER

Do not use the class mailing list to test your patch. You should only send an email to email is in the syllabus after you have tested the process with your own email. Spamming the mailing list with excessive patches will result in a lower grade.

When you submit to the mailing list you will automatically be cc'd on the email so you will have a copy in your own email as proof that you completed the assignment.

You are allowed to submit up to 3 times without penalty.

Open a terminal and submit your patch.

git checkout submit
git send-email --to email is in the syllabus HEAD^

Assuming all went well you are now complete! You have created a patch file from a squash merge, emailed it and tested the resulting patch. You are well on your way to becoming an advanced git user!

Submitting

You do not need to submit anything to canvas for this assignment. Your email is your submission, your grade will be updated after the due date (and late window) have passed.

Released under the MIT License.