failing like never before

6Sep/100

The World’s Most Interesting Intern

And just like that, we return from an incredibly long four month hiatus, something this blog has never seen before...

Guess I'm a little late to the party, but I figure that its still worth talking about. Throughout the summer, Cisco Systems intern Greg Justice has been releasing a bunch of videos where he claims to be the world's most interesting intern, and surprisingly, he's managed to gain a remarkable amount of popularity and even inspired numerous video responses.  I don't know Greg personally, but like him, I too am a Cisco summer intern at the San Jose campus (along with a few hundred others). Here's a few of his videos:

Quite frankly, I'm amazed that he's managed to garner so much attention, since his videos aren't exactly gut-busting hilarious, but rather, just simply amusing. But of course, lamer things have somehow managed to gain more popularity on the inter-webs (I'm looking at you double-rainbow-man). I'm not going to make a case that I'm the world's most interesting intern (I know I'm not) but as my internship at Cisco draws to a close, I figure it might be worthwhile to at least mention some of my experiences this summer.

The work has been intellectually interesting, which is more then I can say for some of my previous internship experiences, and I'm happy to say that I was not relegated to the post of code monkey, although I did pump out a fair bit of code. Whether or not I made a positive contribution to the company as a whole, I cannot truly say, since  some of the aspects of the product I'm working on are not set in stone and if product specs change again my make may have to be discarded. Overall the work environment is fairly nice, the other engineers highly intelligent and helpful, and the management friendly and unobtrusive, so I cannot complain about this summer. My greatest fear, as a software engineer, is to be left in an uninspiring occupation, banging out unoriginal code for rarely used and uninteresting programs. I fear that I may become an out-source-able code monkey. It is often felt that large companies, like Cisco, that have literally buildings filled with engineers, are often prone to relegate their engineers to excruciatingly boring and tedious code-monkey-like tasks, and treating them like cheap, interchangeable workers in a factory. But I'm happy to say that this was not the case for me. So high-fives all around...

Also, might I just say, that the laptops they gave us interns (not to keep of course), are insanely powerful. Which is a little odd considering that we do almost all our development work on the servers, which are even more powerful.

Tagged as: , , No Comments
8May/100

Smashing the Stack for Extra Credit

(So this one is a little old... I have a habit of writing up drafts, stashing them away to be uploaded later, and then completely forgetting about them.)

A quick intro to buffer overflow attacks for the unlearned (feel free to skip this bit).

I would highly recommend reading AlephOne's Smashing the Stack for Fun and Profit if you really want to learn about buffer-overflow attacks, but you can read my bit instead if you just want a quick idea of whats its all about.

Programs written in non-type safe languages like C/C++, do not perform bounds checking on memory when doing reads and writes, and are therefore often to susceptible to what is known as a buffer-overflow attack. Basically, when a program allocates some array on the program stack, the possibility exists that if the programmer is not careful, her program may accidentally overwrite the bounds of the array. One could imagine a situation where a program allocates N amounts of bytes on the stack, reads in input from stdin using scanf (which terminates reading input when it hits a newline) and stores the read bytes in the allocated array. However, the user sitting at the terminal might decide to enter in more then N bytes of data, causing the program to overwrite the bounds of its array. Other values on the stack could then be unintentionally altered which could cause the program to execute erratically and even crash.

But a would-be attacker can do more then just crash a program with a buffer-overflow attack, they could potentially gain control of the program and even cause it to execute arbitrary code. (By "executing arbitrary code" I mean that the attacker could make the program do anything.) An attacker can take control of a program by writing down the program stack past the array's bounds and changing the return address stored on the stack, so that when the currently executing function returns control to the calling function, it actually ends up executing some completely different segment of code. At first glance, this seems rather useless. But an attacker can set the instruction pointer to anything, she could even make it point back to the start of the array that was just overwritten. A carefully crafted attack message, could cause the array to be filled with some bits of arbitrary assembly code (perhaps to fork a shell and then connect that shell to a remote machine) and then overwrite the return address to point to the top of the overwritten array.

