merge in oc-release history after reset to master
diff --git a/Android.mk b/Android.mk
index 6a63e87..ecc5e97 100644
--- a/Android.mk
+++ b/Android.mk
@@ -195,7 +195,7 @@
 
 
 # Syscall filtering native unit tests for the host. Run with:
-# out/host/linux-x86/nativetest(64)/syscall_filter_unittest/syscall_filter_unittest_gtest
+# out/host/linux-x86/nativetest(64)/syscall_filter_unittest_gtest/syscall_filter_unittest_gtest
 # =========================================================
 include $(CLEAR_VARS)
 LOCAL_MODULE := syscall_filter_unittest_gtest
diff --git a/bpf.c b/bpf.c
index b618866..8f5a08d 100644
--- a/bpf.c
+++ b/bpf.c
@@ -267,8 +267,9 @@
 	}
 	end = begin + labels->count;
 	for (id = 0; begin < end; ++begin, ++id) {
-		if (!strcmp(label, begin->label))
+		if (!strcmp(label, begin->label)) {
 			return id;
+		}
 	}
 
 	/* The label wasn't found. Insert it only if there's space. */
@@ -284,7 +285,6 @@
 	return id;
 }
 
-/* Free label strings. */
 void free_label_strings(struct bpf_labels *labels)
 {
 	if (labels->count == 0)
diff --git a/parse_seccomp_policy.cc b/parse_seccomp_policy.cc
index c50b79e..a9daed0 100644
--- a/parse_seccomp_policy.cc
+++ b/parse_seccomp_policy.cc
@@ -32,7 +32,7 @@
 	}
 
 	struct sock_fprog fp;
-	int res = compile_filter(f, &fp, 0);
+	int res = compile_filter(f, &fp, 0, 0);
 	if (res != 0) {
 		die("compile_filter failed");
 	}
diff --git a/syscall_filter.c b/syscall_filter.c
index ad84921..3318052 100644
--- a/syscall_filter.c
+++ b/syscall_filter.c
@@ -12,14 +12,13 @@
 #include "util.h"
 
 /* clang-format off */
-#define MAX_LINE_LENGTH 	1024
 #define MAX_POLICY_LINE_LENGTH	1024
 
 #define ONE_INSTR	1
 #define TWO_INSTRS	2
 /* clang-format on */
 
-int seccomp_can_softfail()
+int seccomp_can_softfail(void)
 {
 #if defined(USE_SECCOMP_SOFTFAIL)
 	return 1;
@@ -51,7 +50,7 @@
 	return buf;
 }
 
-struct filter_block *new_filter_block()
+struct filter_block *new_filter_block(void)
 {
 	struct filter_block *block = calloc(1, sizeof(struct filter_block));
 	if (!block)
@@ -278,10 +277,10 @@
 	return 0;
 }
 