A problem with the generic buffer overflow attack is that the starting location of the stack is determined at runtime and therefore can change slightly. This makes it difficult for an attacker to know exactly where the top of the array is every single time. A solution to this, is to use a "NOP slide," where the attack message doesn't immediately begin with the assembly code but rather begins with a stream of NOPs. A NOP is an assembly language instruction that basically does nothing (I believe that it was originally included in the x86 ISA to deal with hazards) so as long as the instruction pointer is reset to point into somewhere the NOP slide, the computer will "slide" (weeeeee!!!!) into the rest of the injected assembly code.

Sounds simple so far? Just you wait....

The trials and tribulations of my feeble attempt to "smash the stack."

The professor for my security class threw in a nice little extra credit problem on a homework assignment last quarter. One of the problems in the homework asked us to crash a flawed web-server using a buffer overflow attack, but we could get extra credit if we managed to root the server with the buffer overflow. Buffer overflow attacks on real software are nontrivial, something my professor made sure to emphasize when he told us that in his whole experience of teaching the class, only one student had ever successfully rooted the server. Now Scott Adams, author of Dilbert, mentioned in one of his books that the best way to motivate an engineer, is to tell them that a task is nearly impossible and that if they're not up for the challenge, then its no big deal because so-and-so could probably do it better. This must be true, because after discussion section, I went straight to a computer and started reading Smashing the Stack for Fun and Profit, intent on being the second person to "smash the stack" in my school.

I was able to crash the server software within less then one minute of swapping the machine's disk image in, as it was a ridiculously simple task to guess where an unbounded buffer was being used in the server code and force a segmentation fault. It took me a few more minutes to trace down the exact location of where the overflow was occurring (there was a location in the code where the program would use strcat() to copy a message), but as soon as I did, I booted up GDB and started gearing up for some hard work.

16Apr/100

OCaml Infix Notation and Parenthesis

So when I first picked up LISP, I found myself hating everything about the language, from its distinctively un-C-like functional style, to the inordinate number of parenthesis required by the syntax. But before long, I found myself accidentally writing my math homework in prefix notation and putting parenthesis around all of my sentences, just out of pure habit. With time, I began to find the LISP style more relaxing to develop in, and started to understand the stark beauty of the language. A few months after my first excursion into LISP, I was telling people how LISP was the most beautiful language ever created.

Now, enter OCaml, a functional language free from legacy cruft, and inspired in some form from LISP. I thought I would love being able to develop in a LISP-like language without having to worry about ending statements with a dozen end-parenthesis (which I thought to be LISP's only big syntax flaw), but I found the lack of required parenthesis initially quite awkward. Yes, there are a lot of insipid little parenthesis in LISP, but the point of them is to clarify the code and they do! Parenthesis are what allow LISP to have such simple and easy to understand syntax. (Lets face it, Ocaml just doesn't have the "Its full of cars!" sort of easily understood syntax.) Of course, since OCaml makes parenthesis optional in most cases, one could simply add parenthesis to everything in OCaml, much as one would in LISP. I got over the parenthesis business in OCaml quite quickly, although I still miss them quite a bit.

The one thing I could never get over however, was the weird way OCaml uses built-in operators (like '+', '-', '/', etc.) in infix notation, but has all other functions used in typical prefix notation. By enclosing an operator in parenthesis, it can then be used in prefix notation, but this is a little clunky. I would think that it would be better to force all aspects of the language to follow the same common rules in order to reduce confusion, but the OCaml designers were apparently following a different line of reason from mine.

Although OCaml's odd mix of infix and prefix notation has remained a thorn in my side whenever I lay hand to keyboard to bang out some OCaml code, I've nevertheless managed to gain a good understanding of the language. I've also started to find the usefulness of the language, but my heart still pines for LISP...

16Nov/094

Knight’s Tour in Lisp

For those of you unfamilar with the Knight's tour, here's a brief overview of the problem. The Knight's Tour invovles placing a knight on a chessboard and then having the knight move to each and every square on the chessboard once and only once. There are a suprisingly huge number of possible paths that a single Knight can take on a standard chessboard so of course, a blind, exhaustive search is generally out of the question. 

The program I have written below explores the Open Knight's Tour, where the knight simply has to reach each and every square once and only once (the Closed Tour would add the additional requirement that the knight end on the square he started on). I will admit that my Lisp code isn't exactly the best or the most efficient, but it works fairly deccent. My method of solving the tour, uses backtracking (which is very similar to Depth First Search) and a herustic known as Minimum Remaining Value. This herustic is sometimes known as Warnsdorff's algorithm when used in the Knight's Tour. Warnsdorff's algorithm selects as the knight's next move, the square that would present the fewest possible moves following the move to that square. Essentially, the herustic is trying to eliminate dead end's earlier on. And so here's my code (most of which is comments, [Hey, it was written for a class]):

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; FIND-KNIGHTS-TOUR2                                                      ;;; 
;;; using minimum remaining value herustics (aka most constrained variable) ;;;
;;;                                                                         ;;; 
;;; on my laptop, this implementation can find a solution to                ;;;
;;; 100x100 board, starting from (1 1) in under three minutes               ;;;
;;; and can solve 50x50 in about 16 seconds on SEAS                         ;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; you can run the knights tour with:
; (find-knights-tour ([rows in board] [cols in board] [row_pos] [col_pos])

(setq steps 0)
(setq visited-list ()) 


; generate a list of all possible moves for knight
; given that current position of knight is (row col)
; note that this function will generate "wrong" move values, like
; moving off the board or moving to an old spot.
;
; function get_values(number:x number:y):((num num) (num num) )
(defun get_values (row col)
  (list 
    ; there are at most eight possible move values 
    (list (+ row 2) (+ col 1))
    (list (+ row 2) (- col 1))
    (list (+ row 1) (+ col 2))
    (list (+ row 1) (- col 2))

    (list (- row 2) (+ col 1))
    (list (- row 2) (- col 1))
    (list (- row 1) (+ col 2))
    (list (- row 1) (- col 2))) )

; val is a list of possible move values for a knight variable
;   and should be generated by get_values function
; m_row is max number of rows in the board
; m_col is max number of columns in the board
;
; test_valid_values will return a list containing only the valid
; values allowed, removing those values that have already been
; visited and are not on the board
;
; function test_valid_values( 
;       ((num num) (num num) ):vals
;       number:m_row
;       number:m_col):((num num) (num num) )
(defun test_valid_values (vals m_row m_col)
  (let 
    ; grab the first value out of the vals list
    ((v (car vals)))
  (cond
    ((null vals) ()) 
    ; test for out of bound values, or already traversed
    ; if value is out of bound, remove it (cdr vals) 
    ((or (> (car v)  m_row) (<= (car v)  0) 
         (> (cadr v) m_col) (<= (cadr v) 0)
         (list_member v visited-list))
            (test_valid_values (cdr vals) m_row m_col))
    ; value is valid, add to our "valid" list
    (t (cons (car vals) 
             (test_valid_values (cdr vals) m_row m_col))))) )


; check if "l" is a member of "visited"
; return 't' if so, 'nil' otherwise
;
; function list_member( 
;       (number number):l
;       ((num num) (num num) ):visited) :t/nil
(defun list_member (l visited)
  (cond
    ((null visited) nil)
    ((equal (car visited) l) t)
    (t (list_member l (cdr visited)))) )


;minimum remaining value herustic, or the most constrained variable
;instead of just returning randomnly arranged list of possible moves from
;   current location (as in above without herustics) arrange possible moves
;   in the list so that the move that will offer the least number of moves in
;   the next iteration comes first, with the move that offers the most of 
;   moves coming last in the list
;   
;function min_remaining_val(number:m_row number:m_col): 
;       ((number number) (number number) )
(defun min_remaining_val (m_row m_col)
  (let
    ; get valid values
    ((vals (test_valid_values 
        (get_values 
        (car (car (last visited-list))) (cadr (car (last visited-list)))) 
             m_row m_col)))
    ; then call call mrv_helper to attach assign a value to each move
    ; mrv_sort to arrange moves 
    (mrv_sort (mrv_helper vals m_row m_col))
))

; determines number of possible moves allowed if we move to a position in
; the vals list
;
; function mrv_helper(
;   ((num num) (num num) ):vals
;   number:m_row
;   number:m_col) :
;   ((num (num num)) (num (num num)) )
(defun mrv_helper (vals m_row m_col)
  (let 
    ((len 
       ; calculate the number of possible moves from a position in the 
       ; "vals" list
       (length 
         (test_valid_values 
           (get_values (car (car vals)) (cadr (car vals))) 
         m_row m_col))))
    (cond 
      ; if no more moves in "vals", just return it and done
      ((null (cdr vals)) (list (cons len (list (car vals)))))
      ; else add move and length value to list and keep recursing
      (t (cons (cons len (list (car vals))) 
                 (mrv_helper (cdr vals) m_row m_col))))) )

;finds the move with the minimum value in the list "vals"
;i.e. if "vals" is ( (1 (2 4)) (2 (5 2)) (4 (3 2)) )
;   then min_vals would return (1 (2 4)) because its move value is "1"
;
;function min_val(
;   ((num (num num)) (num (num num)) ):vals) :
;       (num (num num))
(defun min_val (vals)
  (cond
    ; base case, return the only move in "vals"
    ((null (cdr vals)) (car vals))
    (t
      (let
        ; calculate the min_val in the rest of the list
        ; store it in "p"
        ((p (min_val (cdr vals))))
        (cond
          ; if the current minimum value is less then previous
          ; min val, then use current min val
          ((<= (car (car vals)) (car p)) (car vals))
          ; else use previous min val
          (t p))))) )

; remove from list 'l' the element that matches 'r'
; this is because we are not allowed to use "remove" function
;
;function remove_list(list:r list:l):list
(defun remove_list (r l)
  (cond
    ; if equal, then done
    ((equal r (car l)) (cdr l))
    ; reached the end and couldn't find a match
    ((null (cdr l)) l)
    ; else keep recursing
    (t (cons (car l) (remove_list r (cdr l))))) ) 

; sort the moves in "vals" list based on their move length values
; and then strips out their "length values
;
; i.e., if "vals" is ((3 (2 3)) (2 (1 2)) (5 (3 4)) (1 (2 1)) (2 (2 2)))
;then mrv_sort returns:
;   ((2 1) (1 2) (2 2) (2 3) (3 4) )

;function mrv_sort(
;   ((num (num num)) (num (num num))  ):vals) :
;   ((num num) (num num) )
(defun mrv_sort (vals)
  (cond
    ; base case, return the last move in "vals"
    ((null (cdr vals)) (cdr (car vals)))
    (t 
      (let
        ;else keep sorting, using min_val function 
        ;v is the min val in "vals"
        ((v (min_val vals)))
        (append (cdr v) (mrv_sort (remove_list v vals)))))) )


; recurse down the search tree, expand out the children for last
; visited spot
;
; m_row is number of rows in board
; m_col is number of cols in board
;
; function recurse_down(number:m_row number:m_col):t/nil
(defun recurse_down (m_row m_col)
  ; get the valid values, store as val
  (let
    ((vals (min_remaining_val m_row m_col)))
    (cond
      ; no valid values, backtrack 
      ; note, that we test for sucessful completion before this 
      ((null vals) nil)
      ; else recurse across
      (t (recurse_across vals m_row m_col)))) ) 

; this function is exactly the same as recurse_across except
; that it calls recurse_down instead of recurse_down
;
;vals is valid moves, having the form:
;     ((number number) (num num) etc.)
; m_row is number of rows in board
; m_col is number of cols in board
;
; function recurse_across(
;       ((num num) (num num) ):vals
;       number:m_row
;       number:m_col) : t/nil
(defun recurse_across (vals m_row m_col)
  (cond
    ; no more valid moves, backtrack
    ((null vals) nil)
    (t 
      (cond
      ; if number of steps taken equals number of squares on board
      ; then we're done
      ((equal (+ steps 1) (* m_row m_col)) 
        ; increment number of steps, add new visited square
        (setq steps (+ steps 1)) 
        (setq visited-list (append visited-list (list (car vals)))) 
        ; return t 
        t)
      (t
        ; else continue moving until end
        ; increment steps and add to visited-list 
        (setq steps (+ steps 1)) 
        (setq visited-list (append visited-list (list (car vals)))) 
        (cond 
          ; recurse down, return t if recurse_down found solution
          ((recurse_down m_row m_col) t)
          (t 
            ; if recurse_down did not find solution, backtrack, removing
            ; moves from visited-list and from "steps" as we backtrack
            ; and then recurse_across
            (setq steps (- steps 1))
            (setq visited-list (reverse (cdr (reverse visited-list))))
            (recurse_across (cdr vals) m_row m_col))))))) ) 

;find the knights tour given board size of (m_row m_col) and 
;starting position (row col)
;use herustics
;
;function find-knights-tour(number:m_row number:m_col number:row number:col) :
;       ((number number) (number number) )
(defun find-knights-tour (m_row m_col row col)
  ; set the global variables
  (setq visited-list (list (list row col)))
  (setq steps 1)
  ; start searching...
  (cond
    ((recurse_down m_row m_col) visited-list)
    (t nil)) )
9Oct/090

IE8 Fail

So apparently the combination of my latest WordPress theme (Lightword) and Google's code syntax highlighter for Python, makes IE8 go insane. The syntax highlighter for C/C++ seems to work fine with IE8, but when IE8 tries to render a page thats displaying Python code, the browser hits some sort of null array error. The worst part, is that instead of handling the problem gracefully, IE8 doesn't display ANY of my Python code. I'm currently displaying Python code on my site without syntax highlighting, and am trying to find a solution to this idiotic problem.

Tagged as: , No Comments
11Sep/094

Python Animated Progress Bar

I wanted to be able to have an animated progress bar to be displayed in a terminal for my current Python project. There are already various implementations on the Internet of something like what I wanted, but I couldn't find one that was animated. So for the sake of practice, I decided to write my own. In order to be able to have the bar animated, and still allow the program to get other work done, I had to create a seperate thread to manage the status bar.

Code for the bar, (and also sample code to create a demo) are below.

import time
import sys
import os
import threading

"""
Display an animated statusbar, with progress and percentage
( items-completed/items-total )
displayed below the statusbar. Seperate thread is used to
display the spinning "icon." In order to stop the statusbar thread
early, calling thread can use join() 

example output created by StatusBar thread:

[===============\--------------]
30/60  50%

Written by chi (aka chi42) from 42gems.com-- 11 Sept, 2009

Copyright (C) 2009 chi (from 42gems.com)

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

Please see http://www.gnu.org/licenses/ for a copy of the license.
"""

class StatusBar(threading.Thread):

    # class variables:
    # max:  number of total items to be completed
    # pos:  number of completed items
    # inc:  amount of items to increment completed 'pos' by
    #           (shared resource)
    # comp: amount of '=' to display in the progress bar
    # running: whether or not the statusbar is running
    def __init__(self, pos=0, max=100):
        threading.Thread.__init__(self)
        self.pos = pos
        self.max = max
        self.busy_char = '|'
        self.running = 0
        self.inc =  0
        self.__getsize()
        self.comp = int(float(self.pos) / self.max * self.columns)
        self.inc_lock = threading.Lock() 

    # find number of columns in terminal
    def __getsize(self):
        rows, columns = os.popen('stty size', 'r').read().split()
        if int(columns) > 80:
            self.columns = 80 - 2
        else:
            self.columns = int(columns) - 2
        return

    # redraw progress bar and all numerial values
    def __print(self):
        self.__getsize()

        sys.stdout.write('\x1b[1G')
        sys.stdout.write('[' + '=' * self.comp + self.busy_char + \
            '-'*(self.columns - self.comp - 1) + ']'   )
        sys.stdout.write('\n\x1b[0K' + str(self.pos) + \
            '/' + str(self.max) + '\t' + \
            str( round(float(self.pos) / self.max * 100, 2)) + '%')
        sys.stdout.write('\x1b[1A\x1b[' + \
            str(self.comp + 2) + 'G')
        sys.stdout.flush()
        return

    # run the thread
    def run(self):
        global busy_chars, inteval
        busy_chars = ['|','/','-','\\']
        interval = 0.3

        self.running = 1 

        self.__print()
        while 1:
            # loop and display the busy spinning icon
            for c in busy_chars:
                self.busy_char = c
                sys.stdout.write(c + '\x1b[1D')
                sys.stdout.flush()
                time.sleep(interval)

                self.inc_lock.acquire()
                if self.inc:
                    if (self.pos + self.inc) >= self.max:
                        self.inc_lock.release()
                        self.pos = self.max
                        self.comp = self.columns
                        self.busy_char = ''
                        self.__print()
                        sys.stdout.write('\n\n')
                        self.running = 0
                        return 0
                    else:
                        self.pos += self.inc
                        self.inc = 0
                        self.inc_lock.release()
                        self.comp = int(float(self.pos) / self.max \
                            * self.columns)
                        self.__print()
                else:
                    self.inc_lock.release()
        return 1

    # increment number of completed items used by calling thread
    def increment(self):
        if self.running:
            self.inc_lock.acquire()
            self.inc += 1
            self.inc_lock.release()
            return 0
        else:
            return 1

Annnd the demo code:

#!/usr/bin/python

import statusbar
import time
import os

print '\n'

min, max = 0, 80
inc_sleep = 3 

bar = statusbar.StatusBar(min, max)

rows, columns = os.popen('stty size', 'r').read().split()
print 'columns in screen: ', columns 

bar.start()
while 1:
    time.sleep(inc_sleep)
    if bar.increment():
        break
print 'done!'
9Jun/090

Network Timeouts in C

Reccently, while coding up some P2P sharing software for class, I came across a problem that really got me stuck. (Note, that I forked different processes to handle each upload and upload.) When reading data from another peer, my peer would generally have to block until the other peer responded, since with network programming we can never expect all of our requests to return immediately. The problem was that occassionally, the other peer would decide to die entirely and I was left with a process that would block essentially forever since the signal it was waiting for was never going to come. Now the great thing about blocking reads is that they don't burn CPU time spinning around in a circle waiting for data to arrive, but they do take up space in the process table and in memory. And of course, if my blocked reading proccesses stayed around forever, it would be very simple for a malacious peer to bring my OS to a grinding halt. Essentially, what I needed was a way to make read() timeout. Now anyone vaguely familar with using internet browsers and other such network-reliant programs are probably familar with timeouts, but I had no idea how to implement it in C.

My first thought, was to use setrlimit(), a Unix function that allows the programmer to set the maximum amount of system resources (CPU time, VM size, created file sizes, etc., for more use "man 2 setrlimit"). When setrlimit() is used to set a maximum amount of CPU time, the process will recieve SIGXCPU when the CPU time soft limit is reached, and then the process is killed when the hard limit is reached. At the time, I was a bit groggy so setrlimit() seemed like a great solution, but of course anyone with half a brain (which I apparently didn't have at the time) will realize that setrlimit() is definetely not the solution to this problem. A blocking process doesn't run and therefore doesn't consume CPU time, so setting a maximum CPU time does pretty much nothing to the blocking process; it'll still keep blocking forever.

After a little bit of trawling the internet, I finally came upon the perfect solution: alarms! When alarm(unsigned int seconds) is called, it will raise SIGALRM after so many seconds, realtime seconds mind you and not CPU seconds consumed by the process, even if the process that called alarm() is blocking. I set the alarm right before I began a read() and used signal() to bind a  signal handler to SIGALRM, so that when the alarm went off my signal handler could gracefully kill the timed-out download process!

7May/091

Something is Not Quite Right

Take a look at this C function, and see if you can can catch whats wrong with it. (That is, what about this function could produce an error?)

void wait_for_ready(void)
{
    while ((inb(0x1F7) & 0x80) || !(inb(0x1F7) & 0x40))
        continue;
}

This question showed up on my midterm and stumped the hell out of me at the time. Now that I know the answer, I feel like a complete idiot for not spotting the problem initially, seeing as its so amazingly obvious. When I took the exam, I spent way too much time on this problem, completely overthinking it.

In this function, we're using a machine level instruction, inb, to read the value of some hardware port on an x86 machines. So far so good, or so I thought when I was taking my exam. But the problem is, is that the data we're reading can be a shared resource, that is, other applications could be writing and reading to it at the same time, so a race condition ensues. Even on a machine with a single processor, this is still a problem, since wait_for_ready() could read the data memory into register, then a context switch could occur, some application could write to that location, and then wait_for_read() regains control but operates with an old data value.

So simple. And now I feel like an idiot.