-struct filter_block *compile_section(int nr, const char *policy_line,
-				     unsigned int entry_lbl_id,
-				     struct bpf_labels *labels,
-				     int use_ret_trap)
+struct filter_block *compile_policy_line(int nr, const char *policy_line,
+					 unsigned int entry_lbl_id,
+					 struct bpf_labels *labels,
+					 int use_ret_trap)
 {
 	/*
 	 * |policy_line| should be an expression of the form:
@@ -429,17 +428,115 @@
 	return head;
 }
 
-int compile_filter(FILE *policy_file, struct sock_fprog *prog, int use_ret_trap,
-		   int allow_logging)
+int compile_file(FILE *policy_file, struct filter_block *head,
+		 struct filter_block **arg_blocks, struct bpf_labels *labels,
+		 int use_ret_trap, int allow_logging)
 {
-	char line[MAX_LINE_LENGTH];
-	int line_count = 0;
+	/*
+	 * Loop through all the lines in the policy file.
+	 * Build a jump table for the syscall number.
+	 * If the policy line has an arg filter, build the arg filter
+	 * as well.
+	 * Chain the filter sections together and dump them into
+	 * the final buffer at the end.
+	 */
+	char *line = NULL;
+	size_t len = 0;
+	while (getline(&line, &len, policy_file) != -1) {
+		char *policy_line = line;
+		char *syscall_name = strsep(&policy_line, ":");
+		int nr = -1;
 
+		syscall_name = strip(syscall_name);
+
+		/* Allow comments and empty lines. */
+		if (*syscall_name == '#' || *syscall_name == '\0') {
+			/* Reuse |line| in the next getline() call. */
+			continue;
+		}
+
+		policy_line = strip(policy_line);
+		if (*policy_line == '\0') {
+			warn("compile_file: empty policy line");
+			free(line);
+			return -1;
+		}
+
+		nr = lookup_syscall(syscall_name);
+		if (nr < 0) {
+			warn("compile_file: nonexistent syscall '%s'",
+			     syscall_name);
+			if (allow_logging) {
+				/*
+				 * If we're logging failures, assume we're in a
+				 * debugging case and continue.
+				 * This is not super risky because an invalid
+				 * syscall name is likely caused by a typo or by
+				 * leftover lines from a different architecture.
+				 * In either case, not including a policy line
+				 * is equivalent to killing the process if the
+				 * syscall is made, so there's no added attack
+				 * surface.
+				 */
+				/* Reuse |line| in the next getline() call. */
+				continue;
+			}
+			free(line);
+			return -1;
+		}
+
+		/*
+		 * For each syscall, add either a simple ALLOW,
+		 * or an arg filter block.
+		 */
+		if (strcmp(policy_line, "1") == 0) {
+			/* Add simple ALLOW. */
+			append_allow_syscall(head, nr);
+		} else {
+			/*
+			 * Create and jump to the label that will hold
+			 * the arg filter block.
+			 */
+			unsigned int id = bpf_label_id(labels, syscall_name);
+			struct sock_filter *nr_comp =
+			    new_instr_buf(ALLOW_SYSCALL_LEN);
+			bpf_allow_syscall_args(nr_comp, nr, id);
+			append_filter_block(head, nr_comp, ALLOW_SYSCALL_LEN);
+
+			/* Build the arg filter block. */
+			struct filter_block *block = compile_policy_line(
+			    nr, policy_line, id, labels, use_ret_trap);
+
+			if (!block) {
+				if (*arg_blocks) {
+					free_block_list(*arg_blocks);
+				}
+				free(line);
+				return -1;
+			}
+
+			if (*arg_blocks) {
+				extend_filter_block_list(*arg_blocks, block);
+			} else {
+				*arg_blocks = block;
+			}
+		}
+		/* Reuse |line| in the next getline() call. */
+	}
+	free(line);
+	return 0;
+}
+
+int compile_filter(FILE *initial_file, struct sock_fprog *prog,
+		   int use_ret_trap, int allow_logging)
+{
 	struct bpf_labels labels;
 	labels.count = 0;
 
-	if (!policy_file)
+	if (!initial_file) {
+		warn("compile_filter: |initial_file| is NULL");
 		return -1;
+	}
 
 	struct filter_block *head = new_filter_block();
 	struct filter_block *arg_blocks = NULL;
@@ -458,93 +555,13 @@
 	if (allow_logging)
 		allow_logging_syscalls(head);
 
-	/*
-	 * Loop through all the lines in the policy file.
-	 * Build a jump table for the syscall number.
-	 * If the policy line has an arg filter, build the arg filter
-	 * as well.
-	 * Chain the filter sections together and dump them into
-	 * the final buffer at the end.
-	 */
-	while (fgets(line, sizeof(line), policy_file)) {
-		++line_count;
-		char *policy_line = line;
-		char *syscall_name = strsep(&policy_line, ":");
-		int nr = -1;
-
-		syscall_name = strip(syscall_name);
-
-		/* Allow comments and empty lines. */
-		if (*syscall_name == '#' || *syscall_name == '\0')
-			continue;
-
-		if (strlen(policy_line) == 0) {
-			warn("compile_filter: empty policy line");
-			free_block_list(head);
-			return -1;
-		}
-
-		nr = lookup_syscall(syscall_name);
-		if (nr < 0) {
-			warn("compile_filter: nonexistent syscall '%s'",
-			     syscall_name);
-			if (allow_logging) {
-				/*
-				 * If we're logging failures, assume we're in a
-				 * debugging case and continue.
-				 * This is not super risky because an invalid
-				 * syscall name is likely caused by a typo or by
-				 * leftover lines from a different architecture.
-				 * In either case, not including a policy line
-				 * is equivalent to killing the process if the
-				 * syscall is made, so there's no added attack
-				 * surface.
-				 */
-				continue;
-			}
-			free_block_list(head);
-			return -1;
-		}
-
-		policy_line = strip(policy_line);
-
-		/*
-		 * For each syscall, add either a simple ALLOW,
-		 * or an arg filter block.
-		 */
-		if (strcmp(policy_line, "1") == 0) {
-			/* Add simple ALLOW. */
-			append_allow_syscall(head, nr);
-		} else {
-			/*
-			 * Create and jump to the label that will hold
-			 * the arg filter block.
-			 */
-			unsigned int id = bpf_label_id(&labels, syscall_name);
-			struct sock_filter *nr_comp =
-			    new_instr_buf(ALLOW_SYSCALL_LEN);
-			bpf_allow_syscall_args(nr_comp, nr, id);
-			append_filter_block(head, nr_comp, ALLOW_SYSCALL_LEN);
-
-			/* Build the arg filter block. */
-			struct filter_block *block = compile_section(
-			    nr, policy_line, id, &labels, use_ret_trap);
-
-			if (!block) {
-				if (arg_blocks) {
-					free_block_list(arg_blocks);
-				}
-				free_label_strings(&labels);
-				free_block_list(head);
-				return -1;
-			}
-
-			if (arg_blocks) {
-				extend_filter_block_list(arg_blocks, block);
-			} else {
-				arg_blocks = block;
-			}
-		}
+	if (compile_file(initial_file, head, &arg_blocks, &labels, use_ret_trap,
+			 allow_logging) != 0) {
+		warn("compile_filter: compile_file() failed");
+		free_block_list(head);
+		free_block_list(arg_blocks);
+		free_label_strings(&labels);
+		return -1;
 	}
 
 	/*
diff --git a/syscall_filter.h b/syscall_filter.h
index 4625d80..3bfbfee 100644
--- a/syscall_filter.h
+++ b/syscall_filter.h
@@ -26,18 +26,22 @@
 
 struct bpf_labels;
 
-struct filter_block *compile_section(int nr, const char *policy_line,
-				     unsigned int label_id,
-				     struct bpf_labels *labels,
-				     int do_ret_trap);
+struct filter_block *compile_policy_line(int nr, const char *policy_line,
+					 unsigned int label_id,
+					 struct bpf_labels *labels,
+					 int do_ret_trap);
+int compile_file(FILE *policy_file, struct filter_block *head,
+		 struct filter_block **arg_blocks, struct bpf_labels *labels,
+		 int use_ret_trap, int allow_logging);
 int compile_filter(FILE *policy_file, struct sock_fprog *prog, int do_ret_trap,
 		   int add_logging_syscalls);
 
+struct filter_block *new_filter_block(void);
 int flatten_block_list(struct filter_block *head, struct sock_filter *filter,
 		       size_t index, size_t cap);
 void free_block_list(struct filter_block *head);
 
-int seccomp_can_softfail();
+int seccomp_can_softfail(void);
 
 #ifdef __cplusplus
 }; /* extern "C" */
diff --git a/syscall_filter_unittest.cc b/syscall_filter_unittest.cc
index 98a1835..4a80976 100644
--- a/syscall_filter_unittest.cc
+++ b/syscall_filter_unittest.cc
@@ -347,7 +347,17 @@
   unsigned int id = 0;
 
   struct filter_block* block =
-      compile_section(nr, fragment, id, &labels_, NO_LOGGING);
+      compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
+  ASSERT_EQ(block, nullptr);
+}
+
+TEST_F(ArgFilterTest, whitespace_atom) {
+  const char* fragment = "\t    ";
+  int nr = 1;
+  unsigned int id = 0;
+
+  struct filter_block* block =
+      compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
   ASSERT_EQ(block, nullptr);
 }
 
@@ -357,7 +367,7 @@
   unsigned int id = 0;
 
   struct filter_block* block =
-      compile_section(nr, fragment, id, &labels_, NO_LOGGING);
+      compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
   ASSERT_EQ(block, nullptr);
 }
 
@@ -367,7 +377,7 @@
   unsigned int id = 0;
 
   struct filter_block* block =
-      compile_section(nr, fragment, id, &labels_, NO_LOGGING);
+      compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
   ASSERT_EQ(block, nullptr);
 }
 
@@ -376,7 +386,7 @@
   int nr = 1;
   unsigned int id = 0;
   struct filter_block *block =
-      compile_section(nr, fragment, id, &labels_, NO_LOGGING);
+      compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
 
   ASSERT_NE(block, nullptr);
   size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
@@ -385,11 +395,11 @@
   /* First block is a label. */
   struct filter_block *curr_block = block;
   ASSERT_NE(curr_block, nullptr);
-  EXPECT_EQ(block->len, 1U);
+  EXPECT_EQ(curr_block->len, 1U);
   EXPECT_LBL(curr_block->instrs);
 
   /* Second block is a comparison. */
-  curr_block = block->next;
+  curr_block = curr_block->next;
   EXPECT_COMP(curr_block);
 
   /* Third block is a jump and a label (end of AND group). */
@@ -417,7 +427,7 @@
   int nr = 1;
   unsigned int id = 0;
   struct filter_block *block =
-      compile_section(nr, fragment, id, &labels_, NO_LOGGING);
+      compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
 
   ASSERT_NE(block, nullptr);
   size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
@@ -426,11 +436,11 @@
   /* First block is a label. */
   struct filter_block *curr_block = block;
   ASSERT_NE(curr_block, nullptr);
-  EXPECT_EQ(block->len, 1U);
+  EXPECT_EQ(curr_block->len, 1U);
   EXPECT_LBL(curr_block->instrs);
 
   /* Second block is a comparison. */
-  curr_block = block->next;
+  curr_block = curr_block->next;
   EXPECT_COMP(curr_block);
 
   /* Third block is a jump and a label (end of AND group). */
@@ -458,7 +468,7 @@
   int nr = 1;
   unsigned int id = 0;
   struct filter_block *block =
-      compile_section(nr, fragment, id, &labels_, NO_LOGGING);
+      compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
 
   ASSERT_NE(block, nullptr);
   size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
@@ -467,11 +477,11 @@
   /* First block is a label. */
   struct filter_block *curr_block = block;
   ASSERT_NE(curr_block, nullptr);
-  EXPECT_EQ(block->len, 1U);
+  EXPECT_EQ(curr_block->len, 1U);
   EXPECT_LBL(curr_block->instrs);
 
   /* Second block is a comparison. */
-  curr_block = block->next;
+  curr_block = curr_block->next;
   ASSERT_NE(curr_block, nullptr);
   EXPECT_COMP(curr_block);
 
@@ -501,7 +511,7 @@
   unsigned int id = 0;
 
   struct filter_block *block =
-      compile_section(nr, fragment, id, &labels_, NO_LOGGING);
+      compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
 
   ASSERT_NE(block, nullptr);
   size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
@@ -510,11 +520,11 @@
   /* First block is a label. */
   struct filter_block *curr_block = block;
   ASSERT_NE(curr_block, nullptr);
-  EXPECT_EQ(block->len, 1U);
+  EXPECT_EQ(curr_block->len, 1U);
   EXPECT_LBL(curr_block->instrs);
 
   /* Second block is a comparison. */
-  curr_block = block->next;
+  curr_block = curr_block->next;
   ASSERT_NE(curr_block, nullptr);
   EXPECT_COMP(curr_block);
   EXPECT_EQ(curr_block->instrs[BPF_ARG_COMP_LEN - 1].k,
@@ -546,7 +556,7 @@
   unsigned int id = 0;
 
   struct filter_block *block =
-      compile_section(nr, fragment, id, &labels_, NO_LOGGING);
+      compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
   ASSERT_NE(block, nullptr);
   size_t exp_total_len = 1 + 3 * (BPF_ARG_COMP_LEN + 1) + 2 + 2 + 1 + 2;
   EXPECT_EQ(block->total_len, exp_total_len);
@@ -554,7 +564,7 @@
   /* First block is a label. */
   struct filter_block *curr_block = block;
   ASSERT_NE(curr_block, nullptr);
-  EXPECT_EQ(block->len, 1U);
+  EXPECT_EQ(curr_block->len, 1U);
   EXPECT_LBL(curr_block->instrs);
 
   /* Second block is a comparison ("arg0 == 0"). */
@@ -603,7 +613,7 @@
   unsigned int id = 0;
 
   struct filter_block *block =
-      compile_section(nr, fragment, id, &labels_, NO_LOGGING);
+      compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
   ASSERT_NE(block, nullptr);
   size_t exp_total_len = 1 + 2 * (BPF_ARG_COMP_LEN + 1) + 2 + 2 + 1 + 2;
   EXPECT_EQ(block->total_len, exp_total_len);
@@ -611,7 +621,7 @@
   /* First block is a label. */
   struct filter_block *curr_block = block;
   ASSERT_NE(curr_block, nullptr);
-  EXPECT_EQ(block->len, 1U);
+  EXPECT_EQ(curr_block->len, 1U);
   EXPECT_LBL(curr_block->instrs);
 
   /* Second block is a comparison ("arg0 == 0"). */
@@ -658,7 +668,7 @@
   unsigned int id = 0;
 
   struct filter_block *block =
-      compile_section(nr, fragment, id, &labels_, NO_LOGGING);
+      compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
   ASSERT_NE(block, nullptr);
   size_t exp_total_len = 2;
   EXPECT_EQ(block->total_len, exp_total_len);
@@ -666,7 +676,7 @@
   /* First block is a label. */
   struct filter_block *curr_block = block;
   ASSERT_NE(curr_block, nullptr);
-  EXPECT_EQ(block->len, 1U);
+  EXPECT_EQ(curr_block->len, 1U);
   EXPECT_LBL(curr_block->instrs);
 
   /* Second block is SECCOMP_RET_ERRNO. */
@@ -688,7 +698,7 @@
   unsigned int id = 0;
 
   struct filter_block *block =
-      compile_section(nr, fragment, id, &labels_, NO_LOGGING);
+      compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
   ASSERT_EQ(block, nullptr);
 }
 
@@ -698,7 +708,7 @@
   unsigned int id = 0;
 
   struct filter_block *block =
-      compile_section(nr, fragment, id, &labels_, NO_LOGGING);
+      compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
   ASSERT_EQ(block, nullptr);
 }
 
@@ -708,7 +718,7 @@
   unsigned int id = 0;
 
   struct filter_block* block =
-      compile_section(nr, fragment, id, &labels_, NO_LOGGING);
+      compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
   ASSERT_EQ(block, nullptr);
 }
 
@@ -718,7 +728,7 @@
   unsigned int id = 0;
 
   struct filter_block* block =
-      compile_section(nr, fragment, id, &labels_, NO_LOGGING);
+      compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
   ASSERT_EQ(block, nullptr);
 }
 
@@ -728,7 +738,7 @@
   unsigned int id = 0;
 
   struct filter_block* block =
-      compile_section(nr, fragment, id, &labels_, NO_LOGGING);
+      compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
   ASSERT_EQ(block, nullptr);
 }
 
@@ -738,7 +748,7 @@
   unsigned int id = 0;
 
   struct filter_block* block =
-      compile_section(nr, fragment, id, &labels_, NO_LOGGING);
+      compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
   ASSERT_EQ(block, nullptr);
 }
 
@@ -748,7 +758,7 @@
   unsigned int id = 0;
 
   struct filter_block *block =
-      compile_section(nr, fragment, id, &labels_, NO_LOGGING);
+      compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
   ASSERT_EQ(block, nullptr);
 }
 
@@ -757,7 +767,7 @@
   int nr = 1;
   unsigned int id = 0;
   struct filter_block *block =
-      compile_section(nr, fragment, id, &labels_, USE_LOGGING);
+      compile_policy_line(nr, fragment, id, &labels_, USE_LOGGING);
 
   ASSERT_NE(block, nullptr);
   size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
@@ -766,11 +776,11 @@
   /* First block is a label. */
   struct filter_block *curr_block = block;
   ASSERT_NE(curr_block, nullptr);
-  EXPECT_EQ(block->len, 1U);
+  EXPECT_EQ(curr_block->len, 1U);
   EXPECT_LBL(curr_block->instrs);
 
   /* Second block is a comparison. */
-  curr_block = block->next;
+  curr_block = curr_block->next;
   ASSERT_NE(curr_block, nullptr);
   EXPECT_COMP(curr_block);
 
@@ -800,7 +810,7 @@
   unsigned int id = 0;
 
   struct filter_block *block =
-      compile_section(nr, fragment, id, &labels_, NO_LOGGING);
+      compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
   ASSERT_NE(block, nullptr);
   size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
   EXPECT_EQ(block->total_len, exp_total_len);
@@ -808,7 +818,7 @@
   /* First block is a label. */
   struct filter_block *curr_block = block;
   ASSERT_NE(curr_block, nullptr);
-  EXPECT_EQ(block->len, 1U);
+  EXPECT_EQ(curr_block->len, 1U);
   EXPECT_LBL(curr_block->instrs);
 
   /* Second block is a comparison ("arg0 == 0"). */
@@ -844,7 +854,7 @@
   unsigned int id = 0;
 
   struct filter_block *block =
-      compile_section(nr, fragment, id, &labels_, USE_LOGGING);
+      compile_policy_line(nr, fragment, id, &labels_, USE_LOGGING);
   ASSERT_NE(block, nullptr);
   size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
   EXPECT_EQ(block->total_len, exp_total_len);
@@ -852,7 +862,7 @@
   /* First block is a label. */
   struct filter_block *curr_block = block;
   ASSERT_NE(curr_block, nullptr);
-  EXPECT_EQ(block->len, 1U);
+  EXPECT_EQ(curr_block->len, 1U);
   EXPECT_LBL(curr_block->instrs);
 
   /* Second block is a comparison ("arg0 == 0"). */
@@ -920,6 +930,126 @@
   return fdopen(pipefd[0], "r");
 }
 
+class FileTest : public ::testing::Test {
+ protected:
+  virtual void SetUp() {
+    labels_.count = 0;
+    head_ = new_filter_block();
+    arg_blocks_ = NULL;
+  }
+  virtual void TearDown() {
+    free_label_strings(&labels_);
+    free_block_list(head_);
+    free_block_list(arg_blocks_);
+  }
+  struct bpf_labels labels_;
+  struct filter_block *head_;
+  struct filter_block *arg_blocks_;
+};
+
+TEST_F(FileTest, seccomp_mode1) {
+  // struct sock_fprog actual;
+  const char *policy =
+      "read: 1\n"
+      "write: 1\n"
+      "rt_sigreturn: 1\n"
+      "exit: 1\n";
+
+  FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
+  ASSERT_NE(policy_file, nullptr);
+  int res = compile_file(
+      policy_file, head_, &arg_blocks_, &labels_, USE_RET_KILL, NO_LOGGING);
+  fclose(policy_file);
+
+  /*
+   * Checks return value and that the blocks only allow expected syscalls.
+   */
+  ASSERT_EQ(res, 0);
+  struct filter_block *curr_block = head_;
+  ASSERT_NE(curr_block, nullptr);
+  EXPECT_ALLOW_SYSCALL(curr_block->instrs, __NR_read);
+  curr_block = curr_block->next;
+  ASSERT_NE(curr_block, nullptr);
+  EXPECT_ALLOW_SYSCALL(curr_block->instrs, __NR_write);
+  curr_block = curr_block->next;
+  ASSERT_NE(curr_block, nullptr);
+  EXPECT_ALLOW_SYSCALL(curr_block->instrs, __NR_rt_sigreturn);
+  curr_block = curr_block->next;
+  ASSERT_NE(curr_block, nullptr);
+  EXPECT_ALLOW_SYSCALL(curr_block->instrs, __NR_exit);
+
+  EXPECT_EQ(curr_block->next, nullptr);
+}
+
+TEST_F(FileTest, seccomp_read) {
+  const char *policy =
+      "read: arg0 == 0\n"
+      "write: 1\n"
+      "rt_sigreturn: 1\n"
+      "exit: 1\n";
+
+  const int LABEL_ID = 0;
+
+    FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
+  ASSERT_NE(policy_file, nullptr);
+  int res = compile_file(
+      policy_file, head_, &arg_blocks_, &labels_, USE_RET_KILL, NO_LOGGING);
+  fclose(policy_file);
+
+  /*
+   * Checks return value, that the blocks only allow expected syscalls, and that
+   * labels between |head_| and |arg_blocks_| match.
+   */
+  ASSERT_EQ(res, 0);
+  struct filter_block *curr_block = head_;
+  ASSERT_NE(curr_block, nullptr);
+  EXPECT_ALLOW_SYSCALL_ARGS(curr_block->instrs,
+                            __NR_read,
+                            LABEL_ID,
+                            JUMP_JT,
+                            JUMP_JF);
+  curr_block = curr_block->next;
+  ASSERT_NE(curr_block, nullptr);
+  EXPECT_ALLOW_SYSCALL(curr_block->instrs, __NR_write);
+  curr_block = curr_block->next;
+  ASSERT_NE(curr_block, nullptr);
+  EXPECT_ALLOW_SYSCALL(curr_block->instrs, __NR_rt_sigreturn);
+  curr_block = curr_block->next;
+  ASSERT_NE(curr_block, nullptr);
+  EXPECT_ALLOW_SYSCALL(curr_block->instrs, __NR_exit);
+
+  ASSERT_NE(arg_blocks_, nullptr);
+  size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
+  EXPECT_EQ(arg_blocks_->total_len, exp_total_len);
+
+  /* First block is a label. */
+  curr_block = arg_blocks_;
+  ASSERT_NE(curr_block, nullptr);
+  EXPECT_EQ(curr_block->len, 1U);
+  EXPECT_ACTUAL_LBL(curr_block->instrs, LABEL_ID);
+
+  /* Second block is a comparison. */
+  curr_block = curr_block->next;
+  EXPECT_COMP(curr_block);
+
+  /* Third block is a jump and a label (end of AND group). */
+  curr_block = curr_block->next;
+  ASSERT_NE(curr_block, nullptr);
+  EXPECT_GROUP_END(curr_block);
+
+  /* Fourth block is SECCOMP_RET_KILL. */
+  curr_block = curr_block->next;
+  ASSERT_NE(curr_block, nullptr);
+  EXPECT_KILL(curr_block);
+
+  /* Fifth block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
+  curr_block = curr_block->next;
+  ASSERT_NE(curr_block, nullptr);
+  EXPECT_ALLOW(curr_block);
+
+  EXPECT_EQ(curr_block->next, nullptr);
+}
+
 TEST(FilterTest, seccomp_mode1) {
   struct sock_fprog actual;
   const char *policy =
@@ -1047,7 +1177,19 @@
   FILE* policy_file = write_policy_to_pipe(policy, strlen(policy));
   ASSERT_NE(policy_file, nullptr);
 
-  int res = compile_filter(policy_file, &actual, 0, NO_LOGGING);
+  int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
+  fclose(policy_file);
+  ASSERT_NE(res, 0);
+}
+
+TEST(FilterTest, whitespace_atom) {
+  struct sock_fprog actual;
+  const char* policy = "open:\t    \n";
+
+  FILE* policy_file = write_policy_to_pipe(policy, strlen(policy));
+  ASSERT_NE(policy_file, nullptr);
+
+  int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
   fclose(policy_file);
   ASSERT_NE(res, 0);
 }
@@ -1059,7 +1201,7 @@
   FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
   ASSERT_NE(policy_file, nullptr);
 
-  int res = compile_filter(policy_file, &actual, 0, NO_LOGGING);
+  int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
   fclose(policy_file);
   ASSERT_NE(res, 0);
 }
@@ -1071,14 +1213,14 @@
   FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
   ASSERT_NE(policy_file, nullptr);
 
-  int res = compile_filter(policy_file, &actual, 0, NO_LOGGING);
+  int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
   fclose(policy_file);
   ASSERT_NE(res, 0);
 }
 
 TEST(FilterTest, nonexistent) {
   struct sock_fprog actual;
-  int res = compile_filter(NULL, &actual, 0, NO_LOGGING);
+  int res = compile_filter(NULL, &actual, USE_RET_KILL, NO_LOGGING);
   ASSERT_NE(res, 0);
 }
 
diff --git a/syscall_filter_unittest_macros.h b/syscall_filter_unittest_macros.h
index 81ec67c..02bac89 100644
--- a/syscall_filter_unittest_macros.h
+++ b/syscall_filter_unittest_macros.h
@@ -44,6 +44,14 @@
 	EXPECT_TRUE((_block)->jf == LABEL_JF);			\
 } while (0)
 
+#define EXPECT_ACTUAL_LBL(_block, _id) \
+do {	\
+	EXPECT_TRUE((_block)->code == (BPF_JMP+BPF_JA));	\
+	EXPECT_TRUE((_block)->k == (_id));			\
+	EXPECT_TRUE((_block)->jt == LABEL_JT);			\
+	EXPECT_TRUE((_block)->jf == LABEL_JF);			\
+} while (0)
+
 #define EXPECT_JUMP_LBL(_block) \
 do {	\
 	EXPECT_EQ((_block)->code, BPF_JMP+BPF_JA);	\